How do you retrieve a route pattern from the route name in Silex? - symfony

Suppose I defined a route and named it new as shown below. How can I use the name to retrieve the route's pattern path /new?
class AppControllerProvider implements ControllerProviderInterface {
public function connect(Application $app) {
$controllers = $app['controllers_factory'];
//some code here...
$controllers->get('/new', function (Request $req) use ($app) {
return $app['twig']->render('content/new.twig', ['params' => $params, 'errors' => []]);
})->bind('new');
//some code here...
$app['url_generator']->generate('new') can be used to return the path for the route. Is there an analogous sort of method? I inquire because I'd like to be able to conveniently access the pattern in case it's modified, and keep the route names the same.

The following seems to work, as it finds the controller matching the route name, then finds the route, and finally outputs the corresponding pattern:
$app['controllers_factory']->get('new')->getRoute()->getPattern()
Unsure whether or not there's a simpler way.

Related

How to pass query string with routes in laravel 5.4

I am using Laravel 5.4. I want to use query string like below:
tempsite.com/lessons?id=23
For getting this how routes are to be modified. It is possible to give route in the following way.
Route::get('lessons/id={id}', ['as' => 'lessons.index', 'uses' => 'Lessons\LessonController#index']);
But adding '?' is not getting for me. Please help us to provide a solution as early as possible.
If you are using resourceful controllers, your routes are all handled for you so you would simply put
Route::resource('lessons', 'Lessons\LessonController');
You can then use route model binding to bind the model instance which matches that particular ID.
Route::model('lesson', Lesson::class);
This would be done in your RouteServiceProvider.
I would also suggest having a good read of the following documentation on the laravel website https://laravel.com/docs/5.4/routing. It provides really good insight in to how routes work and how they should be structured.
Instead of tempsite.com/lessons?id=23
Pass it like this tempsite.com/lessons/23
and in the route
Route::get('lessons/{id}', ['as' => 'lessons.index', 'uses' => 'Lessons\LessonController#index']);
to get the id in your controller, write your function like this
public function index($id)
{
//do anything with $id from here
}
There is no need to define query string parameters in your routes. You can return query string parameters in your controller like so:
URL example: tempsite.com/lessons?id=23
public function lessons(Request $request)
{
$request->get('id'); // Using injection
Request::get('id'); // Using the request facade
request()->get('id'); // Using the helper function
}
You could even validate the parameter:
public function lessons(Request $request)
{
$this->validate($request, ['id' => 'required|integer']);
}
Note: If you want to make the URL not accessible if the ID is omitted, see #DarkseidNG answer.
I was able to inform laravel to accept query stringed requests on my route by affixing the url with a forward slash, like so
// web.php
Route::get('/path/', "Controller#action");
With the above, mysite/path?foo=bar&name=john does not throw 404 errors.

How To Call a Common function to Every (Twig) Symfony2

Hi I have a common function to get a Client Name dynamicaly. Now I want to call that function to every view (Twig). I am following it like this:
//My controler
public function getSchoolNameAction(){
$session = new Session();
$dm = $this->getDocumentManager();
$commonFunction = new CommonFunctions();
return $schoolName= $commonFunction->schoolName($dm,$session);
}
//My View (search.html.twig)
{% render controller('EduAccountBundle:Ledger:getSchoolName') %}
But its showing an error that :
he controller must return a response (null given). I need to make it for every view. Please guide me how to fix this
Don't define a controller as a service, controllers should be used only to take a request and to produce a response (you're just returning a value, that isn't acceptable for Symfony logic)
Unless you want to return a rendered template (or produce a valid response, such like a json response) to put where you're calling the common action (you could do that of course), I will recommend to write a custom twig extension

How can I add multiple Get actions with different input params when working RESTFUL?

I'm trying to figure out whats the best way to have multiple Get actions in a REST controller.
I would like to do something like this:
Get By Id:
public ResponseType Get(Guid id)
{
// implementation
}
Get By Enum Type:
public ResponseType Get(EnumType type)
{
// implementation
}
Get By Other Enum Type:
public ResponseType Get(OtherEnumType otherType)
{
// implementation
}
etc..
Now when I do something like that, I get the next error message:
Multiple actions were found that match the request
I understand why I get the message and I was thinking how is the best way to do something like that (I want to stick with REST).
I know I can add a route like this:
routeTemplate: "api/{controller}/{action}/{id}"
But then I would need to change the action names and the urls - And this seems like a workaround when we are talking about rest.
Another thing I thought was to create multiple controllers with one Get - But that seems even wronger.
The third workaround was to handle one Get action with an input param that will have the state:
public ResponseType Get(ReqeustObj obj)
{
switch(obj.RequestType)
{
case RequestType.GetById:
// etc...
}
}
Anyway, I would like to know whats the best way to do something like that in REST (WebApi).
As you now, when Web API needs to choose an action, if you don't specify the action name in the route, it looks for actions whose name starts with the method name, GET in this case. So in your case, it will find multiple methods.
But it also try to match the parameters. So, if you include the parameters as part of the url (route parameters) or the query string, the action selector will be able to choose one of the available methods.
If you don't specify a parameter or specify the id in the url (or even in the query string) it should invoke the first overload. If you add the parameter name of the second action in the query string like this: ?type=VALUE it should choose the corresponding overload, and so on.
The question is that the parameter names must be different, or it will not be able to choose one or the other among all the overloads.
For example, if you use the urls in the comments in your browser, you'll see how the right method is chosen:
public class TestController : ApiController
{
// GET api/Test
public string Get()
{
return "without params";
}
// GET api/Test/5
public string Get(int id)
{
return "id";
}
// GET api/Test?key=5
public string Get(string key)
{
return "Key";
}
// GET api/Test?id2=5
public string Get2(int id2)
{
return "id2";
}
}
NOTE: you can also use route constraints to invoke differet methods without using query string parameters, but defining different route parameter names with different constraints. For example you could add a constraint for id accepting only numbers "\d+" and then a second route which accepts "key" for all other cases. In this way you can avoid using the query string

MVC3 ActionName attribute, its behaviour and effects

While reading about mcv3 I came across an attribute name called [ActionName]. It actually gives a new name to the action method. I tested a scenario which made me think; how are the internals working. When I have the following two action methods in my controller class
[ActionName("Test")]
public ActionResult Index()
{
return View();
}
[ActionName("Index")]
public ActionResult Test()
{
return View();
}
I thought this will end up in some kind of infinite loop or will give some ambiguity exception. But the same works fine and the second method is called when i give this url http://mysite:1234/mycontroller
What made MVC engine to choose the second method and not the first?
Any idea why this happens?
Phil Haack has a post on this matter: How a method becomes an action
In short: the ControllerActionInvoker uses reflection to find a method matches the action name.
The ActionNameAttribute redefines the name of the method.
Also be aware that the name of your View matches the ActionName, not the MethodName: the method Index will search for a view with the name "Test"
This is the magic of the Routing engine. Somewhere within the global.asax.cs file there would be routing patterns defined, mostly which defaults to
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", id = "" } // Parameter defaults
);
This is a routing pattern defined for your application. The action name attribute maps to the 'action' parameter within the parameter collection (3rd parameter for MapRoute).
In your case if you map the action 'Index' to method 'Test'. It should call Test() method. I am not sure whether it is still calling Index() for you. In fact the routing engine does not care about the method name if it finds the ActionName attribute over your public method.
ActionNameAttribute it represents an attribute that is used for the name of an action. If it is not present the name of the method is used.

mvccontrib test helper and verifying http post routes and parameters

In my Asp.net MVC app, I have two methods on a controller, one for when the user first arrives on the view and then one when they submit the form on said view.
public ActionResult Foo() {}
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Foo(string id, Account accountToFoo) {}
In the second action, there's a custom model binder that's assembling the account object that I'm acting on, though that's really not important. This all works fine in testing locally on a server.
We try to be pretty good about writing unit tests to test all our different views are properly getting routed to, including those that are HTTP POST. To do so, we've been using mvccontrib's test helper.
Testing gets have been super simple
"~/account/foo/myusername".
Route().
ShouldMapTo<AccountController>(c => c.Foo("myusername"));
My question is in testing POST routes, how do I write the lambda that I would use to verify the post is receiving accurate values, similar to the GET test above?
For a POST, it looks something like:
"~/account/foo".
WithMethod(HttpVerbs.Post).
ShouldMapTo<AccountController>(a => something_something);
It's the something_something portion of my lambda that I'm having trouble with. Using arbitrary values doesn't work ("a => a.Foo(0, new Account()"). How would I specify the expected values as part of the test?
EDIT I was hoping there was something akin to the way Moq has lambdas for statements such as foo.Setup(s => s.Foo(It.IsAny(), It.Is(i => i > 32)) and so on. Even I have to explicitly supply the values, that's workable--I just can't seem to grok the desired structure to pass those explicit values.
Here's an example. Assuming you have the following action:
public AccountController : Controller
{
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Foo(string id)
{
return View();
}
}
And the following route registered:
RouteTable.Routes.MapRoute(
"Default",
"{controller}/{action}/{id}",
new { controller = "home", action = "index", id = "" }
);
You could test it like this:
var routeData = "~/account/foo".WithMethod(HttpVerbs.Post);
routeData.Values["id"] = "123";
routeData.ShouldMapTo<AccountController>(c => c.Foo("123"));
Some tweaking might be necessary to include the second Account argument you have.
Using the mvccontrib helper syntax:
"~/account/foo".WithMethod(HttpVerbs.Post).ShouldMapTo<AccountController>(a => a.foo(null));
You pass null as the Foo(string id, Account accountToFoo) method is never executed as part of the routing test.

Resources