Why params plugin magic function default forwarding route?
Why zf not able to get function from parameter like sample below?
public function __invoke($param = null,$type='Route', $default = null)
{
if ($param === null) {
return $this;
}
$type = 'from'.ucfirst($type);
// Need to check function exist, if not must throw some error
return $this->$type($param, $default);
}
Example use
$this->params('name','post');
$this->params('token','get');
$this->params('action'); // this will return from route like default one.
How can i extend default params plugin like this? And is it a good move?
The default params are always fetched from the Route. This is because ZF2 encourages people to do lot of manual routing. This is both for speed purposes, as well as SEO purposes.
$this->params('paramname', 'defaultValueIfNotFound');
In the cases where you need the params from specific regions of the request, you can do that, too, using the params-plugin itself. But this has already been explained greatly by #Matsemann
How to access Route/Post/Get/etc parameters in Zend Framework 2
You could extend the params plugin, but you should use the third parameter for the additional option. Bear in mind though, that the other approach is simply cleaner and ultimately requires less work by the plugin. No switch-statement just to get a param ;)
Related
For google analytics, and to match the websearch parameters correctly on the keyword strategies, i want to make sure the google supplied gclid parameter gets passed on when redirects happen in the controller.
The reason for the redirect is to do split testing, and A/B testing on landingpages, as well as vanity urls matching the campaign themes better.
Currently - this is the way I "Hack" it:
public class ArtclassController : Controller
{
//
// GET: /Artclass/
public ActionResult Kid(string gclid)
{
string _glcid = gclid;
return RedirectToAction("Index", "ArtClassesForKids", new {glcid= _glcid });
}
My question is - is there a way to do this more elegantly? For instance, in the MVC routing?
(For brevities sake, in the supplied code example I have left out a second redirect, and the random function to choose a different landing page.)
I do not believe that there is a way, though you might be able to get away with using Session or even TempData to accomplish your mission.
Wherever gclid is determined in your code now use:
Session["gclid"] = gclid;
Wherever gclid is needed use:
gclid = Session["gclid"];
This is a more specific version of another of my questions: Restful MVC Web Api Inheritance, I hope an answer to this will help me answer that.
Im using ASP.NET web api,
I want to be able to route something like this: [{object}/{id}]/{controller}/{id}.
so i want an array of objects with optional /{id} ending with the 'api endpoint'.
I want to be able to route these:
/houses
/houses/3
suburbs/3/houses
council/5/suburbs/houses
city/8/council/suburbs/houses
ETC
TO
get(List<restRoute>parents, int id){
...
}
restRoute would be an object with a string for the object and an optional int (or guid etc) for the id
Does anyone know where i can start?
I don't want to route every single one individually.
I had also such problems with routing from the box in ASP.NET MVC. Its good way to be used as common routing, but is not so flexible for custom routs.
In WCF Web Api (ASP.NET web api in CTP version) was used attribute based routing.
I think its more flexible, but as negative point - each method should have routing attribute.
Take a look at this blog post:
http://www.strathweb.com/2012/05/attribute-based-routing-in-asp-net-web-api/
It describes how to implement attribute based routing using ASP.NET Web Api. Because such approach is more flexible for routes you can map to methods, it can be helpful for you.
You could use the {*anything} Variable Segmented URL pattern in your route and handle the splitting up and figuring out of what part of the url corresponds to what bit of data in your method:
Global.asax:
routes.MapRoute(
"Special", // name
"{*allthethings}", // parameters
new { controller = "Special", action = "Sauce" } // defaults
);
SpecialController:
public ActionResult Sauce()
{
string data = RouteData.Values["allthethings"].ToString();
string[] items = data.Split('/');
foreach (string item in items)
{
// do whatever you need to figure out which is what!
}
return View();
}
If you wanted to be a bit cleverer about it you could create your own custom RouteHandler to do the splitting. Something like David Ebb's PK routehandler would probably do the trick, with some customisation to fit your requirements in the processing of the route. You could use this to split up the "allthethings" parameter and turn it into your List<RestRoute> format before passing the request on to the Controller
In my webapplication, I always reply with JSON to AJAX calls.
Thus I find myself doing this on a lot of actions:
if ($request->isXmlHttpRequest()) {
$this->getResponse()->setHttpHeader('Content-type', 'application/json');
return $this->renderText(json_encode($details));
}
Is there a way to get that automatically: anytime the request is AJAX, the content type is JSON?
I was thinking I should use a filter maybe but I am not familiar with filters and maybe there is a better solution.
Any suggestion will be more than welcome.
Thanks,
Dan
The way I solved it:
Create a new class myActions which extends from sfActions. In this class create a new function renderJson($data):
protected function renderJson($data) {
$this->getResponse()->setHttpHeader('Content-type', 'application/json');
return $this->renderText(json_encode($data));
}
Now let your controller class inherit from myActions (instead of sfActions). And at the end of your controller just return $this->renderJson($data);.
(I also did some templating. in the renderJson, if the sf_debug is set in the config, and it's not requested through XmlHttp.)
I'm using a similar technique in one of my projects, but I'd suggest also taking a look at this article regarding iPhone optimization. You can set your routing to accept a format and return the appropriate template based on that. Then you don't need to set the header as it's set by the requested format.
Of course, this means you'll need to create separate template files for each output template, which seems a bother, or use a particular layout file and skip the template. So in the end it may amount to pretty much the same thing (or same amount of code, at least).
Recently, I'm trying to migrating my application from CakePHP to Grails. So far it's been a smooth sailing, everything I can do with CakePHP, I can do it with much less code in Grails. However, I have one question :
In CakePHP, there's an URL Prefix feature that enables you to give prefix to a certain action url, for example, if I have these actions in my controller :
PostController
admin_add
admin_edit
admin_delete
I can simply access it from the URL :
mysite/admin/post/add
mysite/admin/post/edit/1
mysite/admin/post/delete/2
instead of:
mysite/post/admin_add
mysite/post/admin_edit/1
mysite/post/admin_delete/2
Is there anyway to do this in Grails, or at least alternative of doing this?
Grails URL Mappings documentation doesn't help you in this particular case (amra, next time try it yourself and post an answer only if it's any help). Daniel's solution was close, but wouldn't work, because:
the action part must be in a closure when created dynamically
all named parameters excluding "controller", "action" and "id" are accessible via the params object
A solution could look like this:
"/admin/$controller/$adminAction?/$param?"{
action = { "admin_${params.adminAction}" }
}
The key is NOT to name the parameter as "action", because it seems to be directly mapped to an action and can not be overriden.
I also tried a dynamic solution with generic prefixes and it seems to work as well:
"/$prefix/$controller/$adminAction?/$param?"{
action = { "${params.prefix}_${params.adminAction}" }
}
I didn't test it, but try this:
"mysite/$prefix/$controller/$method/$id?"{
action = "${prefix}_${method}"
}
It constructs the action name from the prefix and the method.
Just take a look on grails URL Mappings documentation part
What's the best way to handle a visitor constructing their own URL and replacing what we expect to be an ID with anything they like?
For example:
ASP.Net MVC - handling bad URL parameters
But the user could just as easily replace the URL with:
https://stackoverflow.com/questions/foo
I've thought of making every Controller Function parameter a String, and using Integer.TryParse() on them - if that passes then I have an ID and can continue, otherwise I can redirect the user to an Unknown / not-found or index View.
Stack Overflow handles it nicely, and I'd like to too - how do you do it, or what would you suggest?
Here's an example of a route like yours, with a constraint on the number:
routes.MapRoute(
"Question",
"questions/{questionID}",
new { controller = "StackOverflow", action = "Question" },
new { questionID = #"\d+" } //Regex constraint specifying that it must be a number.
);
Here we set the questionID to have at least one number. This will also block out any urls containing anything but an integer, and also prevents the need for a nullable int.
Note: This does not take into account numbers that larger than the range of Int32 (-2147483647 - +2147483647). I leave this as an exercise to the user to resolve. :)
If the user enters the url "questions/foo", they will not hit the Question action, and fall through it, because it fails the parameter constraint. You can handle it further down in a catchall/default route if you want:
routes.MapRoute(
"Catchall",
"{*catchall}", // This is a wildcard routes
new { controller = "Home", action = "Lost" }
);
This will send the user to the Lost action in the Home controller. More information on the wildcard can be found here.
NB: The Catchall should reside as the LAST route. Placing it further up the chain will mean that this will handle all others below it, given the lazy nature of routes in ASP.NET MVC.
Here is some useful infromation that might help.
If you have a action method
public ActionResult Edit(int? id)
{}
then if someone types in
/Home/Edit/23
the parameter id will be 23.
however if someone types in
/Home/Edit/Junk
then id will be null which is pretty cool. I thought it would throw a cast error or something. It means that if id is not a null value then it is a valid integer and can be passed to your services etc. for db interaction.
Hope this provides you with some info that I have found whilst testing.
In ASP.NET MVC, you can define a filter implementing IActionFilter interface. You will be able to decorate your action with this attribute so that it will be executed on, before or after your action.
In your case, you will define it to be executed "before" your action. So that, you will be able to cancel it if there is an error in the passed parameters. The key benefit here that you only write the code which checking the passed paramaters once (i.e you define it in your filter) and use it wherever you want in your controller actions.
Read more about MVC filters here: http://haacked.com/archive/2008/08/14/aspnetmvc-filters.aspx
You can specify constraints as regular expressions or define custom constraints. Have a look at this blog post for more information:
http://weblogs.asp.net/stephenwalther/archive/2008/08/06/asp-net-mvc-tip-30-create-custom-route-constraints.aspx
You will still need to deal with the situation where id 43243 doesn't map to anything which could be dealt with as an IActionFilter or in your controller directly.
The problem with that approach is that they still might pass an integer which doesn't map to a page. Just return a 404 if they do that, just as you would with "foo". It's not something to worry about unless you have clear security implications.