my constructor of my Controller looks like:
function __construct(){#
var_dump($this->get('translator'));
exit();
}
this will give a FatalErrorException: Error: Call to a member function get() on a non-object. But why? If I use it inside a action it will work.
Base controller's method get() is a shortcut for $this->container->get($id);. $this->container is set in one of the controller's parent - abstract class ContainerAware. So,
until object construction is finished, there is no Controller object that would have get() method. In general, container is not available in Controller's constructor.
This is because Controller method get needs the container property. Controller extends ContainerAware which has a method setContainer. This method let the property container be aware of the Container.
Upon instanciation, no method are called, here is the workflow
$controller = new MyController($parameters);
$controller->setContainer($container);
Before calling __construct, controller has no property $container
public function __construct($parameters)
{
var_dump($this->container); // NULL
}
So, by calling $this->get() you are doing
$this->get('translator');
// =
$this->container->get('translator');
// =
null->get('translator');
Hence the error.
If you need the validator, you'll have to ask it in your constructor (and respect the Law of Demeter).
To do so, you'll need to declare your controller as a service
services.yml
services:
my_controller:
class: Acme\FooBundle\Controller\MyController
arguments:
- "#translator"
calls:
- [ "setContainer", [ "#service_container" ] ]
routing.yml
bar_route:
path: /bar
defaults: { _controller: my_controller:barAction }
MyController
class MyController extends Controller
{
protected $translator;
public function __construct(TranslatorInterface $translator)
{
$this->translator = $translator;
}
}
Related
I am trying to pass my service, defined in other bundle to controller which is defined as a service but getting null in contractor.
I know we can do it by passing the service_container but need to know if I can pass only specific service to the controller.
If the name is unique, no problem here.
namespace Yourapp\OneBundle\Controller;
class OneController extends Controller
{
public function oneAction()
{
$otherControllerManager = $this->get('youappOtherbundle.the_manager');
}
}
EDIT : Okay, it seemed to me that you could extend controller even it was a controller as service.
Why don't just "transmit" your required services as usual ?
In your services.yml
OneController.controller.service:
class: Yourapp\OneBundle\Controller\OneController
arguments: ["#templating", "#router"]
In your Controller:
public function __construct(EngineInterface $templating, UrlGeneratorInterface $router)
{
$this->templating = $templating;
$this->router = $router;
}
How can make an Object accessible in a controllers which was set in kernel.controller Event?
I have a onKernelController method which is run before controller and I need some data in a controller which was set in onKernelController.
You can use dependency injection to solve this:
1) Turn your object/class into a service and inject it into the listener.
services:
your_object:
class: Your\Namespace\YourObjectClass
your_listener:
class: Your\Namespace\YourListener
arguments: [ #your_object ]
tags:
- { name: kernel.controller, event: kernel.request, method: onKernelController }
2) Set some property (can be an object aswell) on the injected object
listener class
use Symfony\Component\HttpKernel\Event\FilterControllerEvent;
class YourListener
{
protected $object;
public function __construct($object)
{
$this->object = $object;
}
public function onKernelController(FilterControllerEvent $event)
{
// ...
$object->setProperty('some_property_value');
}
}
3.) Get the property inside a container-aware controller (or turn your controller into a service aswell and inject #your_object )
controller
use Symfony\Component\DependencyInjection\ContainerAware;
// or: use Symfony\Bundle\FrameworkBundle\Controller\Controller;
class SomeController extends ContainerAware // or: extends Controller
{
public function someAction()
{
$property = $this->container->get('your_object')->getProperty;
// $property => 'some_property_value'
}
I'm creating a Twig extension and activating it with a service. Everything works great except I'm trying to simply use another class from my Twig extension.
The idea is to instantiate the new class then use it as needed. Instantiating is a problem as it errors with:
Error: Cannot redeclare class NewClass in .../Bundle/NewClass.php line 13
Surely it instantiates it once. Why is this happening?
namespace Bundle\Twig;
use Bundle\NewClass;
class NewExtension extends \Twig_Extension
{
private $request;
private $new_class;
public function __construct($container) {
//get the Request object
$this->request = $container->get('request');
//instantiate new class
$this->new_class = new NewClass(); // this part triggers the error
}
///etc.
You should make your NewClass into a service and then inject that and the #request service into your twig extension rather than the container. Injecting the container directly is a bad idea apparently.
For example in your services..
services:
# create new class as a instantiated service
acme_demo.new_class:
class: Acme\DemoBundle\NewClass
arguments: [ '#request' ]
acme_demo.twig.acme_extension:
class: Acme\DemoBundle\Twig\AcmeExtension
arguments: [ '#request', '#acme_demo.new_class' ]
# inject the Request service and your class from above
tags:
- { name: twig.extension }
And then in your Twig extension
namespace Bundle\Twig;
use Bundle\NewClass;
class NewExtension extends \Twig_Extension
{
private $new_class;
public function __construct(NewClass $newClass) {
$this->new_class = $newClass;
}
///etc.
In your NewClass:
namespace Bundle;
class NewClass
{
private $param1;
private $param2;
public function __construct(Request $request)
{
$this->param1 = $request->get('param1');
$this->param2 = $request->get('param2');
// You could also add some check in here to make sure they are valid.
}
is there any way to preprocess controller data somehow. I'm going to take param from session, validate it and assign it as controller property and use it as $this->myVar inside actions of some controller or all of them if possible. Using controller's constructor gives me nothing, I couldn't access request and session data. Thanks!
UPD:
Thanks, jkucharovic, very good solution.
Also there is a bit dirtier solution, without injecting: setContainer() method, which has been called straight after $controller = new Controller();
use Symfony\Component\DependencyInjection\ContainerAwareInterface,
Symfony\Component\DependencyInjection\ContainerInterface;
class AppServiceController extends Controller {
private $my_property;
/**
* Used as constructor
*/
public function setContainer(ContainerInterface $container = null)
{
parent::setContainer($container);
$this->my_property = 'foo';
// your controller code
}
}
I'm not sure what you wan't to do is very usefull. A Controller instance will be created each time the controller is called. The session and request will be different each time you call the controller.
I think you should create a BaseController class extending Controller class with a shortcut method to access your MyVar value in session.
class BaseController extends Controller
{
public function getMyVar()
{
return $this->get('session')->get('MyVarSessionKey');
}
}
All your other Controller will extend from this BaseController.
To get the request, just use the shortcut method provided by Controller class, Controller::getRequest().
If you want to use services in __construct method, you have to inject that services first. Then you can use them before any other methods. For example:
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Session;
public function __construct(Request $request, Session $session)
{
…
}
Why it gives the following error when calling controller inside a controller?
Fatal error: Call to a member function get() on a non-object in
/home/web/project/symfony2/vendor/symfony/src/Symfony/Bundle/FrameworkBundle/Controller/Controller.php
on line 149
In the controller I called a class that extends Controller:
class DemoController extends Controller
{
public function indexAction()
{
$object = new \Acme\DemoBundle\Service\Object();
$object->method();
}
// ...
}
The class is something like this:
# Acme/DemoBundle/Service/Object.php
class Object extends Controller
{
public function method()
{
$em = $this->getDoctrine()->getEntityManager(); // the problem
// ...
}
}
When I use $this to call service, doctrine, or something else like within a controller, the error occurred. Otherwise, it works.
How can I use, for example, doctrine inside this class?
Try
$object->setContainer($this->container);
before you call method()
Edit:
Basically it's a bad idea to have a service extend Controller but if you really need to do this, try to add this
your.service:
class: Your\Class
arguments: [...]
calls:
- [ setContainer, [#service_container] ]
in your service configuration file (probably service.yml)