Symfony Bundle Inheritance - Extending an Entity - php

I'm extending the functionality of an existing Symfony-based application and have found that additional bundles and using bundle inheritance has worked well to customise the functionality.
I've now found myself wanting to inherit from an existing bundle to customise its functionality but I also need to add some additional entities and extend the existing ones. The documentation suggests it might not be possible to extend an existing one since the entity is not a mapped superclass.
Is there anything I can do in this case? I basically want to retain the vast majority of the functionality of the existing bundle, but be able to collect more data.
EDIT:
I've looked into Doctrine inheritance and everything seems to require I have access to the top-level class in order to extend it. Which isn't ideal, as I'd like to keep that class the same.

Related

Decoupling Symfony bundles and making coupling loose or configurable

The case I'm trying to solve is:
I got bundle taking care of orders called 'OrderBundle' and wrote additional budle taking care of complaints - 'ComplaintsBundle' - the bundle is not fully standalone - the
entity 'Complaint' is coupled with the entity 'Order' by the field 'order' inside 'Complaint' and - what I think is the
real coupling problem - by the Doctrine annotation pointing to "Order".
What I'm thinking of and would like to achieve is to write a bundle 'Complaints' which can be standalone or have additional, optional fields which can be configured to couple with different entity. For example - the bundle 'Complaints' can serve as a complaints bundle for any
entity which would eventually need complaints functionality.
The similiar situation I got with other bundles. Another example is 'User' entity from UserBundle which is related to 'Company' entity in CompanyBundle,
but the thing again is that I want the UserBundle to be standalone bundle which can be easily installed among different projects which not necessary need the CompanyBundle but
the User can be attached to another entity/entities. It goes futher because it is not only about doctrine annotations but views, created forms, validation, and many other
involved stuff.
What should be my approach to achieve that? Im quite new to symfony in fact and the idea of standalone reusable bundles is also quite new to me, before
I didn't any bundles but was developing applications as a whole. Also I would like to develop other, not related to my job, open-source bundles to share with others, so
I guess I need to apply to them this attitude of not being coupled to practically nothing else - how that can be achieved practically, can you share your experience, thoughts or point to explanatory articles?
Thank you very much for your guidelines and please take note it's a resonable question as there is a lack of know-how about decoupling bundles in Symfony community.
In your standalone bundles, you should declare your entities as abstract and set the doctrine annotation #MappedSuperclass on it.
Then, in your application, you will have to create your 'final' entities witch will be extend the mapped super class provided by your bundle.
Also, you will probably need to expose the FQCN of childs entities in your bundle configuration.
It can seem a little heavy, but unfortunatly Doctrine mapping is not overridable.
Here is some bundles implementing this solution :
Orbital/CmsBundle
FosUserBundle
To handle relations between your MappedSuperclass You have to use Interface in your relation annotation. Here is the official documentation about it.
Best regards

Reusing of entites in symfony or Dynamic mapping of entities

While Working on my project in Symfony, I realized that there is one entity(Assign Item to category) in my project which is being used in all other entities like products,categories,upsells etc as all of them need to be assigned to a category.
Is there a way that this entity can be reused?
I know a way where it can be defined in all ORM's (copy pasted in all entities), but want a more optimal solution to this.
Any help would be appreciated.
After doing a research, here is what I found.
There is a term called dynamic binding in Symphony where one entity can be used into another there by saving us from writing the same code again and again.
Here is the link that helped me:
https://www.theodo.fr/blog/2013/11/dynamic-mapping-in-doctrine-and-symfony-how-to-extend-entities/
Hope that helps someone.
Create a bundle with abstract classes that defines your entities. Don't forget to put there the annotations. Then load that bundle in your projects and extend your entities from these abstract classes. You can override methods or atributtes to customize to the certain usage. FosUserBundle works in that way
FOSUserBundle usage

How to extract actions from Symfony Controllers?

