New guy at Symfony/Doctrine. So kindly guide me.
Requirement: To create a custom EntityManager which would override some of the methods like remove (instead of remove, i want to perform an update and modify a parameter like isValid in my class, so that the records are never deleted) and a find ( find a record which has a non zero isValid ) etc and use it instead of Doctrine's EntityManager.
I started reading through this thread:
Is there a way to specify Doctrine2 Entitymanager implementation class in Symfony2? and found the answer by user2563451 to be not so straightforward. I got lost when he talks about not to follow certain approaches (again no location of the files to be modified).
I have looked at the EntityManager.php and it specifically tells not to use extend the EntityManager class. Rather it asks to extend the EntityManagerDecorator. On looking at the EntityManagerDecorator, there are no methods available inside it (like create, persist, etc which I found in EntityManager) Does it mean I need to create new methods for each and every single Entity Manager functionality ?
Since there is no clear defined way to get this done, I am confused to get this thing started. Also Doctrine cookbook is of little use to me as it does not have any information to achieve this.
So any help regarding the extending of EntityManagerDecorator or EntityManager is appreciated.
Best if you can provide me step by step directions to achieve the same.
Thanks !
Edit 1: my requirement is to use my custom EntityManager instead of Doctrine's EntityManager (EM) and modify those 'remove' and 'find' methods as per my requirements. I am not sure whether I need to reuse the functionality provided by Doctrine's EM or write from scratch.
I think you may be confusing a Manager with a Repository.
An EntityManager is really nothing more than a Service you use to manage that specific or a collection of entities.
A repository extends \Doctrine\ORM\EntityRepository and is what tells Doctrine how to store your entity in the database.
You can use the combination of these two to achieve what you want.
For example. Let's take our entity Foo
class Foo
{
//...other properties
protected $isValid;
//...Getters and setters
}
We then have a manager for Foo.
class FooManager
{
protected $class;
protected $orm;
protected $repo;
public function __construct(ObjectManager $orm , $class)
{
$this->orm = $orm;
$this->repo = $orm->getRepository($class);
$metaData = $orm->getClassMetadata($class);
$this->class = $metaData->getName();
}
public function create()
{
$class = $this->getClass();
$foo = new $class;
return $foo;
}
public function findBy(array $criteria)
{
return $this->repo->findOneBy($criteria);
}
public function refreshFoo(Foo $foo)
{
$this->orm->refresh($foo);
}
public function updateFoo(Foo $foo, $flush = true)
{
$this->orm->persist($foo);
if($flush)
{
$this->orm->flush();
}
}
public function getClass()
{
return $this->class;
}
}
We have some basic functions for Creating and Updating our object. And now if you wanted to "remove" it without actually deleting it, you can add the following function in the Manager.
public function remove(Foo $foo)
{
$foo->setIsValid(false);
return $this->update($foo);
}
This way, we update the isValid fields to false and persist it to the database. And you'd use this like any service inside your controller.
class MyController extends Controller
{
public function someAction()
{
$fooManager = $this->get('my_foo_manager');
$newFoo = $fooManager->create();
//...
$fooManager->remove($newFoo);
}
}
So now we've got the remove part.
Next, we only want to find entities that isValid set to TRUE.
Honestly, the way I'd handle this is not even modify the find and instead in your controller
if(!$foo->getIsValid())
{
//Throw some kind of error. Or redirect to an error page.
}
But if you want to do it the other way. You can just make a repo.
use Doctrine\ORM\EntityRepository;
class FooRepository extends EntityRepository
{
public function find($id, $lockMode = LockMode::NONE, $lockVersion = null)
{
//Some custom doctrine query.
}
}
We override EntityRepository's native find() function with our own.
Finally we get all of this registered in the right places. For the manager you've got to make a service.
services:
my_foo_manager:
class: AppBundle\Manager\FooManager
arguments: [ "#doctrine.orm.entity_manager" , 'AppBundle\Entity\Foo']
And for the repository, you must specify the repositoryClass in the ORM definition of your entity.
AppBundle\Entity\Foo:
type: entity
repositoryClass: AppBundle\Entity\FooRepository
table: foos
id:
id:
type: integer
generator: {strategy: AUTO}
options: {unsigned: true}
fields:
isValid:
type: boolean
Knowing all of this you can now do some pretty cool things with Entities. I hope this helped. Good luck!
Regarding your use cases, you should instead use Doctrine Lifecycle Callbacks for the remove case and simple overide the find method in your entity repository.
Related
I read some articles about repository pattern and I want to know the reason why the constructor is needed when I can directly call the Model and return the data? I also think that Book::all(); is less code than $this->model->all(). Is it just a good practice or it has some purpose?
class BookRepository implements RepositoryInterface {
private $model;
public function __construct(Book $model)
{
$this->model = $model;
}
public function index()
{
return $this->model->all();
}
}
and
class BookRepository implements RepositoryInterface {
public function index()
{
return Book::all();
}
}
The primary reason is Inversion of Control, basically letting your application determine what should be provided to fulfill that dependency. The reason this is important is, in the event you decide to refactor that code, you can simply tell Laravel to load a different implementation. No code need be altered in the Repository itself.
This however leads into the idea of not using classes directly, and using interfaces instead to declare your dependancies. That way any implementation can be swapped out and your code remains readable.
class BookRepository {
public function __construct(BookInterface $book)
{
$this->book = $book;
}
}
Now your Repository doesn't really care about the actual class, just that it implements the book interface which enforces a specific set of methods be defined. An example of the benefit is if you're using, say, MySQL as a database for your Book but switch to Postgres you may need to significantly change the underlying code but want to keep both implementations for legacy reasons. You can easily tell Laravel to load your standard Book class, or your new PostgresBook class because both still implement the BookInterface.
Your Repository doesn't need to change at all. Just add a bind and you're good.
Another more direct example is if you decided you wanted to switch from Eloquent to ActiveRecord.
Both will work but if for any reason you want to change the model class [Book] with any other model for example [MyBook] so in this case, you will change only the constructor parameter, not all the functions which use [Book]
public function __construct(MyBook $model)
{
$this->model = $model;
}
I am currently facing a very interesting dilemma with my architecture and implementation.
I have an interface called ServiceInterface which have a method called execute()
Then I have two different implementations for this interface: Service1 and Service2, which implements the execute method properly.
I have a controller called MainController and this controller has a "type-hint" for the ServiceInterface (dependency injection), it means that both, Service1 and Service2, can be called as resolution for that dependency injection.
Now the fun part:
I do not know which of those implementations to use (Service1 or Service2) because I just know if I can use one or other based on a user input from a previous step.
It means the user choose a service and based on that value I know if a can use Service1 or Service2.
I am currently solving the dependency injection using a session value, so depending of the value I return an instance or other, BUT I really think that it is not a good way to do it.
Please, let me know if you faced something similar and, how do you solve it, or what can I do to achieve this in the right way.
Thanks in advance. Please let me know if further information is required.
Finally, after some days of researching and thinking a lot about the best approach for this, using Laravel, I finally solved it.
I have to say that this was especially difficult in Laravel 5.2 because, in this version, the Session middleware only is executed in the controllers used in a route, it means that if for some reason I used a controller (not linked for a rote) and try to get access to the session it is not going to be possible.
So, because I cannot use the session, I decided to use URL parameters. Here you have the solution approach; I hope some of you found it useful.
so, you have an interface:
interface Service
{
public function execute();
}
Then a couple of implementations for the interface:
Service one:
class ServiceOne implements Service
{
public function execute()
{
.......
}
}
Service two.
class ServiceTwo implements Service
{
public function execute()
{
.......
}
}
The interesting part is that I have a controller with a function with a dependency with the Service interface. Still, I need to resolve it dynamically to ServiceOne or ServiceTwo based on user input. So:
The controller
class MyController extends Controller
{
public function index(Service $service, ServiceRequest $request)
{
$service->execute();
.......
}
}
Please note that ServiceRequest, validated that the request already have the parameter that we need to resolve the dependency (call it 'service_name')
Now, in the AppServiceProvider we can resolve the dependency in this way:
class AppServiceProvider extends ServiceProvider
{
public function boot()
{
}
public function register()
{
//This specific dependency is going to be resolved only if
//the request has the service_name field stablished
if(Request::has('service_name'))
{
//Obtaining the name of the service to be used (class name)
$className = $this->resolveClassName(Request::get('service_name')));
$this->app->bind('Including\The\Namespace\For\Service', $className);
}
}
protected function resolveClassName($className)
{
$resolver = new Resolver($className);
$className = $resolver->resolveDependencyName();
return $className;
}
}
So now all the responsibility is for the Resolver class. This class basically use the parameter passed to the constructor to return the full name (with namespace) of the class that is going to be used as an implementation of the Service interface:
class Resolver
{
protected $name;
public function __construct($className)
{
$this->name = $className;
}
public function resolveDependencyName()
{
//This is just an example, you can use whatever as 'service_one'
if($this->name === 'service_one')
{
return Full\Namespace\For\Class\Implementation\ServiceOne::class;
}
if($this->name === 'service_two')
{
return Full\Namespace\For\Class\Implementation\ServiceTwo::class;
}
//If none, so throw an exception because the dependency can not be resolved
throw new ResolverException;
}
}
Well, I really hope it helps some of you.
Best wishes!
---------- EDIT -----------
I just realize that it is not a good idea to use the request data directly inside the container of Laravel. It really is going to cause some trouble in the long term.
The best way is to directly register all the possible instances supported (serviceone and servicetwo) and then resolve one of them directly from a controller or a middleware, so then is the controller "who decides" what service to use (from all the available) based on the input from the request.
In the end, it works at the same, but it is going to allow you to work more naturally.
I have to say thanks to rizqi, a user from the questions channel of the slack chat of Laravel.
He personally created a golden article about this. Please read it because it solves this issue completely and in a very right way.
laravel registry pattern
The fact that you define that your controller works with ServiceInterface is ok
If you have to choose the concrete implementation of the service basing on a previous step (that, as i've understood, happens in a previous request) storing the value in session or in database is right too, as you have no alternative: to choose the implementation you have to know the value of the input
The important point is to 'isolate' the resolution of the concrete implementation from the input value in one place: for example create a method that takes this value as a parameter and returns the concrete implementation of the service from the value:
public function getServiceImplementation($input_val)
{
switch($input_val)
{
case 1 : return new Service1();
case 2 : return new Service2();
}
}
and in your controller:
public function controllerMethod()
{
//create and assign the service implementation
$this->service = ( new ServiceChooser() )->getServiceImplementation( Session::get('input_val') );
}
In this example i've used a different class to store the method, but you can place the method in the controller or use a Simple Factory pattern, depending on where the service should be resolved in your application
It's an interesting problem. I'm currently using Laravel 5.5 and have been mulling it over. I also want my service provider to return a specific class (implementing an interface) based upon user input. I think it's better to manually pass the input from the controller so it's easier to see what's going on. I would also store the possible values of the class names in the config.
So based upon the Service classes and interface you've defined above i came up with this:
/config/services.php
return [
'classes': [
'service1' => 'Service1',
'service2' => 'Service2',
]
]
/app/Http/Controllers/MainController.php
public function index(ServiceRequest $request)
{
$service = app()->makeWith(ServiceInterface::class, ['service'=>$request->get('service)]);
// ... do something with your service
}
/app/Http/Requests/ServiceRequest.php
public function rules(): array
$availableServices = array_keys(config('services.classes'));
return [
'service' => [
'required',
Rule::in($availableServices)
]
];
}
/app/Providers/CustomServiceProvider.php
class CustomServiceProvider extends ServiceProvider
{
public function boot() {}
public function register()
{
// Parameters are passed from the controller action
$this->app->bind(
ServiceInterface::class,
function($app, $parameters) {
$serviceConfigKey = $parameters['service'];
$className = '\\App\\Services\\' . config('services.classes.' . $serviceConfigKey);
return new $className;
}
);
}
}
This way we can validate the input to ensure we are passing a valid service, then the controller handles passing the input from the Request object into the ServiceProvider. I just think when it comes to maintaining this code it will be clear what is going on as opposed to using the request object directly in the ServiceProvider.
PS Remember to register the CustomServiceProvider!
I find the best way to deal with this is using a factory pattern. You can create a class say ServiceFactory and it has a single method create() it can accept an argument which is used to dynamically choose which concrete class to instantiate.
It has a case statement based on the argument.
It will use App::make(ServiceOne::class) or App::make(ServiceTwo::class).depending on which one is required.
You are then able to inject this into your controller (or service which depends on the factory).
You can then mock it in a service unit test.
Recently, I had to implement a similar logic where I was to implement a method to perform mobile top-ups for multiple networks in our application. So, I decided to implement the logic using Factory and Bridge pattern. Factory to create an instance of the concrete Service class based on the user input, and then, the Bridge pattern to set closely related classes into separate hierarchies and route the request to the respective class.
In the controller's method, both Factory and Service classes are injected. The TopUpServiceFactory's create method creates an object of the concrete class. The TopUpService class then routes the request to that concrete class method.
class TopUpController extends Controller
{
public function topUp(Request $request, TopUpServiceFactoryInterface $serviceFactory, TopUpServiceInterface $topUpService)
{
$serviceFactory->create($request->networkCode);
$topUpService->TopUp($request->all());
}
}
The TopUpServiceFactoryInterface and TopUpServiceInterface are bound to TopUpServiceFactory and TopUpService concrete Classes respectively in Service Container.
class AppServiceProvider extends ServiceProvider
{
public function register()
{
$this->app->bind(TopUpServiceFactoryInterface::class, TopUpServiceFactory::class);
$this->app->bind(TopUpServiceInterface::class, TopUpService::class);
}
}
The create method accepts user input and creates an object of the respective class based on the user input.
class TopUpServiceFactory implements TopUpServiceFactoryInterface
{
public function create(string $networkCode)
{
switch ($networkCode) {
case 'network1':
app()->bind(NetworkServiceInterface::class, Network1Service::class);
break;
case 'network2':
app()->bind(NetworkServiceInterface::class, Network2Service::class);
break;
default:
app()->bind(NetworkServiceInterface::class, DefaultNetworkService::class);
break;
}
}
}
The Service Class then picks the object of NetworkService Class and forwards the request.
class TopUpService implements TopUpServiceInterface
{
public function topUp(array $requestParams)
{
$networkService = app()->get(NetworkServiceInterface::class);
$networkService->topUp($requestParams);
}
}
All network's concrete classes implement a common interface NetworkServiceInterface, which is used to inject dependency dynamically, implementing Liskov Substitution Principle
class Network1Service implements NetworkServiceInterface
{
public function topUp(array $requestParam)
{
Process Topup ......
}
}
class Network2Service implements NetworkServiceInterface
{
public function topUp(array $requestParam)
{
Process Topup ......
}
}
...
I posted another question trying to find a way to statically access a repository class outside of a controller in a custom "helper" class.
So far the only way I have figured out how to achieve this is using the code below. If anyone wants to chime into the other question about "best practice" or "design patterns" please do.
I opened this question to seek the best method on having a singleton service (?) loaded when symfony boots so other classes can access it statically without any dependency injection. I haven't had much luck on finding any official docs or common practices. I know singleton is anti practice, but is the method below the best way, or is there a more ideal solution?
services.yml
parameters:
entity.device: Asterisk\DbBundle\Entity\Device
services:
asterisk.repository.device:
class: Asterisk\DbBundle\Entity\Repositories\DeviceRepository
factory: ["#doctrine.orm.asterisk_entity_manager", getRepository]
arguments:
- %entity.device%
tags:
- {name: kernel.event_listener, event: kernel.request, method: onKernelRequest}
DeviceRepository
class DeviceRepository extends \Doctrine\ORM\EntityRepository
{
/** #var ExtendedEntityRepository */
protected static $instance;
public function __construct(EntityManager $entityManager, ClassMetadata $class)
{
parent::__construct($entityManager, $class);
if(static::$instance instanceof static == false)
static::$instance = $this;
}
public static function getInstance()
{
return static::$instance;
}
public function onKernelRequest($event)
{
return;
}
}
Glad to see you are not running around anymore.
Your approach is not going to work unless someone grabs the repository out of the container first so self::$instance is initialized. But you really don't want to do this anyways. Super hacky.
You want to inject the repository service into your kernel listener. Trying to make the repository act as a kernel listener is just not a good design. So just make a service for your repository and then a second one for the listener. It may seem a bit strange at first but it really does work well in practice and it's the way S2 is designed.
If for some reason you are stuck with the notion that you have to be able to access the container globally then be aware that your kernel is defined globally(take a look at app.php) and it has a getContainer method in it.
$repo = $_GLOBAL['kernel']->getContainer()->get('asterisk.repository.device');
But again, there should be no need to do this.
==============================
Update - It looks like you are trying to use the listener functionality just to setup singletons. You should try to avoid singletons but if you really think you need them then the global access to the kernel can be used:
class DeviceRepository extends \Doctrine\ORM\EntityRepository
{
/** #var ExtendedEntityRepository */
protected static $instance;
public static function getInstance()
{
if (!static::$instance) {
static::$instance = $_GLOBAL['kernel']->getContainer()->get('asterisk.repository.device');
}
return static::$instance;
}
Poor design but at least it get's rid of the listener hack and it avoids creating the repository until it's actually needed. It aslo means you can access the repository from commands (listeners are not setup when commands are called).
I do not understand what the profit will be about this method. The idea of the servicecontainer is to make just one instance of each class and give a reference (or pointer if you like) to any method who asks to use this same instance. Let me proof it:
Service definition:
// app/config.yml
services:
app.test:
class: Vendor\AppBundle\Service\Test
and a custom class:
// src/AppBundle/Service/Test.php
namespace AppBundle/Service;
class Test {
public $test = 0;
}
and a controller:
// src/AppBundle/Controller/DefaultController
namespace AppBundle/Controller;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\Request;
class DefaultController extends Controller
{
/**
* #Route("/", name="homepage")
*/
public function indexAction()
{
$instance1 = $this->get('app.test');
$instance2 = $this->get('app.test');
$instance1->test = 1;
echo $instance2->test; // RETURNS 1 !!!
exit;
}
Read books From Apprentice To Artisan and Implementing Laravel by Chris Fidao and now i don't know how to correctly work with Models in Repositories.
In Implementing laravel book author is working with models in this way:
Example #1
<?php
use MyApp\Interfaces\UserInterface;
use Illuminate\Database\Eloquent\Model;
class UserRepository implements UserInterface
{
protected $user;
public function __construct(Model $user)
{
$this->user = $user;
}
public function find($userId)
{
return $this->user->find($userId);
}
}
But that can by done in other way, not injecting Model as a dependency, like this:
Example #2
Built example using tutorial http://culttt.com/2013/07/08/creating-flexible-controllers-in-laravel-4-using-repositories/
<?php
use MyApp\Interfaces\UserInterface;
use MyApp\Models\User\User;
class UserRepository implements UserInterface
{
public function find($userId)
{
return User::with('profile')->find($userId);
}
}
Why in first example Model is injected, why not use directly Model like in example two?
Which way is correct and why ?
Also which way will be more testable with integrated to laravel UnitTest package ?
The example 2 is bad because it's coupling your repository to a particular implementation of the User model.
Every time you use your repository it'll need to instantiate Univemba\Models\User\User. The whole idea of Dependency Injection is to inject (send) in to your object whatever dependencies it has. If your object needs a Model to work with you can send it a Laravel Eloquent Model, but any of your co-workers could also need to send to it a Doctrine Model. But if you couple your class to Eloquent, this isn't possible.
So in the first example, there is no instantiation happening on your code and it's not using a concrete class directly as in the second:
return User::with('profile')->find($userId);
It is receiving an implementation in the process of its instantiation:
public function __construct(Model $user)
{
$this->user = $user;
}
There are better ways to do that, because it is still expecting a concrete class while it should be expecting an implementation of an interface
public function __construct(ModelInterface $user)
{
$this->user = $user;
}
In this case you just need to pass to your object something that implements ModelInterface, which could be
Univemba\Models\EloquentModel
Or
Univemba\Models\DoctrineModel
Because both would be implementing
Univemba\Models\ModelInterface
I think if a Repository is intended to be the Eloquent implementation of a RepositoryInterface it isn't a bad idea to use the EloquentModel directly.
I wish to set some properties in MyFilter with constructor injection but it seems impossible with Zend_View::addFilter(string $filter_class_name) since it loads a new instance upon usage. MyFilter implements Zend_Filter_Interface.
Can I somehow inject an instance of a filter to an instance of Zend_View?
Closing since it (hopefully) will be pushed into 2.0, see ticket on JIRA.
You may pass object:
$filter = new Your_Filter($params); // implements Zend_Filter_Interface
$view->addFilter($filter);
You may get view instance from viewRenderer, e.g. using staticHelper.
Edit:
The other method may be:
class MyFilterSetup extends MyFilter implements Zend_Filter_Interface
{
public function __construct($params)
{
$this->_params = $params;
parent::__construct();
}
public function filter($string)
{
// .... $this->_params;
}
}
I'm not certain, but I don't think it's possible. Looking at the sourcecode setFilter() and addFilter() only accept the Filter Classname as a string. You cannot set any options, like you can in Zend_Form for instance. What you could do though is:
class MyFilter implements Zend_Filter_Interface
{
protected static $_config;
public static setConfig(array $options)
{
self::_config = $options;
}
// ... do something with the options
}
and then you set the options where needed with MyFilter::setOptions(), so when Zend_View instantiates the Filter instance, it got what it needs to properly run the filter.
You can't in the 1.x branch, ticket is filed:
http://framework.zend.com/issues/browse/ZF-9718
Can't we create a custom view object extending Zend_View that overrides the addFilter() method to accept either a class or an instance. Then override the _filter() method to deal with both types of filters - string and instance - that we have stored.
Why not assign the filter properties to the view, and then either set the properties when the view is set, or access the view directly in your filtering function? e.g.
$view->assign('MyFilterProperty', 'fubar');
and then in your filter class:
public function setView($aView)
{
$this->_property = $aView->MyFilterPropery;
}
It's kludgy, but it should get the job done.