Acces custom Doctrine Manager in a Symfony2 Service - symfony

I don´t know how to do this,
I create a service in Symfony2 and i need to this service use request and doctrine entitymanager service
In services.yml i add these lines:
logdb:
class: %logdb.class%
arguments: ['#doctrine.orm.entity_manager','#request_injector']
My service class:
class LogDB {
protected $em;
protected $request;
public function __construct(EntityManager $em, Request $request){
$this->em= $em;
$this->request= $request;
}
public function saveLog(){
}
}
Well, in saveLog() i need to acces to entitymanager but from a different manager of default, i mean entity manager i am injecting with '#doctrine.orm.entity_manager' is default.
In a controller i can do this:
$em = $this->getDoctrine()->getManager($this->getRequest()->get('shop'));
I use differents databases for every shop, that i choose by url param.
Ask is, how can i acces to a custom entitymanager from a service?
injecting container is a bad solution...
maybe i need to pass entitymanager as argument in every service method from controller i don´t know

Then you are injecting the wrong Object. Why not inject doctrine to the service?
services:
logdb:
class: %logdb.class%
arguments: ['#doctrine','#request_injector']
# ^^^^^^^^^^^^^- not the entity_manager
Then you can call this in your service:
$em = $this->doctrine->getManager($this->request);

Related

How to inject Doctrine Entity Manager into Symfony 4 Service

I have a controller
use Doctrine\ORM\EntityManagerInterface:
class ExampleController{
public function someFunction(ExampleService $injectedService){
$injectedService->serviceFunction();
}
}
With a Service
use Doctrine\ORM\EntityManagerInterface;
class ExampleService{
public function __construct(EntityManagerInterface $em){
...
}
}
However, calls to someFunction() fail due to 0 parameters being passed (the EntityManagerInterface is not being injected). I am attempting to use the EntityManager from the Service. Autowiring is on. I've tried the solutions for Symfony3 but they don't seem to work unless I'm missing something.
Edit: Here is my services.yaml:
services:
_defaults:
autowire: true
autoconfigure: true
public: false
App\:
resource: '../src/*'
exclude: '../src/{Entity,Migrations,Tests,Kernel.php}'
App\Controller\:
resource: '../src/Controller'
tags: ['controller.service_arguments']
Use only in Symfony 4.
use Doctrine\ORM\EntityManagerInterface;
use App\Entity\Name; //if you use entity for example Name
class ExampleService{
private $em;
public function __construct(EntityManagerInterface $em)
{
$this->em = $em;
}
function newName($code) // for example with a entity
{
$name = new Name();
$name->setCode($code); // use setter for entity
$this->em->persist($name);
$this->em->flush();
}
}
I know it's an old post, but just in case somebody struggles with this, there's a typo in the use statment:
use Doctrine\ORM\EntityManagerInterface: //<- see that's a colon, not a semicolon
Agree with Yarimadam. Service container, dependency injection and autowiring is not a story about injecting into methods. Dependencies injected into objects we are calling "services".
When application is up, service container is built injecting one services into another ones via class constructor or "set" method invocation.
Your ExampleController::someFunction is intended to be called only by you, so only way how this method will receive $injectedService as an argument, is that you will pass it evidently. This is the wrong way.
A classic symfony service with autowiring uses constructor injection method to inject dependencies. In your case, you don't have a constructor.
You may consider to add a constructor method and set dependency to a private class property. And use accordingly.
Or you can utilize setter injection.
Service Configuration:
services:
app.example_controller:
class: Your\Namespace\ExampleController
calls:
- [setExampleService, ['#exampleService']]
Controller Class:
class ExampleController
{
private $exampleService;
public function someFunction() {
$this->exampleService->serviceFunction();
}
public function setExampleService(ExampleService $exampleService) {
$this->exampleService = $exampleService;
}
}

Symfony autowiring interface to a real service

