Symfony 3 inject service into controller - symfony

I'm using symfony 3.1.7 and I have problems with inject services into a controller, my english is bad I believe that it is better if I show all the code.
The error:
Type error: Argument 1 passed to
...Bundle\Controller\AdminController::__construct() must
implement interface
Symfony\Component\DependencyInjection\ContainerInterface, none given,
called in /......./project/var/cache/dev/classes.php on line 2512
This is my code:
GenericRestController
namespace MyCoreBundle\Controller;
use Symfony\Component\DependencyInjection\ContainerInterface as Container;
use MyCoreBundle\Handler\GenericRestHandlerInterface as Generic;
/** other uses like FOSRestController **/
/**
* Class GenericRestController
*/
abstract class GenericRestController extends FOSRestController
{
protected $handler;
protected $container;
public function __construct(Container $container,Generic $handler)
{
$this->container = $container;
$this->handler = $handler;
}
/** other methods like get, post, put, etc **/
}
AdminController
namespace ...Bundle\Controller;
use MyCoreBundle\Controller\GenericRestController;
class AdminController extends GenericRestController
{
}
RESOLVED
The solution was change the routes as Cerad says.
Oficial documentation
services.yml
services:
app.hello_controller:
class: AppBundle\Controller\HelloController
routing.yml
hello:
path: /hello
defaults: { _controller: app.hello_controller:indexAction }
Thanks mtaqi and Cerad

The solution was change the routes as Cerad says.
Oficial documentation
services.yml
services:
app.hello_controller:
class: AppBundle\Controller\HelloController
routing.yml
hello:
path: /hello
defaults: { _controller: app.hello_controller:indexAction }
Sorry for the delay and thanks!

Related

Symfony2 - Controller as a Service - Routing via annotations

