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年底)。它並非是關於結構方面的抱怨,它只是表明了我是如何解決這一常見問題的。

3.1. LET’S HAVE A QUICK SYMFONY2 AND DOCTRINE TOUR

3.1.Symfony2和Doctrine的簡要說明


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通過兩個不同的命名空間定義

3.2. LET’S START TO MIX THESE POINTS TOGETHER

3.2.讓我們開始將這些觀點混和起來

  • 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將不能使用這個新模型...太糟了

3.3. CAN THIS PROBLEM BE SOLVED WITH THE ALTERNATE SYNTAX?

3.3.這個問題可以用替代語法解決嗎?

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並未完成)

3.4. A PRAGMATIC WAY TO SOLVE THIS ISSUE

3.4.實用的解決方法

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將能幫到您。

3.5. HOW TO MAKE YOUR BUNDLE EASY EXTENDABLE

3.5.如何讓您的功能包容易被擴展

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/


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章