I'm trying to access the EasyCorp\Bundle\EasyAdminBundle\Dto\PaginatorDtoin my Crud Controller :
public function __construct(
private EntityManagerInterface $manager,
private EntityRepository $entityRepository,
private PaginatorDto $paginatorDto,
) {
}
But I've got this error => Cannot autowire service "App\Controller\Activity\ActivityCrudController": argument "$paginatorDto" of method "__construct()" references class "EasyCorp\Bundle\EasyAdminBundle\Dto\PaginatorDto" but no such service exists. and I don't understand why and How to fix it :(
Any idea ?
I'm not an expert of that bundle so take my answer with a pinch of salt but looking at bundle's code I've noticed PaginatorDto not to be a service (as the name suggests).
As that DTO is not a service (and it's ok it is not), you can't autowire it nor make it a service "locally" (eg.: in your application).
So, in order to retrieve the DTO object, inject AdminContextProvider (that is a service as you can notice here) instead and use it to get the DTO
$adminContext->getCrud()->getPaginator();
Your crud controller should extend AbstractCrudController which give you access to the current admin context.
So if you want to use it in one of your crud controller method you should be able to access the paginator with:
$paginator = $this->getContext()->getCrud()->getPaginator();
If you want to do the same outside your crud controller, let's say in another service. You need to inject the AdminContextProvider to first get the AdminContext and do it the same way.
private ?AdminContext $siteRepository;
public function __construct(AdminContextProvider $adminContextProvider)
{
$this->adminContext = $adminContextProvider->getContext();
}
Related
Is there a way to access the container and thus the $app array of settings from a Slim Model file? It appears that this is ok for controllers but when I try to access $this->container always comes back null.
You can't. All that is not instantiated by the app itself won't be injected with dependencies/have access to the container.
However, there are ways to solve the problem you are facing.
Using a parameter in the model constructor
You could simply add a parameter in your constructor that takes the settings array:
function __construct(array $settings){...}
and then pass it when instantiating from a controller.
Pay attention to the fact that a container is not a service locator (see part 1.3 of the PSR), so you should not pass the container directly.
Using a factory that contains the array of settings
You could create a Factory that takes the array of settings as constructor, then store an instance in your container and add it as property of your class, this is an extension to the first answer that will save you time by not having to pass the settings as argument ever time.
// The factory
class MyModelFactory{
private array $settings;
function __construct(array $settings){
$this->settings = $settings;
}
public function makeInstance(): MyModel
{
return new MyModel($this->settings);
}
}
// In the controller
class Controller{
private MyModelFactory $myModelFactory;
...
// In your route method
$myModelInstance = $this->myModelFactory->makeInstance();
...
}
I have not included how to put the Factory inside the container and how to populate the controller class with it since this depends on the way you setup your application, but it's the easy part of the whole process :)
I've got class like this,
use Doctrine\ORM\EntityManagerInterface;
class LoginTools {
private $em;
public function __construct(EntityManagerInterface $em)
{
$this->em = $em;
}
and in Controller
$logTool = new LoginTools();
Question
Does autowire should pass EntityManagerInterface to LoginTools automatically?
Because when I call LoginTools class without passing the argument I get error
Too few arguments to function App\Utils\LoginTools::__construct(), 0 passed exactly 1 expected
With Regards,
Wiktor.
As you said, LoginTools is a service. That means, that you mustn't create it in code, like you do, Symfony creates it for you and you have just to inject this service in controller instead of EntityManagerInterface.
The thing is that Symfony has DI container, it's purpose is creating services based on your configuration from config/services.yaml and then injecting them into other services' constructors/functions/properties. There's no magic, all this code, which creates your services and inject them into other services, is generated automatically and is saved into var/cache dir by Symfony, you can check it by yourself.
My symfony2 application has the following structure:
There is a service data_provider, which gets data from various external sources and represents it as entity objects.
Some objects has relations. Currently I am loading relations in controller or helper-services if needed.
It is not very convenient, sometimes I want to get relations from my entity ojbect. To do this I need access to data_provider service.
I want to implement something like doctrine lazy-loading, what is the right way of doing this ?
Some obvious solutions - to inject data_provider in every entity instacne, or to some static property, or to make some static methods in service, or to use evenet dispatcher, but I don't think it is the right way
Made some research of ObjectManagerInterface as Cerad suggested, and found this peace of code: https://github.com/doctrine/common/blob/master/lib/Doctrine/Common/Persistence/PersistentObject.php
PersistentObject implements ObjectManagerAware interface, it has private static property where ObjectManager is stored.
So I ended with this:
class DataProvider
{
public function __construct()
{
...
AbstractEntity::setDataProvider($this);
}
}
abstract class AbstractEntity
{
private static $dataProvider;
public static function setDataProvider() {...};
protected static function getDataProvider() {...};
}
The main purpose of services in Symfony (and not only) is exactly this one - to deliver distinguished functionalitys globally over your project.
In this regard, a single service, in your case - dataProvider, should always deliver a single entity. If you have to deal with multiple entities returned from one data source, wrap the data source deliverer into a service itself, and then define one service per each entity with the deliverer injected into it.
Then you can inject the respective entity services into your controllers.
I read in the documentation how to use a controller as a service. But I am not sure what would be the purpose of it. Why not then simply use a service (a class define as a service)?
If anyone could give me some good examples of transforming a controller in a service that would be great.
The classical Symfony controller uses a Service Locater pattern to pull in it's dependencies:
class PersonController
{
public function showAction()
{
$personRepository =
$this->getDoctrine()->getEntityManager()->getRepository('Entity\Person');
$person = $personRepository->find(1);
return new JsonResponse($person);
Getting the person repository requires the action to have quite a bit of knowledge about how to locate things. Somewhat magical in fact . The controller is tied directly to doctrine and the framework infrastructure.
It also makes the action hard to test. You have to make a container then define the necessary services before running the action.
Contrast that with a controller defined as a service with it's dependencies injected:
class PersonController
{
protected $personRepository;
public function __construct($personRepository)
{
$this->personRepository = $personRepository;
}
public function showAction()
{
$person = $this->personRepository->find(1);
The action no longer needs know about how to locate the repository. It's just there. For testing, just need to make a repository and inject it. Clean and simple.
I'm looking for a good example of how to correctly implement Service Layer with Zend Framework and Doctrine2
I've seen some implementations but all of them have access to the EM from the controller when instantiating the service, and I think that might be wrong or not?
Exmaple:
http://cobbweb.me/2010/11/integrate-doctrine-2-zend-framework-application/
Also I got to this project but not really sure how to implement it:
Thanks
Use a helper to act like a factory for the services:
You need to create an Action Helper and inject the EntityManager on it when you register the instance in the Front Controller.
This Action Helper receives as parameter in the direct() method the name of the service class that the factory should create.
Inside this method you should try to instantiate the service class requested, and return it (or throw an exception if the same is not found).
Let your service classes receive as parameter in the constructor the EntityManager and inject it during the construction on the factory.
The rest should already be clear to you. In your controller you only need to use something like:
SomeController extends Zend_Controller_Action {
//...
public function someAction ()
{
$myService = $this->_helper->service( 'MyService' );
$myService->doSomething();
}
}