Imagine situation, when the url should looks like
/catalog/sectionIdent?page=1
where page param is optional.
Of course, custom route should be defined. Consider the following code:
$route = new Zend_Controller_Router_Route_Regex(
'catalog/([-a-z]+)(?:\?page=([0-9]*))?',
array('controller'=>'catalog','action'=>'list','page'=>''),
array(1=>'section',2=>'page'),
'catalog/%s?page=%d'
);
$router->addRoute('catalog-section-page',$route);
But this route won't be triggered with '?' symbol in url.
Without '?' (for example, by adding escaped '!' symbol to pattern) everything works as it should.
Is there any way to achieve '?' presence in custom defined regex route? Maybe I'm doing something wrong in pattern?
P.S.: Don't offer to use '/' instead of '?', question is exactly about pattern restrictions in Zend_Controller_Router_Route_Regex implementation.
The ZF routing classes operate on the REQUEST_URI with the query string stripped off, so you may have a hard time get this working in the way you are expecting. However, I believe GET parameters are put into the request object by default, so you shouldn't need to cater for them in your routes. I'd suggest changing your route to remove the query string parts:
$route = new Zend_Controller_Router_Route_Regex(
'catalog/([-a-z]+)',
array('controller'=>'catalog','action'=>'list'),
array(1=>'section'),
'catalog/%s'
);
$router->addRoute('catalog-section-page',$route);
You should still be able to access the params in your controller as if they had been populated by the routes:
public function listAction()
{
echo $this->_getParam('page');
}
and you can use the same method to set a default:
public function listAction()
{
$page = $this->_getParam('page', 1); // defaults to 1 if no page in URL
}
You just may need to sanitise them there (make sure they are numeric).
Edit:
Example of URL helper with this route:
echo $this->url(array('section' => 'foo', 'page' => 2), 'catalog-section-page')
Related
When I parse html response body I want to find route names for all links found in the body. I use next code snippet:
my $url = Mojo::URL->new( $got );
my $method = uc( $url->query->clone->param( '_method' ) || 'GET' );
my $c = $t->app->build_controller;
my $m = Mojolicious::Routes::Match->new( root => $t->app->routes );
$m->find( $c => { method => $method, path => $url->path } );
Then $m->endpoint->name gives me the name of route.
But is there more simple way to find route name by given path?
I am looking for something like: $app->routes->find( '/api/v/users/146/link/7QRgs' ) which should return user_hash_check because I have next route:
$guest->get( '/users/:id/link/:hash', 'user_hash_check' )->to( 'user#hash_check' );
I have found only one place where we can find route by path. That is Mojolicious::Routes::Match and there is no other way to do this
The one ugly thing here to my mind is requirement to supply Mojolicious::Controller object. But controller is only required to make decision: dispatch or not dispatch Because it has extra info to make this decision: this is data to check conditions
The problem as I think is because of here are mixed two things:
Request
Path
And find should just return all routes matched against given arguments: path and method. Like selectors does The array result maybe cached (now routes with conditions are not cached)
Then dispatcher should check conditions against each route, not matcher. Here each condition may be called in context of right controller and not default one. And this will fix this issue. The routes have in most cases their own controller class have not?
Until this behavior will be fixed the example in the question is the best way to find routes
I would like to interpret, for example a request like this:
GET /my/path?foo=bar
just as if it was actually rewritten to e.g.
GET /?path=/my/path&foo=bar
Now I thought I'll be able to achieve this using following route, and use param('path') along with param('foo') and the likes, e.g.:
get '/:path' => sub {
return printf "...so you want %s, thinking that best foo is %s...",
param('path'),
param('foo');
}
but I get 404 -- It seems that the :path part cannot contain slashes.
Can I achieve this with routes at all? Or I'm looking at the wrong direction (I'm fresh new to Dancer)?
You might want to match route by regular expression instead of the token. Matches are then stored in a special array that can be returned by keyword splat. Your path will not be accessible by param('path'), though.
Code:
get qr{/([^?]*)} => sub {
my ($path) = splat;
return printf "...so you want %s, thinking that best foo is %s...",
$path,
param('foo');
}
I'm a Zend Framework newbie, and I'm trying to work out how to add another route to my application.ini file.
I currently have my routes set up as follows:
resources.router.routes.artists.route = /artists/:stub
resources.router.routes.artists.defaults.controller = artists
resources.router.routes.artists.defaults.action = display
...so that /artists/joe-bloggs uses the "display" action of the "artists" controller to dipslay the profile the artist in question - that works fine.
What I want to do now is to set up another route so that /artists/joe-bloggs/random-gallery-name goes to the "galleries" action of the "artists" controller.
I tried adding an additional block to the application.ini file (beneath the block above) like so:
resources.router.routes.artists.route = /artists/:stub/:gallery
resources.router.routes.artists.defaults.controller = artists
resources.router.routes.artists.defaults.action = galleries
...but when I do that the page at /artists/joe-bloggs no longer works (Zend tries to route it to the "joe-bloggs" controller).
How do I set up the routes in application.ini so that I can change the action of the "artists" controller depending on whether "/:gallery" exists?
I realise I'm probably making a really stupid mistake, so please point out my stupidity and set me on the right path (no pun intended).
Try reversing the order of the routes. ZF matches routes in the opposite order they are added (so that the default route is the last to be matched)
If that doesn't work, you'll probably have to investigate regex routes with optional components.
Your second block needs to have a different route name, rename the 'artists' word to something similar to this for your new block:
resources.router.routes.artists-gal.route = /artists/:stub/:gallery
resources.router.routes.artists-gal.defaults.controller = artists
resources.router.routes.artists-gal.defaults.action = galleries
I usually setup my routes in application/Bootstrap.php (or wherever your Bootstrap.php file is)
add a method like the one below:
protected function _initRoutes()
{
$ctrl = Zend_Controller_Front::getInstance();
$router = $ctrl->getRouter();
$router->addRoute(
'artist_detail',
new Zend_Controller_Router_Route('artists/:stub',
array('controller' => 'artists',
'action' => 'display'))
);
$router->addRoute(
'artist_detail_gallery',
new Zend_Controller_Router_Route('artists/:stub/:gallery',
array('controller' => 'artists',
'action' => 'gallery'))
);
}
As far as checking weather an specific artist has a gallery, in the case of my example, i would have a galleryAction method in the ArtistsController
do a check if a gallery exists for the 'stub' request paramater, if it doesnt throw a 404:
throw new Zend_Controller_Action_Exception("Object does not exist", 404);
or redirect them to some other page:
return $this->_helper->redirector('index', 'index'); //redirect to index action of index controller
Hope this helps.
I use Zend URL view helper for building my urls. Everythings works exactly as I'd like to, except one thing: The character used for replacing spaces in the url is a plus (+). I'd like it to be a 'min' (-). How can I change this?
Example:
Now: /nl/nieuws/bericht/3/title/nieuwe**+affiches
Wish: /nl/nieuws/bericht/3/title/nieuwe-**affiches
Thanks in advcance!
This isn't in the documentation anywhere, but it appears that the Zend URL view helper can take a parameter in it's $urlOptions array called chainNameSeparator. No guarantee that's what you're looking for, but trying playing with that and see if it changes anything.
This is likely happening because, by default, Zend_View_Helper_Url will urlencode() what you send it, which would translate spaces into +. My suggestion to you would be to create a new view helper for the type of URL in your code that needs the special inflection.
Something like:
class Default_View_Helper_SpecialUrl extends Zend_View_Helper_Abstract
{
public function specialUrl(array $opts = array(), $name = null, $reset = false, $encode = true)
{
if (!empty($opts['whatever'])) {
$opts['whatever'] = str_replace(' ', '-', $opts['whatever']);
}
$router = Zend_Controller_Front::getInstance()->getRouter();
return $router->assemble($opts, $name, $reset, $encode);
}
}
This way the spaces are changed for whatever necessary route parameters before URL encoding happens by the router.
I'm implementing a search box using CodeIgniter, but I'm not sure about how I should pass the search parameters through. I have three parameters: the search string; product category; and the sort order. They're all optional. Currently, I'm sending the parameters through $_POST to a temporary method, which forwards the parameters to the regular URI form. This works fine. I'm using a weird URI format though:
http://site.com/products/search=computer,sort=price,cat=laptop
Does anyone have a better/cleaner format of passing stuff through?
I was thinking of passing it into the products method as arguments, but since the parameters are optional things would get messy. Should I suck it up, and just turn $_GET methods on? Thanks in advance!
Query Strings
You can enable query strings in CodeIgniter to allow a more standard search function.
Config.php
$config['enable_query_strings'] = FALSE;
Once enabled, you can accept the following in your app:
http://site.com/products/search?term=computer&sort=price&cat=laptop
The benefit here is that the user will find it easy to edit the URL to make a quick change to their search, and your search uses common search functionality.
The down side of this approach is that you are going against one of the design decisions of the CodeIgniter development team. However, my personal opinion is that this is OK provided that query strings are not used for the bulk of your content, only for special cases such as search queries.
A much better approach, and the method the CI developers intended, is to add all your search parameters to the URI instead of a query string like so:
http://site.com/products/search/term/computer/sort/price/cat/laptop
You would then parse all the URI segments from the 3rd segment ("term") forward into an array of key => value pairs with the uri_to_assoc($segment) function from the URI Class.
Class Products extends Controller {
...
// From your code I assume you are calling a search method.
function search()
{
// Get search parameters from URI.
// URI Class is initialized by the system automatically.
$data->search_params = $this->uri->uri_to_assoc(3);
...
}
...
}
This would give you easy access to all the search parameters and they could be in any order in the URI, just like a traditional query string.
$data->search_params would now contain an array of your URI segments:
Array
(
[term] => computer
[sort] => price
[cat] => laptop
)
Read more about the URI Class here: http://codeigniter.com/user_guide/libraries/uri.html
If you're using a fixed number of parameters, you can assign a default value to them and send it instead of not sending the parameter at all. For instance
http://site.com/products/search/all/somevalue/all
Next, in the controller you can ignore the parameter if (parameter == 'all'.)
Class Products extends Controller {
...
// From your code I assume that this your structure.
function index ($search = 'all', $sort = 'price', $cat = 'all')
{
if ('all' == $search)
{
// don't use this parameter
}
// or
if ('all' != $cat)
{
// use this parameter
}
...
}
...
}