Symfony 2 + Doctrine 2 overriding entity configuration - php

I have a case where I need to reuse common doctrine entities across multiple applications (that reside within the same project). These applications are merely instances of information system used by corresponding institutions.
I've isolated all entities and repositories into separate bundle and that worked like a charm so far. Here's the catch: I have received a requirement that only some of these instances need to support some other features. Modification would include adding new attributed/relations to some of entities.
Here is the brief example:
We have a university which has number of faculty units (instances, that is). Information system was built to support only bachelor studies program but a month ago we received requirement to support specialization and master studies as well. They want to handle all the them thought the same application instance. This applies only to some of these instances.
The question: Is there any way to "override" affected entities while keeping functionality of original ones? Can I override entity configuration (YAML or annotation, not important), at all? I would really like to keep the code base and not to copy all the entities/repositories to another package...

You can override classes metadata on entities loading by catching an event.
EventListener
<?php
namespace Lol\RandomBundle\EventListener;
use Doctrine\ORM\Event\LoadClassMetadataEventArgs;
class ClassMetadataListener
{
/**
* Run when Doctrine ORM metadata is loaded.
*
* #param LoadClassMetadataEventArgs $eventArgs
*/
public function loadClassMetadata(LoadClassMetadataEventArgs $eventArgs)
{
$classMetadata = $eventArgs->getClassMetadata();
// Override User class to flag MappedSuperclass.
if ('AnotherLol\AnotherRandomBundle\Entity\User' === $classMetadata->name) {
// Do whatever you want...
$classMetadata->isMappedSuperclass = true;
}
}
}
Services configuration
services:
lol.random.listener.class_metadata:
class: Lol\RandomBundle\EventListener\ClassMetadataListener
tags:
- { name: doctrine.event_listener, event: loadClassMetadata }

Sympatch provides tools to override any code part of your Symfony2 project, including entities, without destroying the code base. See https://github.com/DHorchler/SympatchBundle.

I don't know what this means. Looks like it is possible but not documented yet. I don't whether the documentation or the code is in progress.
In this issue, stof suggests it is not possible at all.
I think you should use SCM branches for this.

Related

Domain Mapping - Convert Models from external Software to internal structure

i'm currently working on a php-framework to abstract and make it fun and easy to work with an external software ($ES) my company consults. My approach is the hexagonal design pattern, which works great so far. My only concern is mapping (and where to map) entities from $ES to our internal structure.
Example:
$externalSoftwareProduct (kind of a god class which handles everything)
is mapped to $internalFrameworkProduct (and many other classes to split responsibilities). This happens in Repositories. In every repository method, i collect those entities from $ES and do
new $internalFrameworkProduct(some arguments here coming from
$externalSoftwareProduct)
foreach of my collected entities which then gets returned. In those repositories there are only generic methods, like getById, getAll, you name it.
Now we use this framework in a customer project and extend those base classes with domain specific extension, like CustomerNameProductRepository.
There you find domain specific methods like getProductsCustomerAlwaysNeeds and so on. At the end of those methods, we map the $internalFrameworkProduct to $customerSpecificProduct which holds data for easier access, which is needed. A method in this specific repository looks like this.
public function getProductsCustomerAlwaysNeeds()
{
$dataStuff = parent::getSomeStuff();
/** #var internalFrameworkProduct[] $products **/
$products = magic();
foreach($products as $product)
{
$customerProducts[] = $this->getCustomerSpecificProduct($product->getId());
}
return $customerProducts;
}
public function getCustomerSpecificProductById(int $productId)
{
$externalSoftwareProduct = new externalSoftwareProduct($productId)
$customerSpecificProduct = new CustomerSpecificProduct(some arguments here coming from $externalSoftwareProduct)
return $customerSpecificProduct;
}
Now this works fine so far. The only problem is in unit tests. We are using phpunit + Mockery. In order to mock those new created instances we have to use mock(overload:externalSoftwareProduct) and mock(overload: CustomerSpecificProduct) which is always a pain (especially if you try to test this with multiple instances, which is needed from time to time).
How would you approach this? There must be a better way to get those 3 Pieces connected (externalSoftwareProduct, internalFrameworkProduct and CustomerSpecificProduct (which extends internalFrameworkProduct)).
I was thinking about using a factory for the CustomerSpecificProduct in order to just mock the factory and let it spit out my Products. But i feel like im overengineering such a simple task.
«.... mapping (and where to map) entities from $ES to our internal structure...»
In the adapter you use to access the external software.

