Zend framework router problem - strange routing behavior - php

I've set the following routes for in Zf:
$router->addRoute(
'page',
new Zend_Controller_Router_Route('stranka/:niceuri/:id', array('controller' => 'page', 'action' => 'index'))
);
$router->addRoute(
'cat',
new Zend_Controller_Router_Route('kategoria/:niceuri/:id', array('controller' => 'category', 'action' => 'index'))
);
The problem is that the 'cat' route keeps overwriting the other 'page' route and simle $this->url() routes aswell. That means, that any links using the 'page' route and having the param 'niceuri' defined have the the value of 'niceuri' equal to the currently open page using the 'cat' route - which they sholdn't have. (sorry, does that make sense to you?) Any ideas on how to solve this behavior? Thanks a lot.

I didn't exactly understand what did you mean, but...
When you calling $this->uri helper in view you can set the name of the preffered router to use to assemble the url. Something like this:
echo $this->uri(array('niceuri' => 'Ololo', 'id' => '123'), 'page');
Hope this helps.

Related

CakePHP pagination on custom route

I obviously have a fundamental misunderstanding of how pagination works in CakePHP.
I have the following route set up which shows all posts in a category:
Router::connect('/:parent/:category',
array('controller' => 'posts', 'action' => 'viewCategory'),
array('parent' => '[a-z0-9-]+', 'category' => '[a-z0-9-]+'));
The pages work fine, however the pagination helper is outputting the wrong links for pagination.
I'm using $this->Paginator->numbers().
It's outputting links in this format: mysite.com/posts/viewCategory?page=2
rather than like this: mysite.com/parent-category/sub-category?page=2.
I've tried adding the following route after the first one and it still doesn't work:
Router::connect('/:parent/:category/:page',
array('controller' => 'posts', 'action' => 'viewCategory'),
array('parent' => '[a-z0-9-]+',
'category' => '[a-z0-9-]+',
'page' => '[0-9]+'));
For reference, my pagination options set in my view are as so:
<?php $this->Paginator->options(
array('url' =>
array('controller' => 'posts', 'action' => 'viewCategory')
)); ?>
What am I doing wrong here?
You are setting the url yourself
This is your paginator options call:
<?php
$this->Paginator->options(array(
'url' => array(
'controller' => 'posts',
'action' => 'viewCategory'
)
));
?>
Where you are overriding the current url - and explicitly requesting that the paginator uses the the '/posts/viewCategory' url (with no arguments) as it's base url.
Just don't define the url
Simply don't call options and the helper will use the current url - that should mean that if the current url is:
/parent-category/sub-category
Then page 2 will be (assuming you are using the paramType option to use GET arguments rather than named parameters):
/parent-category/sub-category?page=2
If that's not the case there's information missing from the question; it's important to distinguish between "vanity routes not being used" and "the url is not equivalent (the current situation).
Just had a battle fixing something similar and came across this post. Though old, but I think my answer might save someone the time I had to spend fixing it.
Basically, what you need to do is call the Paginator->options() before Paginator->numbers(), thus:
$this->Paginator->options(
array(
'controller' => 'parent-category',
'action' => 'sub-category'
)
);
Though the controller and action do not exist, it just tricks CakePHP to use them "AS IS", since the reverse routing isn't working!
And for those (like me), who want have set up a route similar to
Router::connect(
'/go/page:id',
array(
'controller' => 'blog',
'action' => 'paginated'
)
);
There might be difficulty setting up the Paginator options. This, however, worked for me:
$this->Paginator->options(
array(
'controller' => 'go',
'action' => '/'
)
);
I guess you know why it worked ;)

CakePHP pages without controller in url

