Symfony where to initialize routes? (routing.yml or inside controller) - php

On the routing page of smyfony is an routing example (the first one). Now they give us 4 options of code (Annotations, YAML, XML, PHP). Where is the difference? And maybe you can take a look on my Controller + Route.
The controller looks like this:
<?php
namespace AppBundle\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
class ToDoListController extends Controller
{
/**
* #Route("/ToDoList", name="ToDoList")
*/
public function showToDoList()
{
}
}
?>
Now I added this route into the routing.yml too.
ToDoList:
path: /Aufgabenliste
defaults: {_controller: AppBundle\Controller \ToDoListController::showToDoList}
Is that correct? Whats about the path? In the first example of the symfony page they wrote defaults: { _controller: AppBundle:Blog:show } but in the description they wrote:
The _controller string is called the logical name. It follows a pattern that points to a specific PHP class and method, in this case the AppBundle\Controller\BlogController::listAction and AppBundle\Controller\BlogController::showAction methods.

Allright. So in Symfony you get to choose between different methods of routing. You can do this for example via annotations or yml(I used to use yml but now I switched to annotations). The only difference is in... format of the file ;) For example I realy like to use annotations because instead of having one billion entries in one file I have every route right next to the code it leads to. At this point for you it depends on what you like better. However I think it's considered as good practice to use annotations.
<?php
namespace AppBundle\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
class ToDoListController extends Controller
{
/**
* #Route("/ToDoList", name="ToDoList")
*/
public function showToDoList()
{
}
}
?>
Code above is ok - you used required namespaces and created correct annotation. All of this you have to do in your bundle you are working on. Also you have to go to app/config/routing.yml and put there something like this:
YourBundleName:
resource: "#YouBundle/Controller/"
type: annotation
Of course it's just an example - you need to adjust it to your needs. This way you are saying to Symfony that you want to use annotations.

Related

Controller has no container set, did you forget to define it as a service subscriber

I'm trying to refactor some controllers in Symfony 5 server, but suddenly I'm unable to change or create controllers because of the following error:
'App\Controller{{ControllerName}}' has no container set, did you forget to define it as a service subscriber?
This is the controller:
<?php
namespace App\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\HttpFoundation\Request;
use App\Entity\Shiftsummary;
use App\Entity\Station;
use App\Entity\Shift;
use App\Entity\Line;
use \Datetime;
class StartStationController extends AbstractController {
/**
* #Route("/start", name="StartStation")
*/
public function route(Request $request)
{
...
} }
This is the content of service.yaml
services:
_defaults:
autowire: true
autoconfigure: true
App\:
resource: '../src/*'
exclude: '../src/{DependencyInjection,Entity,Migrations,Tests,Kernel.php}'
App\Controller\:
resource: '../src/Controller'
tags: ['controller.service_arguments']
The controllers are inside the src/controller/ folder
The issue had to do with the cached files, deleting /var/cache made the error not occur.
Thanks go to Cerad for point this out.
I have to add that if you set the wrong namespace, you get this error too:
// src/Controller/Api/ProductController.php
namespace App\Controller;
class ProductController extends AbstractController {}
namespace must follow folders structure.
namespace App\Controller\Api;
this is just it, your controller did not have container injected. However, framework expects it to be done if your controller inherits from AbstractController.
in ControllerResolver.php:
TLDR; What you need is to inject it.
In your services.yaml, add the following setter call
In my case, the class had just a different name than the file.
You have to change:
namespace App\Controller;
with:
namespace App\Controller\Api;
None of above helped in my case.
I solved my case by:
calls:
- [setContainer, ["#service_container"]]
https://symfony.com/doc/5.4/service_container/calls.html
In my case it was an error in the controller name when I used the bin/console command :
bin/console make:controller APIController this command add automatically suffix -Controller to the file.
Then the controller created is called APIControllerController.
Next I made a copy/paste of Auth0 guide to create API nammed APIController.
In the end the file had the name APIControllerController.php and the class APIController: you just had to change the filename and remove the duplicate -Controller suffix.
Or - in general - verify the name of file controller and the class name ;)
(Another possibility, even more basic than the other suggestions:)
I had a simple controller that was requiring another PHP file, but in the course of some changes that required file couldn't even be compiled. Fixing that required file resolved the somewhat misleading "has no container set..." message.
I have just resolved this issue.
Turned out for me - I had miss typed __construct() as a private function, should be public

Controllers managed by the dependency injection container and "action" suffix

