Reputation: 39350
I have a Symfony controller that uses a data_provider service. I can't figure out how to initialise this service.
I tried:
class DefaultController extends Controller {
public $dataProvider=$this->get('data_provider');
That causes an error, can't use constructor in a Controller so that leaves me with:
public $dataProvider=false;
public function someAction(){
$this->dataProvider=$this->get('data_provider');
...
public function anotherAction(){
$this->dataProvider=$this->get('data_provider');
...
So I have to set it every time in the controller action function. Is there an easy way to initialise the dataProvider when the controller is created?
The service is only for this bundle so it's defined in Symfony/src/mmt/myBundle/Resources/config/services.yml and that file is loaded by Symfony/src/mmt/myBundle/DependencyInjection/myExtension.php. Not sure if that makes a difference but I would prefer something that doesn't need changes to files outside the bundle.
Using symfony 2.3.4
[update]
After a seemingly endless list of instructions that cover less than half of what you need to do to get it working I got the injection part to work. Thanks to everyone giving me excellent advice.
My service is part of my bundle and don't want to change config files outside the bundle to load it. To make sure that Symfony/src/mmt/mrBundle/Resources/config/services.yml gets loaded you need a file called Symfony/src/mmt/mrBundle/DependencyInjection/mmtmrExtension.php (no, don't use just any name for the php file it's related to your application and bundle name).
What is in that file is explained here. I didn't need to do anything there because it was created when I created the bundle and have it create most of the files. (creating a bundle is in the standard documentation)
2.
Added a data_provider service in the services.yml file: (read standard documentation about setting up your db with doctrine)
data_provider:
class: mmt\mrBundle\Services\dataProvider
arguments: [ @doctrine.orm.entity_manager ]
Content of: Symfony/src/mmt/mrBundle/Services/dataProvider.php
<?php
namespace mmt\mrBundle\Services;
class dataProvider
{
protected $em;
public function __construct($em){
$this->em = $em;
}
public function getItem($id){
$item = $this->em->getRepository('mmtmrBundle:Item')
->find($id);
return $item;
}
public function saveItem($item){
$this->em->persist($item);
$this->em->flush();
}
}
?>
Now that I have the service I can use it in the controller like so:
$this->get("data_provider")->getItem(22);
But I would like my DefaultController have a $this->dataProvider when DefaultController is created. Preferably one depending on dev, prod, and test.
In comes dependency injection. Add the following to Symfony/src/mmt/mrBundle/Resources/config/services.yml
mmt.mr.DefaultController:
class: mmt\mrBundle\Controller\DefaultController
arguments: [@data_provider]
calls:
- [ "setContainer", [ @service_container ] ]
Now use the mmt.mr.DefaultController:indexAction (don't use mmtmrBundle:Default:index) in your routes:
/var/www/html/Symfony/src/mmt/mrBundle/Resources/config/routing.yml
mmtmr_homepage:
path: /{id}
requirements:
id: \d+
defaults: { _controller: mmt.mr.DefaultController:indexAction, id: false }
In Symfony/src/mmt/mrBundle/Controller/DefaultController.php should look like this:
<?php
namespace mmt\mrBundle\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\Session\Session;
class DefaultController extends Controller {
public $dataProvider;
public function __construct($data_provider){
$this->dataProvider = $data_provider;
}
public function indexAction($id) {
$item=$this->dataProvider->getItem($id);
return $this->render('mmtmrBundle:Default:index.html.twig',
array('item' => $item));
}
}
?>
I think that's it, of something is missing please let me know. Congrats; you now know how to inject dependency (If you didn't already). The bad news is that by the time you read this it's probably out of date and you have to go to the Symfony site. Documentation is good there but didn't mention any of the things that broke it for me.
Upvotes: 0
Views: 371
Reputation: 10404
You should inject it in the controller using Depency Injection.
Based on the classes in your question you can do the following:
Symfony/src/mmt/mrBundle/Resources/config/services.yml
mmt.mr.DefaultController:
class: mmt\mrBundle\Controller\DefaultController
calls:
- [ setContainer, [ @service_container ] ]
- [ setDataProvider, [ @data_provider ] ]
Symfony/src/mmt/mrBundle/Controller/DefaultController.php
public function setDataProvider($provider){
if($this->dataProvider===false){
$this->dataProvider=$provider;
}
}
Make sure you use the service name and then the action in your router, for example:
Symfony/src/mmt/mrBundle/Resources/config/routing.yml
mmtmr_homepage:
path: /{id}
requirements:
id: \d+
defaults: { _controller: mmt.mr.DefaultController:indexAction, id: false }
mmt.mr.DefaultController
is the name used in your services.yml and :indexAction
is the function called indexAction in your DefaultController.php
Upvotes: 2
Reputation: 1847
After use the depedency injection, $data_provider must be correctly given to your controller so why do you not use it in:
public function dataInit($data_provider){
$logger = $this->get('logger');
$logger->notice('from dataInit so this works');
}
maybe it's must be:
public function dataInit($data_provider){
$logger = $data_provider->getLogger();
$logger->notice('from dataInit so this works');
}
If no, please paste you dataProvider class
Upvotes: 0
Reputation: 79
I recommend to use a method that returns the service.
Something like:
public function getDataProvider()
{
return $this->get('data_provider');
}
And create a 'AdvancedController' that extends the Symfony2 Controller, put this method in it, and let all your controllers extend it.
In the AdvancedController you can put all your global methods that you use in controllers, it's really comfortable.
Upvotes: 0