I am experimenting with creating controllers as services as shown at http://symfony.com/doc/current/cookbook/controller/service.html. I’ve followed this example and everything works fine when I have the route set in app/config/routing.yml. However when I try and set the route via annotations I get an error
My routing.yml file looks like this:
#hello:
# path: /hello/{name}
# defaults: { _controller: app.hello_controller:indexAction }
hello:
resource: "#EventBundle/Controller/HelloController.php"
type: annotation
My controller looks like this:
<?php
namespace Me\EventBundle\Controller;
//use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Bundle\FrameworkBundle\Templating\EngineInterface;
use Symfony\Component\HttpFoundation\Response;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
//class HelloController extends Controller
class HelloController
{
private $templating;
public function __construct(EngineInterface $templating)
{
$this->templating = $templating;
}
/**
* #Route("/hello/{name}", name="hello")
*
*/
public function indexAction($name)
{
return $this->templating->renderResponse(
'EventBundle:Default:test.html.twig',
array('name' => $name)
);
}
}
As I say if I just use routing.yml and not the annotations the page renders correctly. However using annotations I get the error:
Catchable Fatal Error: Argument 1 passed to Me\EventBundle\Controller\HelloController::__construct() must be an instance of Symfony\Bundle\FrameworkBundle\Templating\EngineInterface, none given, called in /Library/WebServer/Documents/symfony-project/app/cache/dev/classes.php on line 2176 and defined
EDIT - as requested in comments:
service.yml looks like:
services:
app.hello_controller:
class: Me\EventBundle\Controller\HelloController
arguments: ['#templating']
The answer with thanks especially to #Artamiel and #Cerad was to add #Route(service="app.hello_controller") just above my class name, so it now looks like:
/**
* #Route(service="app.hello_controller")
*/
class HelloController
{
private $templating;
public function __construct(EngineInterface $templating)
{
$this->templating = $templating;
}
..........etc

Inject Doctrine Repository into controller

I had the following controller:
<?php
namespace AppBundle\Controller;
use AppBundle\Controller\BaseController;
use Symfony\Component\HttpFoundation\Request;
class UserController extends BaseController
{
public function allAction(Request $request)
{
$users = $this->getDoctrine()
->getRepository('AppBundle:User')
->findAll();
return $this->respond(['users' => $users], 200);
}
}
And I would like to inject the repository into the controller (for testing purposes)
Controller:
<?php
namespace AppBundle\Controller;
use AppBundle\Controller\BaseController;
use Doctrine\ORM\EntityRepository;
use Symfony\Component\HttpFoundation\Request;
class UserController extends BaseController
{
private $userrepository;
public function __construct(EntityRepository $userrepository)
{
$this->userrepository = $userrepository;
}
public function allAction(Request $request)
{
$users = $this->userrepository->findAll();
return $this->respond(['users' => $users], 200);
}
}
services.yml
services:
userrepository:
class: Doctrine\ORM\EntityRepository
factory_service: doctrine.orm.entity_manager
factory_method: getRepository
arguments:
- AppBundle\Entity\User
usercontroller:
class: AppBundle\Controller\UserController
arguments:
- "#userrepository"
routing.yml
api_users_all:
path: /api/users.{_format}
defaults: { _controller: usercontroller:allAction, _format: json }
requirements:
_method: GET
I keep facing the following error:
PHP Fatal error: Call to a member function get() on a non-object in /Applications/MAMP/htdocs/api/vendor/symfony/symfony/src/Symfony/Bundle/FrameworkBundle/Controller/Controller.php on line 350
line 350
return $this->container->get($id);
So my guess is that the controller is no longer 'ContainerAware' or something like that.
But I can't seem to figure this out.
I am working with symfony 2.7
After you configure the router to call controller via service, controller is not created directly but requested from the Dependency Injection container. And yes, there is no longer container because you inject only one parameter to it: user repository.
If you want whole container (which is not recommended) and you extending Symfony Controller in your BaseController set it in your service:
services:
usercontroller:
class: AppBundle\Controller\UserController
calls:
- [setContainer, ["#service_container"]]
arguments:
- "#userrepository"
If you not extending Symfony Controller, inject container as argument:
services:
usercontroller:
class: AppBundle\Controller\UserController
arguments:
- "#userrepository"
- "#service_container"
Controller:
class UserController extends BaseController
{
private $userrepository;
private $container;
public function __construct(EntityRepository $userrepository, $container)
{
$this->userrepository = $userrepository;
$this->container = $container;
}
It's not recommended, inject only what you want eg. if you use in your controller only repository and mailer inject only them not the whole container.

How to definitely disable registration in FOSUserBundle

In my project, I allow only one user to manage the content of the website. This user will be added using the command line at first.
Now, I want to get the registration action inaccessible and I don't know how?
Till now, I just put the ROLE_ADMIN in the access control for the route register to avoid that visitors can go throw it.
Any tips?
Take a look at the routing configuration imported from
vendor/friendsofsymfony/user-bundle/Resources/config/routing/all.xml
If you want just the basic security actions, just import
#FOSUserBundle/Resources/config/routing/security.xml
instead of
#FOSUserBundle/Resources/config/routing/all.xml
This way you can simply select which components (security, profile, resetting, change_password) you want to use or event import only specific routes from those components.
There are many ways to solve this issue. You can simply remove fos_user_registration_register route from routing.yml. Or use more complicated solution: set up event listener to FOS\UserBundle\FOSUserEvents::REGISTRATION_INITIALIZE event and redirect user to login page.
services.xml
<service id="app.registration.listener" class="AppBundle\EventListener\RegistrationListener">
<tag name="kernel.event_subscriber" />
<argument type="service" id="router" />
</service>
RegistrationListener.php
<?php
namespace AppBundle\EventListener;
use FOS\UserBundle\Event\GetResponseUserEvent;
use FOS\UserBundle\FOSUserEvents;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
class RegistrationListener implements EventSubscriberInterface
{
/**
* #var UrlGeneratorInterface
*/
private $router;
/**
* #param UrlGeneratorInterface $router
*/
public function __construct(UrlGeneratorInterface $router) {
$this->router = $router;
}
public static function getSubscribedEvents()
{
return [
FOSUserEvents::REGISTRATION_INITIALIZE => 'onRegistrationInitialize',
];
}
public function onRegistrationInitialize(GetResponseUserEvent $event)
{
$url = $this->router->generate('fos_user_security_login');
$response = new RedirectResponse($url);
$event->setResponse($response);
}
}
You can just change app/config/security.yml:
- { path: ^/register, role: ROLE_ADMIN }
Change from the default (IS_AUTHENTICATED_ANONYMOUSLY) to ROLE_ADMIN and it will stop allowing anonymous users from getting to the /register form.
Another simple solution (the one I used) is to overwrite the registerAction() default FOSUserBundle controller method:
namespace Acme\UserBundle\Controller;
use FOS\UserBundle\Controller\RegistrationController as FOSRegistrationController;
use Symfony\Component\HttpFoundation\Request;
class RegistrationController extends FOSRegistrationController
{
public function registerAction(Request $request)
{
return $this->redirectToRoute('getStarted', array(), 301);
}
}
Doing this will leave active other routes, as the confirmation page.
I simply overwrote the register action and redirect the user to my first registration page (getStarted).
If you use the JMSSecurityExtraBundle you can use the denyAll directive like so:
- { path: ^/register, access: denyAll }
This is how I solve this issue...
First you have to define your listener in the services.yml file:
services:
registrationListner:
class: App\YourBundle\Listener\RegistrationListener
arguments: [#service_container]
tags:
- { name: kernel.event_listener, event: kernel.request, method: onKernelRequest}
Then create your class RegistrationListener:
<?php
namespace App\YourBundle\Listener;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpKernel\Event\GetResponseEvent;
class RegistrationListener
{
private $router;
public function __construct(ContainerInterface $container){
$this->router = $container->get('router');
}
public function onKernelRequest(GetResponseEvent $event)
{
$route = $event->getRequest()->attributes->get('_route');
if ($route == 'fos_user_registration_register') {
//here we're gonna to redirect to you_route for example, I guess in the most cases it will be the index...
$event->setResponse(new RedirectResponse($this->router->generate('your_route')));
}
}
}
Hope it helps.
You can try to change your routing.yml
fos_user_registration_register:
path: /register{trailingSlash}
defaults: { _controller: AcmeBundle:Default:register, trailingSlash : "/" }
requirements: { trailingSlash : "[/]{0,1}" }
And in your DefaultController
public function registerAction(Request $request)
{
return $this->redirectToRoute('404OrWhatYouWant');
}

Override Bundle Controller Symfony2

I'm using EasyAdminBundle in my Symfony2 application.
I want to override some actions of the controller, and I follow the Bundle instructions.
But The application never enter in my actions, always enter in the bundle action.
This is my route:
easy_admin_bundle:
resource: "#EasyAdminBundle/Controller/"
type: annotation
prefix: /admin
And in my bundle, I have a AdminController class which extends EasyAdminController
...
class AdminController extends EasyAdminController
/**
* #Route("/admin/", name="admin")
*/
public function indexAction(Request $request)
{
return parent::indexAction($request);
}
protected function listAction() {
//Never enter here
...
}
Anybody know how can I override this action in my controller?

Create an action - Symfony2

I created a bundle backend/main/:
my app/routing.yml
backendmain:
resource: "#backendmainBundle/Resources/config/routing.yml"
prefix: /main
my backend/Bundle/mainBundle/config/routing.yml:
backendmain_homepage:
pattern: /hello/{name}
defaults: { _controller: backendmainBundle:Default:index }
my backend/Bundle/mainBundle/DefaultController.php:
namespace backend\Bundle\mainBundle\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
class DefaultController extends Controller
{
public function indexAction($name)
{
return $this->render('backendmainBundle:Default:index.html.twig', array('name' => $name));
}
public function testAction($name)
{
return $this->render('backendmainBundle:Default:test.html.twig', array());
}
}
How can I call the action test in my browser?
Sorry, but was Fabien on drugs, when he created Symfony2? Symfony 1.4 was so freaking easy!
There isn't any match in your routes definition for the test action. The only route you added is for the index action. So you need to add something like,
backendmain_test:
pattern: /test
defaults: { _controller: backendmainBundle:Default:test }
In your backend/Bundle/mainBundle/config/routing.yml file so that you can make a call to your test action.
Update:
Using annotations
app/config/routing.yml
backendmain:
resource: "#backendmainBundle/Controller/DefaultController.php"
prefix: /main
type: annotation
DefaultController.php
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
// ...
class DefaultController extends Controller
{
/**
* #Route("/test", name="backendmain_test")
*/
public function testAction()
{
// ...
}
// ...

Resources