i have a factory for creating an object.
Abbruchprotokoll::class => factory(function(ContainerInterface $c){
return new Abbruchprotokoll($c->get(Request::class)->getRouterParam('stts-id'), $c->get(MySQL::class));
})
the factory is creating that object with a string and a dependency injection (MySQL Class).
In my Abbruchprotokoll::class i have an inject annotation:
/**
* #Inject
* #var \Smarty
*/
protected $smarty;
the problem is, that this inject annotation is not resolved. i think this is because i am on FactoryResolver and there is no injectMethodsAndProperties() like in ObjectCreator.
can i use injection annotations with factories in some other way?
You cannot use annotations with factories, you need to use autowire(Abbruchprotokoll::class) instead. autowire() asks for the class to be autowired, which resolves the annotations.
Related
I am using PHPStan with its Doctrine extension.
I have a custom entity repository called App\Repository\Doctrine\UserRepository with the #extends doc block:
/**
* #extends \Doctrine\ORM\EntityRepository<\App\Entity\User>
*/
class UserRepository extends EntityRepository implements IUserRepository
{
public function customRepositoryMethod()
{
// ...
}
}
In a controller, this code:
public function getUserMatches(EntityManager $em)
{
$userRepo = $em->getRepository(\App\Entity\User::class);
$userRepo->customRepositoryMethod();
}
...results in this PHPStan error:
Call to an undefined method Doctrine\ORM\EntityRepository<meQ\Entity\User>::customRepositoryMethod().
Thanks to phpstan-doctrine, static analysis knows that $em->getRepository(User::class) returns a EntityRepository<User>.
However, it does not know to consider the custom repository class UserRepository as the implementation of that generic type.
How do I DocBlock the UserRepository class, or otherwise configure PHPStan, so that it interprets UserRepository as the implementation of EntityRepository<User>?
What else I've tried
I've also tried this DocBlock on UserRepository to no avail:
/**
* #implements \Doctrine\ORM\EntityRepository<\App\Entity\User>
*/
PhpStan has no way of knowing EntityManager::getRepository() is going to return your custom method.
Either add a #var annotation right there:
/** #var UserRepository $userRepo */
$userRepo = $em->getRepository(\App\Entity\User::class);
Or better yet, just inject the UserRepository, not the whole EntityManager:
public function getUserMatches(UserRepository $userRepository)
{
$userRepository->customRepositoryMethod();
}
The above would work with PhpStan or any static analysis tool out of the box. (And, injecting the specific repository instead of the Entity Manager is a better practice in any case).
But if not, you can always try installing the Doctrine Extensions for PHPStan, which may help the tool understand the codebase in relationship to Doctrine ORM.
If you are already using the Doctrine Extensions, note that from what I gather in the docs it's only able to extract typing if your mapping configuration is provided via annotations. If you configurate ORM mappings via XML (or YAML, in older versions of Doctrine), then I think the Extensions won't be able to extract the typing data, and the above solutions will be your only way to go.
I have a service class that has dependencies on multiple entity repositories, for example 4.
I could inject each repository and end up with many dependencies, or I could inject the entity manager as a single dependency; relying on EntityManager->getRepo('xyz').
Separate dependencies has the benefit of code hinting.
Single dependency means less verbose at construct.
Possibly easier mocking and less setup?
What is considered a better practice?
In this case EntityManager is something like Service Locator. When service depends on EntityManager, it also formally depends on all its API and all related objects (repositories, metatada, etc). Better inject only what you really need:
explicit injection of specific repositories makes your service easier to read and test.
Also, prefer interface over class if possible (ObjectRepository instead of EntityRepository, ObjectManager instead of EntityManager).
I assume, that you must use only one Doctrine Entity Manager in your service dependencies.
But if you want to have code hinting in your IDE, you can do it with phpdoc annotation like this
class SomeServiceWithDoctrineDependency
{
/** #var YourFirstObjectRepository */
protected $firstRepo;
/** #var YourSecondObjectRepository */
protected $secondRepo;
/** #var YourThirdObjectRepository */
protected $thirdRepo;
public function __construct(EntityManagerInterface $entityManager)
{
$this->firstRepo = $entityManager->getRepository('First:Repo');
$this->secondRepo = $entityManager->getRepository('Second:Repo');
$this->thirdRepo = $entityManager->getRepository('Third:Repo');
}
public function getCodeHint()
{
// You get hint here for find method
// $this->thirdRepo()->find()...
}
}
The title explains the question pretty well. I am in the lifecycle callback of the Doctrine Entity class and want to do some extra DB entries. For this I need to get an instance of the Kernel. How can I do this?
Needing the container/kernel in an entity is most of the time, wrong. An entity shouldn't be aware of any services. Why is that?
Basically, an entity is an object which represents a thing. An entity is mostly used in a relationnal database, but you can at any time use this entity for other matters (serialize it, instanciate it from an HTTP layer...).
You want your entity to be unit-testable, this means you need to be able to instanciate your entity easily, without anything around, mostly, without any piece of business logic.
You should move your logic into another layer, the one that will instanciate your entity.
For your use case, I think, the most easy way is to use a doctrine event.
services.yml
services:
acme_foo.bar_listener:
class: Acme\FooBundle\Bar\BarListener
arguments:
- #kernel
tags:
- { name: doctrine.event_listener, event: postLoad }
Acme\FooBundle\Bar\BarListener
use Symfony\Component\HttpKernel\KernelInterface;
use Doctrine\ORM\Event\LifecycleEventArgs;
use Acme\FooBundle\Entity\Bar;
class BarListener
{
protected $kernel;
/**
* Constructor
*
* #param KernelInterface $kernel A kernel instance
*/
public function __construct(KernelInterface $kernel)
{
$this->kernel = $kernel;
}
/**
* On Post Load
* This method will be trigerred once an entity gets loaded
*
* #param LifecycleEventArgs $args Doctrine event
*/
public function postLoad(LifecycleEventArgs $args)
{
$entity = $args->getEntity();
if (!($entity instanceof Bar)) {
return;
}
$entity->setEnvironment($this->kernel->getEnvironment());
}
}
And there you go, your entity remains flat without dependencies, and you can easily unit test your event listener
if you have to use some service, you shouldn't use whole container or kernel instance especially.
use the services itself - always try to inject single service, not whole container
your case looks like you should use doctrine events
I'm browsing the Symfony 2 docs related to Dependency Injection, and can't find a reference to autowiring. I found a bundle that offers some of this functionality, but it's still in beta and seems to be tied to annotations (correct me if I'm wrong).
What I'm looking for is an object (such as the service container), that could inject dependencies in my services, via setter injection.
For example, I would define a Service:
class Service {
/**
* #var \PDO
*/
protected $pdo;
/**
* #param \PDO $pdo
* #Inject
*/
public function setPDO(\PDO $pdo) {
$this->pdo = $pdo;
}
}
And then, I could use this hypothetical service container to inject dependencies in the Service, even if this one has been created outside the container:
$service = new Service();
// ...
$container->inject($service);
Is there a DI container that could autowire dependencies this way?
Since Symfony 2.8, autowiring is natively supported: https://github.com/symfony/symfony/pull/15613
There is also autowiring bundle aviable at https://github.com/kutny/autowiring-bundle.
See the #InjectParams annotation from JMSDiExtraBundle.
Is there an easy way to get Doctrine's entity manager from within an entity's class method?
<?php
/** #Entity */
class MyEntity {
/** #Id #GeneratedValue #Column(type="integer") */
protected $id;
[...]
public function someFunction() {
// Is there any way to get Doctrine's EntityManager in here?
}
}
You're really not supposed to. The idea behind a datamapper ORM like Doctrine is that your entities are just plain-old objects that know nothing about the persistence layer. If you find yourself wanting an EntityManager inside your entity, that's a signal that you ought to be creating a service class of some sort.
That said, Doctrine is quite flexible. For example, if you were so inclined, you could use Doctrine as the foundation for an ActiveRecord-style ORM.
However, outside of very specific use-cases, I wouldn't recommend it.