I'm refactoring a not-so-complex website based on Symfony 2.2 / PHP 5.3, and the main issue here is repeated code.
There are two bundles, one for the main website, and another with the mobile version. Those differences are not only on templates and static files, as they comprise some differences in business rules and so on.
Currently those two bundles sport three controllers, one being the main guy, another being the exceptions controller, but a third is the "mother-controller", that holds several common methods and behaviours, and is inherited by the actual controllers.
This poses a small problem, since I can't simply make the action controllers of the mobile bundle inherit from the desktop bundle. All I could do is implement inheritance between the mobile's DefaultController and the desktop one... And thus I still have a bunch of actions almost equal, except for some custom lines.
Is there a way to extract those actions to a generic class and them import them into the controllers (like we have in Yii's Action classes)? I searched about using the decorator pattern to no avail, and was wondering if there's any sort of known method to implement this idea.
Since you have two bundles my first idea would be to create another (let's call it "CoreBundle") and create CommonController there and put common logic into it. Then, let other controllers extend this CommonController.
The more cleaner, but harder, solution would be to create service which would be parametrized by needed data/services.

Why should plugins extend base classes from the application?

If you read the documentation for CakePHP on creating PlugIns. It clearly states that the PluginAppModel and PluginAppController base classes extend from the AppModel and AppController classes. Which are implemented in the application using the plugin.
This seems very risky to me.
A plugin doesn't have control over what callbacks, components, helpers, etc.. that an application may have configured in those base classes.
Is there any problems in having your PluginAppModel/PluginAppController extend just the base classes from the CakePHP lib. Like Model and Controller?
Can someone explain the logic in why a plugin should extend these application specific classes?
Not matter what you do, exclude the App* classes from the inheritage chain or if you include them. There will be always points of possible failure because it is not predictable what people do in these classes.
The less likely scenario is that things break in your plugin if you extend the App* base classes than when you would not extend them.
Auth and Session Component are in the case of a Controller a good reason why you should extend the App* classes. Behaviours in an AppModel another one.
If your plugin depends on a certain - unchanged - state of a property of the Controller or Model class you did something wrong while building that plugin in my opinion. It is better to keep your plugin flexible by providing configuration options or check the states of inherited properties and attached components and behaviours.
If there is really a pitfall in your plugin - I still think it's done wrong then - you should document it so that it can be integrated properly by people who read the documentation.

Doctrine 2 ORM and WordPress - Centralizing Doctrine management for multiple dependent applications

In WordPress, plugins are created and distributed as packages for other WordPress users to install.
Each of the plugins I'm creating share certain common entities in a core plugin. I'm struggling with creating and managing the EntitiyManager to use among these plugins.
I've come up with two ways to implement this and would like to hear some feedback before moving forward:
Option 1: Single, global EntityManager
// Example Plugin
// Unique Entities
// Add Unique Entity Paths and REQUIRED Entity Paths from Core Entities to EntityManager
// Example Plugin
// Unique Entities
// Add Unique Entity Paths and REQUIRED Entity Paths from Core Entities to EntityManager
// Core Plugin
// Core Entities
// Contains EntityManager
The problem with this version is that, although there is a way to add paths to a MetadataDriver:
$entityManager->getConfig()->getMetadataDriverImpl()->addPaths();
I am not sure if this will actually update the MetadataDriver within the config of this EntityManager. My worries is that this will only return a config that has been updated with the new paths and not update the EntityManager's config.
Is this true?
Note that there is no setConfig function so if it is, I would have to recreate the EntityManager from each plugin, defeating the purpose of a centralized EntityManager.
Option 2: Multiple EntityManagers
// Example Plugin
// Unique Entities
// Create EntityManager with Unique Entity path and path to Core Entities that are required for this plugin.
// Core Plugin
// Core Entities
The problem with this implementation is that it seems inefficient. I've noticed that there is a Doctrine plugin for WordPress, although it is Doctrine 1.2.3, and it allows you to have one centralized place as I would assume is appropriate for managing applications that share resources like the Core Entities.
What are your thoughts on using Doctrine in this scenario. Is there a way to centralize the operations so that the ORM is managed through one central plugin that others depend upon?
I was able to figure out that:
$entityManager->getConfiguration()->getMetadataDriverImpl()->addPaths();
Does in fact add additional paths to the $entityManager object and not just to the config that is returned with getConfiguration.
I will continue finishing up this implementation and update with my results here. Hopefully the core can become distributable as a plugin for other programmers to use.

Categories