天天看點

SonataEasyExtendsBundle功能包:讓您的Symfony2功能包可被擴充

Note

this post is not part of the Symfony2 documentation; it is just a state about how things work now (end of 2010) between Doctrine2 and Symfony2. It is not a complaint about the architecture, it just exposes how I solve a recurrent problem I have.

注意:本文檔并非Symfony2的官方文檔,它隻是表現Symfony2和Doctrine2之間如何工作的狀态(2010年底)。它并非是關于結構方面的抱怨,它隻是表明了我是如何解決這一常見問題的。

A quick Doctrine tour:

Doctrine的簡要說明:

Doctrine2 entities are plain PHP objects; there is no database layer information. An Comment::post_id property is part of the database layer and not part of the domain layer. So a comment entity will have a postproperty and not a post_id property. Doctrine2實體是一個簡單PHP對象;它沒有資料庫層資訊。Comment::post_id屬性是屬于資料庫層而非域層,是以Comment實體有一個post屬性而非post_id屬性。 Doctrine2 entities are mapped through mapping information: yaml, xml, annotation or php code. There is one mapping per class. So if Blog extends SuperBlog, which extends SuperEntity, you will have 3 classes and so 3 information mappings and you will be able to use 3 different tables to save these entities. Doctrine2實體通過yaml、xml、annotation或PHP代碼等映射資訊來進行映射,它是基于每個類來做映射的。是以如果Blog從SuperBlog(SuperBlog又是從SuperEntity擴充出來的)擴充出來的話,您将有三個類和三個映射資訊,并且您将使用3個不同的資料表來儲存這些實體。 A mapped entity is final (from doctrine2 point of view), it cannot be extended unless you create a new mapping definition for the new child class. 如果一個被映射的實體是最終實體(從Doctine2的角度來看)的話,那麼它不能被擴充,除非您為新的子類定義一個新的映射。 Each entity is linked to a ClassMetadata information which contains all the mapping information and the final class name. 每個實體都被鍊到一個ClassMetadata資訊,該資訊包括所有的映射資訊和最終類名。 An entity can extend a SuperClass. A SuperClass is just a mapping definition, a SuperClass cannot be persisted. 實體可以從SuperClass擴充,SuperClass隻是個映射定義,它是不能被持久化的。

A quick Symfony2 bundle tour:

Symfony2功能包的簡要說明:

There are two types of bundles: Application Bundle (AB) and Vendor Bundle (VB), the latter should not be modified inside a project. 功能包有兩類:應用程式功能包(AB)和供應商提供的功能包(VB),後者不能在項目中修改。 The AB directory is where developers implement the project requirements. AB的目錄位置可以由開發者在根據項目要求來實作 An AB can overwrite almost everything from a VB, example: you can redefine a VB template at the AB level. AB幾乎可以覆寫VB中的任何東西,如您可以在AB層次重定義VB的模闆

名稱空間的簡要說明:

“命名空間是一個提供上下文的抽象容器 An entity is defined by a namespace 實體通過命名空間定義 A bundle is defined by a namespace 功能包通過命名空間定義 A VB and AB are defined with two different namespaces VB和AB通過兩個不同的命名空間定義
If an AB bundle A wants to use an entity from a VB bundle B, the fully qualify namespace must be used. 如果AB功能包A想使用來自VB功能包B的實體,那麼必須使用一個完整的命名空間 If a developer wants to add a new property into a VB entity, the developer needs to create a new child entity with a custom mapping. 如果開發者想添加一個新屬性到一個VB實體,那麼他需要通過一個自定義的映射去建立一個新的子實體

At this point you have 2 entities with 2 different namespace. The VB bundle’s code refers to its own namespace to instantiate the model, BUT ... how ... you just create a new entity. Your VB will be unable to use this new model ... too bad.

此時,您有兩個不同命名空間的兩個實體。VB功能包代碼指向它自己的命名空間用來對模型進行執行個體化,但...您剛才建立了一個新的實體。您的VB将不能使用這個新模型...太糟了

