Symfony router annotations override default controller prefix - symfony

I have a little question about #Routing annotations in symfony.
I have a controller in which i add a default #Route('/api/v1/users'), and in this controller I have a method with #Route('/{userId}/documents'}).
Since I have V2 that add a parameters int this route, but the main logic on method stay the same, I wanted to add a new route ( for V2) on the same method #Route(/api/v2/users/{userId}/{newParam}/documents').
But like there is a default #Route on the controller the route I generate are not good ( because they use the v1 prefix :
Generated :
/api/v1/users/{userId]/documents
/api/v1/users/api/v2/users/{userId]/{newParam}/documents
And I want to have this :
/api/v1/users/{userId]/documents
/api/v2/users/{userId]/{newParam}/documents
Does it exist a way to achieve that without a new controller ? Maybe some options I do not find on #Route ?

I am not sure you can do it with annotation.
The only solution i found is to add your v2 route in routes.yml and match it with the same controller function.

Related

asp.net web api route for controllers with same name

I am integrating my project with another one
Multiple types were found that match the controller named 'XXXXX'.
This can happen if the route that services this request ('api/{controller}/{action}/{id}') found multiple controllers defined with the same name but differing namespaces, which is not supported.
The request for 'XXXXX' has found the following matching controllers:
COM.example.host.XXXXXController
COM.example.parasite.XXXXXController
Is there a way to make this somehow work with the least amount of edit from either side?
I would like to avoid having to make modifications to all of my controllers.
Thank you
Unfortunately, that is not very simple because default controller selector (DefaultHttpControllerSelector) does not look for namespace in the full controller name when it selects controller to process request.
So, there are at least two possible solutions to your problem:
Write your own IHttpControllerSelector which takes controller type namespace into account. Sample can be found here.
Rename one of controller types to make then unique.
TL;DR Default controller selector uses the cache of controller types (HttpControllerTypeCache) which holds something like:
{
"Customers" : [
typeof(Foo.CustomersController),
typeof(Bar.CustomersController)
],
"Orders" : [
typeof(Foo.OrdersController)
]
}
So it uses controller name as dictionary key, but it can contain several types which have same controller name part. When request is received, controller selector gets controller name from route data. E.g. if you have default route specified "api/{controller}/{id}" then request api/customers/5 will map controller value to "customers". Controller selector then gets controller types which are registered for this name:
if there is 1 type, then we can instantiate it and process request
if there is 0 types, it throws NotFound exception
if there is 2 or more types, it throws AmbiguousControllerException exception (your case)
So.. definition of another named route will not help you, because you can only provide controller name there. You cannot specify namespace.
Even if you'll use Attribute Routing and specify another route for one of the controller actions
[RoutePrefix("api/customers2")]
public class CustomersController : ApiController
{
[Route("")]
public IHttpActionResult Get()
//...
}
you will still face the controller selector problem because attribute routes are applied to actions - there will be no controller value in route data for those requests. Attributed routes are treated differently - they are processed as sub-routes of the "MS_attributerouteWebApi" route.
The easiest path for you might be to add action based routing to your web api:
RouteTable.Routes.MapRoute(
"WithActionApi",
"api/{controller}/{action}/{id}"
);
To your WebApiConfig.cs, be sure to put it above the default rule. Then, change how you call your controllers by including the method name, which at this point should be or should be made unique.

How do you manually create Controllers in Symfony2 without the use of the command line?

I am unable to create Controllers through the Command line. Does anyone know how can I manually create controllers for my Symfony2 project?
What files I need to update?
You should create file YourControllerNameController.php at src/YourBundle/Controller folder. And put class with name YourControllerNameController into this file. Also be assured that you wrote right namespace according to PSR-0.
If you create controller as a service you can define it as a service and have no problem.
If you want create standard controller that are not registered at service container you could extend your class from Symfony\Bundle\FrameworkBundle\Controller\Controller
In both cases you need also define route for your actions. The easiest way would be to define one route with annotation type. It will generate routes automatically based on your annotations related to actions:
your_route_name:
resource: "#YourBundle/Controller"
type: annotation
It will scan your src/YourBundle/Controller folder and will generate new route for any method in any class in any file that will have annotation #Route:
/**
* #Route("/your/path", name="you_can_specify_name_here_but_it_is_optional")
*/
public function yourAction()
{
// Your code here
}