What is the usage of repositories and interfaces in Laravel?

After developing a few projects using Codeigniter since 2 years, I stared to learn Laravel.
I downloaded a few projects lo learn how they are coded. As I understood, many of them are using only models, views and controllers which is same as Codeigniter.
But one project has used repositories and interfaces. It is really hard to understand whats going on that project. So what is the usage of repositories and interfaces in Laravel? When should I use them?
I will try to explain as clearly as possible the two concepts.
Interfaces\Contracts
In general OOP interfaces are used to describe which methods/functionalities the class that implements that interface is offering without caring about the actual implementation.
Laravel uses Contracts mainly to separate a service from the actual implementation. To be more clear let's make an example
<?php
namespace App\Orders;
class OrdersCache
{
protected $cache;
public function __construct(\SomePackage\Cache\Memcached $cache)
{
$this->cache = $cache;
}
public function find($id)
{
if ($this->cache->has($id)) {
//
}
}
}
As you can see in this class the code is tightly coupled to a cache implementation (i.e. \SomePackage\Cache\Memcached) so if the API of that Cache class changes our code also must be changed accordingly. The same thing happens if we want to change the Cache implementation with another one (e.g. redis).
Instead of doing that, our code could depend on an interface that is agnostic from the implementation:
<?php
namespace App\Orders;
use Illuminate\Contracts\Cache\Repository as Cache;
class OrdersCache
{
public function __construct(Cache $cache)
{
$this->cache = $cache;
}
public function find($id)
{
if ($this->cache->has($id)) {
//
}
}
}
Now our code is not coupled with any specific implementation because Cache is actually an interface. So basically in our class we are requiring an instance of a class that behaves like described in the Cache interface, but we are not really interested in how it works internally. Doing that if we want to change the cache implementation we could write a class that implements the interface Cache without changing any line of code in our OrdersCache class. Doing that our code is easier to understand and maintain and your packages are a lot more reusable. See the section Loose Coupling in the Laravel documentation for further examples.
Interfaces and Service Container
One of the main features of Laravel is its Service Container, it is used to manage dependencies and performing dependency injection. Please take a look at Service Container definition from Laravel documentation.
Dependency Injection is widely used by Laravel also to bind interfaces to implementation. Let's make an example:
$app->bind('App\Contracts\EventPusher', 'App\Services\RedisEventPusher');
And let our class be
<?php
namespace App\Http\Controllers;
use App\Contracts\EventPusher;
class EventsController extends Controller
{
protected $pusher;
public function __construct(EventPusher $pusher)
{
$this->pusher = $pusher;
}
}
Without declaring anything else we are basically saying everytime that someone need an EventPusher instance, please Laravel, provide an instance of RedisEventPusher class. In this case everytime that your controller is instantiated, Laravel will pass an instance of RedisEventPusher to your controller without specifying anything else.
You can dig into that by looking at Binding Interfaces to Implementation section on the Laravel documentation.
Repositories
Repositories is a concept applicable to the MVC pattern independently from any specific framework. Typically you have your Model that is the data layer (e.g. interacts with the database directly), your Controller that handles the access logic to the data layer and your View that shows the data provided by the Controller.
Repositories instead could be defined as follows:
To put it simply, Repository pattern is a kind of container where data access logic is stored. It hides the details of data access logic from business logic. In other words, we allow business logic to access the data object without having knowledge of underlying data access architecture.
Soruce: https://bosnadev.com/2015/03/07/using-repository-pattern-in-laravel-5
To know how to use them within Laravel please take a look at this great article.
That's all, i hope it helps to clear up your mind.
Interfaces are what any implementing class should call.
interface CanFlyInterface
{
public function fly();
}
Think of it like programming without bothering with logic.
if ($object instanceof CanFlyInterface) {
$obj->fly();
}
Now we could have passed a Bird object, or an Aeroplane object! PHP DOESN'T CARE, so long as it implements the interface!
class Bird implements CanFlyInterface
{
public function fly()
{
return 'flap flap!';
}
}
class Aeroplane implements CanFlyInterface
{
public function fly()
{
return 'roar! whoosh!';
}
}
Your other question, what a Repository class is. It's just a class that keeps all your DB queries in the one place. Check this interface as an example:
interface RepositoryInterface
{
public function insert(array $data);
public function update(array $data);
public function findById($id);
public function deleteById($id);
}
Hopefully this should clear things up for you! Good luck with all your PHP coding :-D
Let's start with the easier one, the interface:
You normally use interfaces to implement classes with required methods:
http://php.net/manual/en/language.oop5.interfaces.php
Laravel's Contracts are a set of interfaces that define the core services provided by the framework. For example, a Illuminate\Contracts\Queue\Queue contract defines the methods needed for queueing jobs, while the Illuminate\Contracts\Mail\Mailer contract defines the methods needed for sending e-mail.
https://laravel.com/docs/5.4/contracts#introduction
When Laravel is running it can check if a class implements a special interface:
if ($cls instanceof IInterface) {
$cls->interfaceFunction();
}
Since Laravel is able to work with queues it will check if the event should be queued or not by checking for an exiting interface.
To inform Laravel that a given event should be broadcast, implement the Illuminate\Contracts\Broadcasting\ShouldBroadcast interface on the event class.
https://laravel.com/docs/5.4/broadcasting#defining-broadcast-events
Repository:
I didn't found that much about this:
Our repository should not have so much knowledge regarding who is providing them data or how they are providing it. https://laravel.com/docs/5.4/contracts#loose-coupling
But I found some other information on a webpage:
a Repository will connect Factories with Gateways
https://code.tutsplus.com/tutorials/the-repository-design-pattern--net-35804
The link will give you more information about the the details.
Hope I could help you :)
First of all, using Repository and Interface in larger application is not only beneficiary in Laravel but in all technology for coding standard as well as for separation of concern.
According to Microsoft (I found best explanation here)
Why to use Repository:
Use a repository to separate the logic that retrieves the data and
maps it to the entity model from the business logic that acts on the
model. The business logic should be agnostic to the type of data that
comprises the data source layer. The repository mediates between the
data source layer and the business layers of the application. It
queries the data source for the data, maps the data from the data
source to a business entity, and persists changes in the business
entity to the data source.
A repository separates the business logic
from the interactions with the underlying data source or Web service.
The separation between the data and business tiers has three benefits:
It centralizes the data logic or Web service access logic. It provides
a substitution point for the unit tests. It provides a flexible
architecture that can be adapted as the overall design of the
application evolves. There are two ways that the repository can query
business entities. It can submit a query object to the client's
business logic or it can use methods that specify the business
criteria. In the latter case, the repository forms the query on the
client's behalf. The repository returns a matching set of entities
that satisfy the query.
For Interface, you have a lot of answers above, hope you have understand.
First of all, repositories and interfaces are not specific to Laravel but common coding standards in most of the languages.
Below Laracasts videos will be useful to understand the basics if you don't mind spend few dollars.
https://laracasts.com/lessons/repositories-and-inheritance
https://laracasts.com/series/object-oriented-bootcamp-in-php