Is it possible to have pages route without the controller in the URL but still have other controllers work? Example:
Access pages like this: http://domain.com/about/
Instead of like this: http://domain.com/pages/about/
But still have access to http://domain.com/othercontroller/action/
Doing the following works for having the pages without /pages/ in the URL but if I try to access any other controller it doesn't work:
From: Router::connect('/pages/*', array('controller' => 'pages', 'action' => 'display'));
To: Router::connect('/', array('controller' => 'pages', 'action' => 'display', 'index'));
Is there a way to setup the Router so that it runs controller/action if it exists. If it does not it runs the pages controller/action?
I think the short answer is, no - it's not possible in the manner you're hoping*. Routing isn't really "logic" driven, so unless you can come up with a way to match the things you want in both respects you can't do "if controller exists, then _, else _" kind of thing.
*You could, however add each "page" as a row in your routes file. That would allow "about", "contact" ...etc to be accessed directly, while things that don't exactly match them are handled by the remaining routes.
I know I'm late, but here's my tip for someone looking for this.
In routes.php
foreach(scandir('../View/Pages') as $path){
if(pathinfo($path, PATHINFO_EXTENSION) == "ctp"){
$name = pathinfo($path, PATHINFO_FILENAME);
Router::connect('/'.$name, array('controller' => 'pages', 'action' => 'display', $name));
}
}
This will create a route for every ctp file in the View/Pages folder.
I actually solved this the opposite way from Dave's answer above, by adding a route for each controller, rather than each page. (I won't be adding new controllers very often, but I will be adding new content on a regular basis.)
// define an array of all controllers that I want to be able to view the index page of
$indexControllers = array('posts','events','users');
//create a route for each controller's index view
foreach ($indexControllers as $controller) {
Router::connect(
'/' . $controller,
array(
'controller' => $controller,
'action' => 'index'
)
);
}
//create a route to remove 'view' from all page URLs
Router::connect(
'/:title',
array(
'controller' => 'contents',
'action' => 'view'
),
array(
'pass' => array('title'),
'title' => '[a-z0-9_\-]*'
)
);

Zend Url View Helper not working with Regex Routes

I'm using Zend Framework 1.12 and have this route:
$router->addRoute('item_start',
new Zend_Controller_Router_Route_Regex(
'(foo|bar|baz)',
array(
'module' => 'default',
'controller' => 'item',
'action' => 'start'
),
array(
1 => 'area'
),
'%s'
)
);
Problem is, when I call '/foo' and use the Url Helper in the View, it doesn't give me any parameters:
$this->url(array("page"=>1));
// returns '/foo' (expected '/foo/page/1')
$this->url(array("page"=>1), "item_start", true);
// also returns '/foo'
Any idea how to get the page-parameter into the URL? I can't use the wildcard like in the standard route, can't I?
In addition to David's suggestions, you could change this route to use the standard route class, and then keep the wildcard option:
$router->addRoute('item_start',
new Zend_Controller_Router_Route(
':area/*',
array(
'module' => 'default',
'controller' => 'item',
'action' => 'start'
),
array(
'area' => '(foo|bar|baz)'
)
)
);
// in your view:
echo $this->url(array('area' => 'foo', 'page' => 1), 'item_start');
Your Regex route doesn't have a page parameter, so when the url view-helper ends up calling Route::assemble() with the parameters you feed it, it ignores your page value.
The two choices that come to mind are:
Modify your regex to include a (probably optional with default value) page parameter
Manage the page parameter outside of your route in the query string.

CakePHP - How to do reverse routing with slug?