Symfony2 / routing / use parameters as Controller or Action name

Is it possible to route to a controller/action using given parameters ?
For example :
my_custom_route:
pattern: /{controller}/{action}
defaults: { _controller: AcmeDemoBundle:[controller]:[action] }
I would like [controller] and [action] to be replaced by given route's parameters values.
I.E : http://www.somedomain.com/Content/add should call action "addAction" of controller "ContentController" in bundle "AcmeDemoBundle"
Yes you can do so however it is not recommended. What would you do in future of you had to refactor your code and your controller / action had to change? You may break links and functionality along with possibly losing search engine optimization that may have been done for that particular route.

How to pass arguments to controller from route in Symfony2

I'm working on a Symfony2 project and am trying to figure out how to pass parameters from the route configuration to the controller. I know I can configure default values in the route configuration, and retrieve the values in the controller using the appropriate var name in the function declaration, but that isn't exactly what I want.
My use case is the following. I have a standard method in my controller that I want to access from 2 or 3 different routes. Depending on which route is being called, I want to "configure" the method differently. I can accomplish this in a few ways:
In my controller, check the route name using `$this->container->get("request")->get("_route"), but that is ugly, and then I am hardcoded to the route name. Moves configuration to the controller, which should just be logic - not configuration.
Create a base controller class, and subclass each method for my different routes. Each subclassed method would then have the necessary configuration within the method. Cleaner soln than #1, but still "heavy" in the sense of having multiple classes for a simple need and still pushes configuration data into the business logic.
Put configuration data into the route configuration. In the controller, access the configuration data as required. Ideal solution, but don't know how.
I can use the route default array to specify my arguments, but then must make sure to use a regex to ensure that the params are not overridden at the URL level (security risk). This is functional, but still kinda cludgy and not a pretty hack.
I presume that there must a better way to do this, but I can't seem to figure it out. Is there a way to access the routing object from the controller, and access the different configuration parameters?
You can pull the actual route from the router service. Something like:
$routeName = $this->container->get("request")->get("_route");
$router = $this->container->get("router");
$route = $router->getRouteCollection()->get($routeName);
Not sure if this would be such a great design though. Consider passing a $configName to your controller method, adding a parameter with the same name in a config file then using getParameter to access it. That would eliminate the route stuff from the equation.
Something like:
zayso_arbiter_import:
pattern: /import
defaults: { _controller: ZaysoArbiterBundle:Import:index, configName: 'someConfigName' }
public function importAction(Request $request, $configName)

How do I pass variable to controller

I create my own bundle. There is a class in this bundle.
In this class I have a variable $Url. I would like to use this variable in my controller in another bundle. How do I pass a variable to a controller in a different bundle?
I think the best option is to create a Controller as a Service. You can read about that in a blog article by Richard Miller.
After you have done that, you can create a service parameter with the value of $Url:
# app/config/config.yml
parameters:
my_first_bundle.url: Some value
services:
# request and response services
my.response:
class: Symfony\Component\HttpFoundation\Response
my.request:
class: Symfony\Component\HttpFoundation\Request
# controller services
my_second_bundle.mycontroller:
class: Acme\MySecondBundle\Controller\MyController
arguments: [ %my.response%, %my.request%, %my_first_bundle.url% ]
It sounds like you need to turn that class into a service and set the $url value with dependency injection.. Or you may néed to persist the $url if you plan to modify $url in one controller and access it again in another controller later on. Either way, you'll need to turn that class file into a service.

Resources