I need to configure an autowiring for a Symfony 2.8 application.
A service has a dependency on a Symfony\Component\Templating\EngineInterface:
use Symfony\Component\Templating\EngineInterface;
class MyService
{
/** #var EngineInterface */
private $templating;
public function __construct(EngineInterface $templating)
{
$this->templating = $templating;
}
}
But I obviously get an error since this interface is implemented in three different classes.
Unable to autowire argument of type
"Symfony\Component\Templating\EngineInterface" for the service
"myservice". Multiple
services exist for th is interface (templating.engine.delegating,
templating.engine.php, templating.engine.twig).
I would like to inject the templating.engine.delegating every time when the EngineInterface is required so I add a definition to my service.yml
services:
template:
autowiring_type: 'Symfony\Component\Templating\EngineInterface'
alias: 'templating.engine.delegating'
But I still get the same error - application can not find which service to use for the EngineInterface
So the question is it possible to wire an interface to an already defined kernel service?
I've managed to handle similar problem when have to wire an abstract class to a service.
A service:
use Doctrine\Common\Cache\CacheProvider;
class MyOtherService
{
/** #var CacheProvider */
private $cache;
public function __construct(CacheProvider $cache)
{
$this->cache = $cache;
}
}
services:
memcache_cache:
class: 'Doctrine\Common\Cache\MemcacheCache'
autowiring_types: 'Doctrine\Common\Cache\CacheProvider'
calls:
- [ setMemcache, ["#memcache"] ]
- [ setNamespace, ["%memcache.prefix%"] ]
So, I've created a service (memcache_cache) and defined a autowiring_types for it. Every time the abstract CacheProvider is injected the memcache_cache should be used.
But it was easy as this is not a kernel service. I've defined it myself in a services.yml, whereas I don't have an access to extends the templating.engine.delegating service in a way to add the autowiring_types: 'Symfony\Component\Templating\EngineInterface'

Adding doctrine entity manager to service in symfony2