I am using CakePHP 1.3. I have a Product model. on the DB table among others there are id and slug fields.
If I have a product that is id:37 and slug:My-Product-Title I want the URL for the product to be:
products/37/My-Product-Title
Instead of the standard:
products/view/37
I created a route that looks like this:
Router::connect(
'/products/:id/:slug',
array('controller' => 'products', 'action' => 'view'),
array('pass' => array('id'), 'id' => '[0-9]+')
);
Now I can go to http://server/products/37/My-Product-Title and it takes me to the right place.
But How do I get reverse routing to automatically build the correct URL in $HtmlHelper->link?
When I use:
echo $html->link(
'Product 37',
array('controller'=>'products', 'action' => 'view', 37)
);
It still outputs the standard products/view/37 url.
I don't believe that it's possible to be done auto-magically. The helper is just an "helper" who builds the link from the given parameters.
So the easiest method is to add another parameter in your link like so:
echo $html->link(
'Product 37',
array('controller'=>'products', 'action' => 'view', 37, $slug)
);
where the $slug is the data from the slug field.
Probably it could be done your idea, but you need to break the MVC pattern very badly :)
Edit:
Reading your question again I understood it well. See how should be done:
in your router.php add the following rule:
Router::connect(
'/product/*',
array('controller' => 'products', 'action' => 'view')
);
Please note that it's /product/* rather than /products/*
Your link should be done like this:
echo $html->link(
'Product 37',
array('controller'=>'products', 'action' => 'view', 37, 'my-product-title')
);
and the link would look like:
http://yourdomain.com/product/37/my-product-title
For me doing your suggestion is bad practice. Also I don't think it's good from SEO point of view redirecting always the user.
For routing:
Router::connect(
'/products/:id/:slug',
array('controller' => 'products', 'action' => 'view'),
array('pass' => array('id'), 'id' => '[0-9]+')
);
Your links should look like this:
echo $html->link(
'Product 37',
array('controller'=>'products', 'action' => 'view', 'id' => 37, 'slug' => 'my-product-title')
);
You have to add additional (key => value) to your array for each :param in your routing. Then magic will work
You should look at the following post regarding custom route classes.
The slug data doesn't need to be involved with the database at all - the field is a fake field used to simplify logic and lookups. This solution allows you to reverse route slugs, without needing a slug field in the models table.
http://42pixels.com/blog/slugs-ugly-bugs-pretty-urls
I am not sure how bad this is but with the following code in the ProductsController:
function view($id)
{
if( isset($_SERVER) && stristr($_SERVER["REQUEST_URI"],'view/') )
{
$this->Product->id = $id;
$slug = $this->Product->field('slug');
$this->redirect($id.'/'.$slug);
}
$data = $this->Product->find('first', array('conditions' => array('Product.id' => $id)));
$this->set("data", $data);
}
If the page is accesses via /view/id it automatically redirects them to the current page using /id/slug
Now I can just use the default link scheme:
echo $html->link(
'Product 37',
array('controller'=>'products', 'action' => 'view', 37)
);
and they will be redirected to the right URL.
Only problem is I am not sure how bad it is to have a redirect happening every time a user visits a product page?

key value routing in Zend Framework Route

I'm using a Hostname route to capture a subdomain and use as a category. I then chain a Router route for the controller, action and key/value pairs.
$hostnameRoute = new Zend_Controller_Router_Route_Hostname(
':customer.ddc.:domain',
array(
'customer' => ':customer'
)
);
$routerRoute = new Zend_Controller_Router_Route(
':controller/:action/*',
array(
'controller' => 'index',
'action' => 'index'
)
);
$chainedRoute = $hostnameRoute->chain($routerRoute);
$frontController->getRouter()->addRoute('default',$chainedRoute);
I can capture everything except the key/value pairs on the URI. Adding them causes the Params object in the Request to not get populated.
This works: http://category.mydomain.com/controller/action/
This does not: http://category.mydomain.com/controller/action/username/frank
Thanks for any suggestions.
Try to use without /*.
$routerRoute = new Zend_Controller_Router_Route(
':controller/:action',
array(
'controller' => 'index',
'action' => 'index'
)
);
as in 12.5.2. Using a Router is described.
The suggested patch didn't work for me. I adapted another patch found elsewhere on the ZF website and it seems to work well: http://pastie.org/1815135
There is indeed a bug which prevents wildcard matching when chaining routes. The comments in the bug description were very helpful in solving this issue with just a few lines of code change.
framework.zend.com/issues/browse/ZF-6654

Categories