Files
Chamilo/vendor/sonata-project/easy-extends-bundle/Resources/doc/reference/why.rst
2025-04-10 12:24:57 +02:00

109 lines
5.3 KiB
ReStructuredText
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
.. index::
double: Reference; Installation
single: Doctrine
single: Tour
Make your Symfony2 bundle extendable
====================================
.. 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.
Lets have a quick Symfony2 and Doctrine tour
---------------------------------------------
A quick Doctrine tour:
* `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 ``post`` property and not a ``post_id`` property.
* `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,
* 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,
* Each entity is linked to a `ClassMetadata` information which contains all the mapping information and the final class name,
* An entity can extend a `SuperClass`. A `SuperClass` is just a mapping definition, a `SuperClass` cannot be persisted.
A quick `Symfony2` bundle tour:
* There are two types of bundles:
* Application Bundle (AB),
* Vendor Bundle (VB), that should not be modified inside a project.
* The AB directory is where developers implement the project requirements,
* An AB can overwrite almost everything from a VB, example: you can redefine a VB template at the AB level.
A namespace tour:
* “a namespace is an abstract container providing context for the items” (`Source <http://en.wikipedia.org/wiki/Namespace>`_),
* An entity is defined by a namespace,
* A bundle is defined by a namespace,
* A VB and AB are defined with two different namespaces.
Lets start to mix these points together
----------------------------------------
* If an AB bundle A wants to use an entity from a VB bundle B, the fully qualify namespace must be used,
* 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.
At this point, you have 2 entities with 2 different namespaces. The VB bundles 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.
Can this problem be solved with the Alternate syntax?
-----------------------------------------------------
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.
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. Its not really nice and creates a dependency to the class metadata.
Last issue, the entitys 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. (Dont take this for granted; this might
change in a near future, as Symfony2 is not complete yet)
A pragmatic way to solve this issue
-----------------------------------
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``.
So, inside your mapping definition or inside your VB code, you will use one final namespace: ``problem solved``.
How to achieve this:
* Declare only SuperClass inside a VB, dont use final entity,
* Call your entity ``BaseXXXX`` and make it abstract, change the properties from private to protected,
* The same goes for a repository,
* Always use ``Application\YourBundle\Entity\XXXX`` inside your code.
Of course, you need to create for each VB bundle:
* a valid structure inside the Application directory,
* 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.
How to make your bundle easy extendable?
----------------------------------------
Mainly all you need is to follow instructions in previous paragraph:
* Declare you entity/repository as described above,
* Use your entity/repository as described above,
* 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``.
At last you can run:
.. code-block:: bash
php app/console sonata:easy-extends:generate YourVBBundleName
.. note::
Note that the `--dest` option allows you to choose the target directory, such as `src`. Default destination is `app/`.
Also note that the `--namespace` option allows you to choose the base namespace, such as `Application\\Sonata`. Default destination is `Application\\:vendor`.