Im trying to add entity manager to my service layer in Symfony. I've researched online but none of the answers seem to work for me.
I have a class with a namespace called AppBundle\Controller. My class name is MasterController. Then what exactly do I need to add into my services.yml?
Other than that I think I only need to pass EntityManager $em into the constructor as a param and then assign $em to $this->em (private)?
E.g.
class MasterController extends Controller
{
private $em;
public function __construct(EntityManager $em)
{
$this->em = $em;
}
}
It's possible to define controllers as services while at the same time, extending the framework controller class. Why do this? By doing this you can take advantage of the base functionality such as the form factory, template rendering, get user stuff etc.
At the same time, you can inject any controller specific services you need. This avoids using the container as a service locator pattern. In other words, we can push services into the controller as opposed to having the controllers pull the services. The controllers don't need to care where the services come from and become more self contained.
Example:
class PersonController extends Controller
{
private $personRepository;
public function __construct($personRepository)
{
$this->personRepository = $personRepository;
}
public function editAction(Request $request, $id)
{
$person = $this->personRepository->find($id);
$form = $this->createForm(new PersonFormType(), $person);
$form->handleRequest($request);
if ($form->isValid()) {
// Note: I add flush/persist methods to my repositories
// You could inject the entity manager and flush from it
$personRepository->flush();
return $this->redirect($this->generateUrl('wherever'));
}
return $this->render('person/edit.html.twig', array(
'form' => $form->createView(),));
}
}
Make the controller a service with:
services:
person_repository:
class: AppBundle\Entity\PersonRepository
factory_service: 'doctrine.orm.default_entity_manager'
factory_method: 'getRepository'
arguments:
- 'AppBundle\Entity\Person'
person_controller:
class: AppBundle\Controller\PersonController
calls:
- [setContainer,['#service_container']]
arguments:
-'person_repository
So basically, you end up with a standard Symfony controller with all the standard functionality but you can inject controller specific services such as repositories which in turn makes your controllers easier to read and debug. You should never need to use $this->get('service') from within your controller action methods.
Contract this with the more standard method of retrieving an entity:
$personRepository = $this->getDoctrine()->getManager()->getRepository('AppBundle\Entity\Person');
As you can see, the standard method not only ties the controller directly to doctrine but also requires the controller to know the entity's class name. You can decide which method is easier to write, understand and maintain.
First of all if your MasterController extends Symfony\Bundle\FrameworkBundle\Controller class then you have already EntityManager available by using:
$this->em = $this->getDoctrine();
But if you want to inject it by yourself to your constructor (and have Controller as a service) all you need to do is have entry in your services.yml like this:
services:
your_controller_service:
class: AppBundle\Controller\MasterController
arguments: [#doctrine.orm.entity_manager]
And that's it.
EDIT:
Remember that you need to have use Doctrine\ORM\EntityManager somewhere before your class definition to avoid Catchable fatal error

Accessing generateURL() from Entity class

I would like to access generateUrl in my entity class. You can access generateUrl in controller class like this:
$url = $this->generateUrl('your_route_name', array(/* parameters */));
Accoring do this article, I should try to 'create a service, and inject the router component in it'. Then I am reading Symfony Docs: Service Container and try configuration, but I still can not make it.
in app/config/config.yml
services:
router:
class: ???
arguments: ???
How can I make router as service?
update
Why I want to use generateUrl in Entity class?
I am using Eko/FeedBundle. It requires to implements getFeedItemLink() in Entity. I need to give URL as return value of this function.
The short answer is: you don't use the router inside entities and you don't create entities as services. You should create a separate service which is responsible for creating urls (if you wrote more about what you are trying achieve it would be simpler to give you more appropriate example).
For example:
use Symfony\Bundle\FrameworkBundle\Routing\Router;
class YourCustomUrlGenerator
{
private $router;
public function __construct(Router $router)
{
$this->router = $router;
}
public function generateUrl(YourEntity $entity)
{
// generate the url
}
}
Then define your service for DIC:
services:
custorm_url_generator:
class: Namespace\YourCustomUrlGenerator
arguments: [#router]

How should I configure an object dynamically when using Symfony's DI?

I'm using a YAML configuration to wire my dependencies, and I need to provide some runtime information to get a useful object back. I was going to run a setter method from my code once the object has been injected, but I Was wondering if there was a better way of doing it (or if there's something I'm missing).
This is the gist of my configuration:
services:
example_object : "myObject"
arguments : ["%object_parameter1%"]
parameters:
object_parameter1 : Some Static Data
object_parameter2 : #Rutime info required
For retrieving the current logged in user in any service, inject the security.context. In this case I use setter injection to simply user mock injection.
namespace Acme\ExampleBundle\Foo;
use Symfony\Component\Security\Core\SecurityContextInterface;
class MyService
{
private $param;
private $user;
public function __construct($param)
{
$this->param = $param;
}
/**
* Retrieve the current logged in user from the security context.
*/
public function setUserFromContext(SecurityContextInterface $context)
{
$this->user = $context->getToken()->getUser();
}
/**
* Set any user object.
*
* Usefull for testing, to inject a simple user mock.
*/
public function setUser($user)
{
$this->user = $user;
}
public function doSomething()
{
// do something with the user object
}
}
Define the service:
services:
my_service:
class: Acme\ExampleBundle\Foo\MyService
arguments: ["%object_parameter1%"]
calls:
- [ setUserFromContext, [#security.context] ]
You should not try to add dynamic values directly into the DI configuration. Symfony services configuration is reflected by compiled DI container and recompilation is very heavy operation.
If you do not want to couple your service with Symfony's security system directly, you can add your custom "user provider" service as a dependency. Then you will need to rewrite this service if the source of information will change. It may be also easily mocked.
You can also use a factory to inject a user object instead of user provider service.

Resources