There is actually a start of a solution, the DoctrineBundle allows us to use an alternate syntax, ie (BlogBundle:Blog instead of Bundle\BlogBundle\Entity\Blog). As you can guess this syntax only works for string, inside a query for instance.

有個解決方案:DoctrineBundle允許我們使用一個替代文法,如使用BlogBundle:Blog來替代Bundle\BlogBundle\Entity\Blog,是以您可以猜到該文法僅适用于字元串,以便放置在執行個體的查詢中。

So if you want to instantiate a new model, you need first to get the ClassMetadata instance, retrieve the class name and create the model. It’s not really nice and creates a dependency to the class metadata.

是以如果您想執行個體化一個新模型,您首先需要獲得ClassMetadata執行個體,檢索類名并建立模型,然後建立類中繼資料依賴,這并不是太好。

Last issue, the entity’s mapping association required fully qualifies namespace: no alternate syntax. (I suppose, this last point can be fixed).

最後,實體映射關聯要求完整的命名空間:沒有替代文法(我假定最後一點沒有變化)

At this point, we are stuck with no solution to fully extend a bundle. (Don’t take this for granted; this might change in a near future, as Symfony2 is not complete yet)

基于上述考慮,我們認為目前沒有一個完全擴充功能包的解決方案。(不要想當然,在将來這些也許會被改變,因為Symfony2并未完成)

The easiest way to solve this problem is to use global namespace inside your VB, the global namespace is the only namespace allowed Application\YourBundle\Entity.

最容易解決這一問題的方法在您的VB中使用全局命名空間,全局的命名空間隻允許Application\您的功能包\Entity

So inside your mapping definition or inside your VB code, you will use one final namespace: problem solved. How to achieve this

是以在您的映射定義或VB代碼中,您将使用一個最終命名空間:問題解決。如何來實作呢?

Declare only SuperClass inside a VB, don’t use final entity 在VB中隻聲明SuperClass,并不使用最終實體 Call your entity BaseXXXX and make it abstract, change the properties from private to protected. 調用您的BaseXXXX并将其抽象,并将其屬性由私有(private)改為保護(protected)。 The same goes for a repository 同樣對repository中也作相同操作 Always use Application\YourBundle\Entity\XXXX inside your code 總在在您的代碼中使用Application\您的功能包\Entity\XXXX

Of course, you need to create for each VB bundle

當然,您需要為每個VB功能包建立:

a valid structure inside the Application directory Application目錄下的合法結構 a valid entity mapping definition 合法的實體映射定義 a model inside the entity folder 實體目錄中的模型

The last part is quite inefficient without an efficient tool to generate for you this structure: EasyExtendsBundle to the rescue.

最後這部分如果沒有一個有效的工具來幫您生成這一結構将會十分繁瑣:EasyExtendsBundle将能幫到您。

Mainly all you need is to follow instructions in previous paragraph.

綜上所述,您主要需要:

Declare you entity/repository as described above 根據上節的說明重新聲明您的entity/repository Use your entity/repository as described above. 根據上節的說明使用您的entity/repository Before generation you also need “skeleton” file that will describe AB entity. Skeleton file can either xml or yml. For fully working example see SonataMediaBundle. 在生成之前,您還需要“skeleton”檔案來描述AB實體,該檔案可以是xml或yml格式,完整示例請參見SonataMediaBundle

At last you can run php app/console sonata:easy-extends:generate YourVBBundleName. Note that the –dest option allows you to choose the target directory, such as src. Default destination is app/

最後您可以運作 php app/console sonata:easy-extends:generate 您的VB功能包名。注意--dest選項允許您選擇目的目錄,如src等,該目錄預設為app/

本文轉自 firehare 51CTO部落格,原文連結:http://blog.51cto.com/firehare/1397586,如需轉載請自行聯系原作者