In Symfony 2+, when you describe the method that is executed for a specific route, you can use either:
MyBundle:MyController:hello
Or, given that you setup MyController to be managed by the dependency injection container as service my_controller:
my_controller:helloAction
Why does Symfony expect the Action suffix in one case but not the other?
Why does the second variant NEED helloAction instead of hello,
like in the first variant?
Nope!
Don't be misled.
When defining controller as service, the controller method names can be whatever name you want.
Thus, if in your controller you have method called hello, so you must define it in the routing config as hello only, instead helloAction (which is wrong). That is why symfony expects for a valid callable name.
On the other hand, when extending from default framework controller, Symfony expects all methods name have a Action suffix (That's just a convention rather than technical requirement, see Symfony\Component\HttpKernel\KernelInterface#ControllerNameParser, line 78).
Here is a practical exemple:
namespace AppBundle\Controller;
/** My controller as service */
class DefaultController
{
public function hello()
{
return new Symfony\Component\HttpFoundation\Response('Hello!');
}
}
My route settings:
# app/config/touting.yml
hello:
path: /hello
# NOTE: Method name is hello, not helloAction
defaults: {_controller: app.controller.default:hello}

Why we use "Action" in Symfony2 controller's methods?

I've just started working my way through the symfony2 book.
I wonder why do we named our controller's functions Action:
public function [something]Action() { // ...
In everyone example in the book thus far and all code I see online Action is the function name. There's any reason for it?
This works perfectly:
<?php
// src/AppBundle/Controller/LuckyController.php
namespace AppBundle\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpFoundation\JsonResponse;
class LuckyController extends Controller{
/**
* #Route("/lucky/number/{count}")
*/
public function countTESTING($count){
return new Response(
'<html><body>I DONT HAVE TO CALL THIS somethingACTION</body></html>
');
}
}
?>
I've tried googline this but I see no mention or reasoning as to why. Could someone explain why we use that suffix?
It's just a conventions. You can use those suffixes, but you can also do without it.
If you have
public function somethingAction()
in your controller, you can refer it in the routing configuration in this way:
index:
path: /path_for_something
defaults: { _controller: AppBundle:Index:something }
The _controller parameter uses a simple string pattern called the logical controller name. So, AppBundle:Index:something means:
Bundle: AppBundle
Controller class: IndexController
Method name: somethingAction
But, you can also do this without this feature. Symfony is very flexible, and it does not force you to do almost anything. It is just one of many ways you have to do the same thing.
If you adopt this convention, it's easier for you to understand which action do you have in your controller, it's easy for other developer to understand your code, and it's easier for symfony2 to locate your actions/controllers inside your bundle, so that you can also overriding controllers. This is the best practice.
But if you don't want these benefits, you can using its fully-qualified class name and method as well:
index:
path: /something
defaults: { _controller: AppBundle\Controller\IndexController::indexAction }
But, as the documentation say:
if you follow some simple conventions, the logical name is more
concise and allows more flexibility.
No it wasn't just a naming convention. It was used to execute some code before or after every controller 'action' method. Like checking is user has logged in.
It is based on magic __call function which is executed for a non-existent or non-public method call.
$controller = new Posts();
$controller->index();
class Posts
{
public function __call($name, $args)
{
//run code before
call_user_func_array()[$this, "$nameAction"], $args);
//run code after
}
public function indexAction()
{
}
}
You HAVE TO name your actions
public function somethingAction(){}
because your routes point to a controller, and the action you want to call.
you can also have private functions in your controller, that you will only name
private function something(){}
I say that using yml to configure controllers, i dont believe its different when using annotations, but my advise is to use yml for configuring controllers... really !

FileLoaderException: Cannot import resource "mycontroller" from "C:/wamp/www/Symfony/app/config\routing.yml

I just followed the tutorial about single route on github for this bundle : https://github.com/FriendsOfSymfony/FOSRestBundle/blob/master/Resources/doc/5-automatic-route-generation_single-restful-controller.md
But I got this error when I'm trying to load my home page:
"FileLoaderException: Cannot import resource "ADC\OgppBundle\Controller\OgppRestController" from "C:/wamp/www/Symfony/app/config\routing.yml" (Class could not be determined for Controller identified by "ADC\OgppBundle\Controller\OgppRestController".)
I know this is some basic stuff but I cannot make it work. Here is the code :
app/config/routing.yml
adc_rest:
resource: ADC\OgppBundle\Controller\OgppRestController
type: rest
ADC\OgppBundle\Controller\OgppRest.php
namespace ADC\OgppBundle\Controller;
use FOS\RestBundle\Controller\Annotations\View;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
class OgppRestController extends Controller
{
public function getProfilesAction()
{
} // "get_profiles" [GET] /profile/all
public function getProfileAction($id)
{
} // "get_profile" [GET] /profile/{id}
}
EDIT : I tried to clear the cache in dev environment but when I do it I have the same issue.
Hope this helps
I don't know how FOSRestBundle works (I've never used it), but I think your controller file name is wrong, it should be OgppRestController.php, not OgppRest.php.

Combining view layer and automatic route generation

I am having problems including FOSRestBundle in my Symfony 2.1 project.
When I use automatic route generation ( documentation ) and want to use the view layer ( documentation ).
I receive an exception: No route found for "GET /users".
My config.yml:
fos_rest:
routing_loader:
default_format: json
My routing.yml:
users:
type: rest
resource: Api\UserBundle\Controller\UsersController
My UsersController class:
namespace Api\UserBundle\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use FOS\RestBundle\Controller\FOSRestController;
class UsersController extends FOSRestController
{
public function getUsersAction() { die('get'); }
public function postUsersAction() { die('post'); }
}
When I remove extends FOSRestController everything works - but I lose the view layer functionality. Anyone who can steer me in the right direction to solving this problem?
I don't know if you manage to solve it by now... But I had the very same problem and it seems to come from the fact that FOSRestController implements ClassResourceInterface (FOSRestBundle will determine the resource based on the Controller name).
All I had to do to make it work was omitting the resource name from the methods.
https://github.com/FriendsOfSymfony/FOSRestBundle/blob/master/Resources/doc/5-automatic-route-generation_single-restful-controller.md
/ jonas

Categories