Configurable dynamic Doctrine database entities in Symfony 2

What I am trying to achieve
Users would be able to configure Doctrine entities through an HTML form on a website.
Users would be able to define new entities, as well as add and delete fields for existing entities. (Similar to Drupal's content types)
The Doctrine entities would get dynamic properties based on the configuration that the user supplied through the web UI.
Either the single DB table per Doctrine entity would be altered dynamically whenever an entity configuration changes; Or there could be multiple tables used per single entity (each new entity field would get its own table).
Done so far
I have been researching this for the past few days without much success but I stumbled across this answer which seems quite related to what I am trying to achieve.
I have registered and added the loadClassMetadata listener which maps the field foo:
// src/DynamicMappingTest/AdminBundle/EventListener/MappingListener.php
namespace DynamicMappingTest\AdminBundle\EventListener;
use Doctrine\ORM\Event\LoadClassMetadataEventArgs;
class MappingListener
{
public function loadClassMetadata(LoadClassMetadataEventArgs $eventArgs)
{
$classMetadata = $eventArgs->getClassMetadata();
if ($classMetadata->getName() != 'DynamicMappingTest\\AdminBundle\\Entity\\CustomNode')
{
// Not the CustomNode test class. Do not alter the class metadata.
return;
}
$table = $classMetadata->table;
$oldName = $table['name']; // ... or $classMetaData->getTableName()
// your logic here ...
$table['name'] = 'custom_node';
$classMetadata->setPrimaryTable($table);
$reflClass = $classMetadata->getReflectionClass();
dump($reflClass);
// ... or add a field-mapping like this
$fieldMapping = array(
'fieldName' => 'foo',
'type' => 'string',
'length' => 255
);
$classMetadata->mapField($fieldMapping);
}
}
Now, this all works as long as I have the foo property declared in the DynamicMappingTest\AdminBundle\Entity\CustomNode class:
// src/DynamicMappingTest/AdminBundle/Entity/CustomNode.php
namespace DynamicMappingTest\AdminBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* CustomNode
*
* #ORM\Table()
* #ORM\Entity(repositoryClass="DynamicMappingTest\AdminBundle\Entity\CustomNodeRepository")
*/
class CustomNode
{
...
private $foo;
}
Problem
However, there is no way for me to know what properties the users will define for their custom entities. If I remove the foo property from the CustomNode class, the ReflectionClass that I get from the ClassMetadata will naturally not include the foo property and so I get the following exception whenever the mapField() in MappingListener is executed:
ReflectionException: Property DynamicMappingTest\AdminBundle\Entity\CustomNode::$foo does not exist
in vendor/doctrine/common/lib/Doctrine/Common/Persistence/Mapping/RuntimeReflectionService.php at line 80
77. */
78. public function getAccessibleProperty($class, $property)
79. {
80. $reflectionProperty = new ReflectionProperty($class, $property);
81.
82. if ($reflectionProperty->isPublic()) {
83. $reflectionProperty = new RuntimePublicReflectionProperty($class, $property);
Questions
Is it possible to have fully configurable dynamic Doctrine entities?
Am I on the right track with my approach? If not, could you suggest an alternative?
How could I have truly dynamic class properties? Or should I be generating new Doctrine entity PHP classes whenever the users change the entity configuration?
Is it possible to have fully configurable dynamic Doctrine entities?
Doctrine generates proxy classes for you entities. That means that doctrine generates PHP code with class, which extends your Entity class and overrides the methods - puts some custom logic and then calls the parent method.
So, I think that the only way to make this really happen is to generate the PHP code for entities in your code. That is, every time entity is created in your website, you should generate PHP file with that entity, then run migrations.
Am I on the right track with my approach? If not, could you suggest an alternative?
I don't think that you should use Doctrine ORM at all in this case, at least in the way you're trying to do that.
Generally, ORM is used for easier/more manageable programming. That is, you can set relations, use lazy-loading, unit of work (change entity properties and then just flush) etc. If your entities are generated dynamically, what features will you use at all? Developer will not write code for these entities, because, as you've said, there is no way to know what fields it will have.
You haven't provided concrete use-case - why do you want to do that in the first place. But I imagine that it could be really done in some easier way.
If users can store any structure at all, should you use MySQL at all? ElasticSearch or similar solutions could be really much better in such cases.
How could I have truly dynamic class properties? Or should I be generating new Doctrine entity PHP classes whenever the users change the entity configuration?
As I've mentioned - yes. Unless you would want to override or replace some of Doctrine code, but I imagine it could be lots of it (proxy classes etc.)

How should 3rd party bundles be wrapped in Symfony2?

If I add a 3rd party bundle, say from Knp bundles for example, should I wrap it first or should I use it directly in my code?
If I decide to wrap it, where do I put the wrapping code? In a separate new bundle? In my application bundle?
To clarify:
I'm not asking about how to add a thirds party bundle to my project.
I'm not asking what a bundle is.
This question is aimed at encapsulating 3rd party code behind wrapper classes. Since the bundle was developed by a 3rd party developer it is a subject for unexpected changes that could break my code.
How do you wrap a 3rd party bundle after adding it to your project?
This is an answer for 3rd party bundles included via composer in Symfony2 in general, it does not refer to a special bundle.
First of all
As long as you are fixing the version of the requested bundle to a stable version (like 1.*) in your composer.json (and as long as the developer follows his own guide lines), you shouldn't have any problems with compatibility breaks of the interfaces, thus wrapping is not necessary.
But I'm assuming that you want to prevent any code breaks by throwing Exceptions in the wrapper code and/or implementing fallbacks, so that everything that uses the wrapper code could still work or at least display appropriate errors.
If you want to wrap
If you want to use the dev-master version of a given 3rd party bundle, major changes might occur. But there shouldn't be a case where you really want to include the dev-master when there are stable versions.
Anyway, there are two ways that I see, that could make sense in the case that you want to include the dev-master or want to wrap it to display errors, log them, catch exceptions etc.:
Build a single service class that uses all instances of the services of the 3rd party bundle
This service class could be in one of your bundles that uses the 3rd party bundle, there's no need for an extra bundle in this approach.
This way you have a single service like acme.thirdparty.client that wraps single method calls of other services. You would need to inject all 3rd party services that you need (or create instances of the desired sub classes) and wrap all desired method calls.
# src/Acme/MyBundle/Resources/config/services.yml
parameters:
acme.thirdparty.wrapper.class: Acme\MyBundle\Service\WrapperClass
services:
acme.thirdparty.wrapper:
class: %acme.thirdparty.wrapper.class%
arguments:
someService: #somevendor.somebundle.someservice
someOtherService: #somevendor.somebundle.someotherservice
And the service class:
<?php
namespace Acme\MyBundle\Service;
use SomeVendor\SomeBundle\SomeService\ConcreteService;
use SomeVendor\SomeBundle\SomeService\OtherConcreteService;
class WrapperClass
{
private $someService;
private $someOtherService;
public function __construct(ConcreteService $someService, OtherConcreteService $someOtherService)
{
$this->someService = $someService;
$this->someOtherService = $someOtherService;
}
/**
* #see SomeVendor\SomeBundle\SomeService\ConcreteService::someMethod
*/
public function someMethod($foo, $bar = null)
{
// Do stuff
return $this->someService->someMethod();
}
/**
* #see SomeVendor\SomeBundle\SomeService\ConcreteOtherService::someOtherMethod
*/
public function someOtherMethod($baz)
{
// Do stuff
return $this->someOtherService->someOtherMethod();
}
}
You could then add some error handling to those method calls (like catching all exceptions and log them etc.) and thus prevent any code outside of the service class to break. But needless to say, this does not prevent any unexpected behaviour of the 3rd party bundle.
or you could:
Create a bundle that has multiple services, each wrapping a single service of the 3rd party bundle
A whole bundle has the advantage of being more flexible on what you exactly want to wrap. You could wrap a whole service or just single repositories and replace the wrapped classes with your own ones. The DI container allows the overriding of injected classes, like the following:
# src/Acme/WrapperBundle/Resources/config/services.yml
parameters:
somevendor.somebundle.someservice.class: Acme\WrapperBundle\Service\WrapperClass
By overriding the class parameter somevendor.somebundle.someservice.class all services that use this class are now instances of Acme\WrapperBundle\Service\WrapperClass. This wrapper class could be either extending the base class:
<?php
namespace Acme\WrapperBundle\Service;
use SomeVendor\SomeBundle\SomeService\ConcreteService;
class WrapperClass extends ConcreteService
{
/**
* #see ConcreteService::someMethod
*/
public function someMethod($foo, $bar = null)
{
// Do stuff here
parent::someMethod($foo, $bar);
// And some more stuff here
}
}
... or could use an instance of the original class to wrap it:
<?php
namespace Acme\WrapperBundle\Service;
use SomeVendor\SomeBundle\SomeService\ConcreteServiceInterface;
use SomeVendor\SomeBundle\SomeService\ConcreteService;
class WrapperClass implements ConcreteServiceInterface
{
private $someService;
/**
* Note that this class should have the same constructor as the service.
* This could be achieved by implementing an interface
*/
public function __construct($foo, $bar)
{
$this->someService = new ConcreteService($foo, $bar);
}
/**
* #see ConcreteService::someMethod
*/
public function someMethod($foo, $bar = null)
{
// Do stuff here
$this->someService->someMethod($foo, $bar);
// And some more stuff here
}
}
Note that implementing an interface for a class that is overriding another one might be mandatory. Also the second one might not be the best idea, since then it's not very clear that you are actually wrapping the ConcreteService and not just replacing it. Also this is ignoring the whole idea of Dependency Injection.
This approach needs a lot more work and means a lot more testing, but if you want more flexibility, this is the way to go.
Perhaps there already are wrapper bundles for your desired 3rd party bundles around (like the SensioBuzzBundle for the Buzz Browser), in this case, you could porbably use those instead of writing everything yourself.
Conclusion
Trusting the developer and including a stable version (like 1.* for bugfixes and new features or 1.0.* for bugfixes only) is the way to go. If there are no stable versions or if you want to include the dev-master, wrapping is an option. If you want to wrap your code, building an extra bundle is the more flexible way, but a single service class could be enough if there's not much code to wrap.
The documentation for this bundle is available in the Resources/doc
directory of the bundle:
Read this it is easy to use.
add your bundle into /vendor/bundles
Add the following namespace entries to the registerNamespaces call in your autoloader:
// app/autoload.php
or Configure the bundle in
app/config/config.yml

Dependency Injection and dependencies not used

First of all, sorry for my bad English, I hope you understand what I'm saying.
Here is my problem:
Lets assume i have an MVC application including standard router, controller, model(service) layer and some kind of db connector.
Model layer depends on a db connector, controllers depends on models/services and the top-level "application" class depends on routers and controllers.
My object hierarchy looks like this:
App -> ControllerFactory -> ServiceFactory -> DAO -> DbConnection
Perhaps, written above doesn't look like best application architecture ever, but i want to focus on the other thing:
When i'm trying to instantiate an App class i should pass all dependencies to the class instantiated; class dependencies, in turn, has their own dependencies and so on.
As a result I get all hierarchy stack instantiated at once. But what if i dont need to access the database in some cases; what if some controllers are used for rendering static templates without model interaction?
I mean, what if there are some special cases when class does not require its own dependencies(and in some cases it does)? Should i inject dependencies conditionaly or something?
I'm really stuck at this point and i don't know what to do.
Update: after re-reading carefully your question, here is another advice: yes, every class has different dependencies.
Don't inject every object into every other object. For example, some services might need DAOs, so inject them. But if a service doesn't need a DAO, don't inject any DAO.
The rest of my answer is valid if you have (for example) a service that needs a DAO (and thus a DB connection) not for every method.
What you may be looking for is lazy injection.
It is the act of injecting a dependency not loaded, so that the object is loaded only if/when used.
In conrete terms, that means injecting a proxy object, that would look like and behave exactly like the original object (for example, the db connection).
Several DI container (frameworks) support this so you don't have to create proxies yourself. I'll take as an example PHP-DI (I work on that project FYI).
Here is an example using annotations:
use DI\Annotation\Inject;
class Example {
/**
* #Inject(lazy=true)
* #var My\Class
*/
protected $property;
/**
* #Inject({ "param1" = {"lazy"=true} })
*/
public function method(My\Class $param1) {
}
}
Of course if you don't want to use annotations you can use any other configuration you want (PHP, YAML, …). Here is the same example by configuring the container in pure PHP:
$container->set('Example')
->withProperty('property', 'My\Class', true)
->withMethod('method', array('param1' => array(
'name' => 'My\Class',
'lazy' => true,
)));
See more in the documentation about Lazy Injection.
Note: you may not be using a Container for now (and that's not a problem), but for tackling lazy injection this is a fair amount of work and you might need to start considering using one.
If your dependency construction is complex, simply add a new factory class that should contain all the logic to create a correct object for you.
class AppFactory(){
__construct(all params){
}
build(useDB=true){
// logic to build
if(useDB){
App = new App(new ControllerFactory(new ServiceFactory(new DAO(new DbConnection(params)))))
} else {
App = new App(new ControllerFactory(new ServiceFactory(null))))
}
return App;
}
}

Categories