ZEND - Conflicting route patterns - php

I'm using Zend framework 1.12, trying to come up with custom routes.
I'm trying to create something that looks like facebook's profile URL (http://facebook.com/username). So, at first I tried something like that:
$router->addRoute(
'eventName',
new Zend_Controller_Router_Route(
'/:eventName',
array(
'module' => 'default',
'controller' => 'event',
'action' => 'detail'
)
)
);
I kept getting the following error anytime I tried running mydomain.com/something:
Fatal error: Uncaught exception 'Zend_Controller_Router_Exception'
with message 'eventName is not specified' in
/var/desenvolvimento/padroes/zf/ZendFramework-1.12.0/library/Zend/Controller/Plugin/Broker.php
on line 336
Not only I was unable to make that piece of code work, all my default routes were (obviously) overwritten. So I have, for example, stuff like "mydomain.com/admin" that should send me to the "admin" module, on the Index controller, but was now returning the same error (as it fell in the same pattern as /:eventName).
What I need to do is to create this custom route, without overwriting the default ones and actually working (dûh).
I have already checked the online docs and a lot (A LOT) of stuff on google, but I didn't find anything related to the error I'm getting or how to not overwrite the default routes. I'd appreciate anything that could point me the right direction.
Thanks.
EDIT¹:
I managed to get it working, but I didn't use any routing at all. I just made a plugin with the following:
public function preDispatch(\Zend_Controller_Request_Abstract $request) {
if (!\Zend_Controller_Front::getInstance()->getDispatcher()->isDispatchable($request)) {
$request->setModuleName($this->_eventRouter["module"]);
$request->setControllerName($this->_eventRouter["controller"]);
$request->setActionName($this->_eventRouter["action"]);
}
}
It feels like an ugly workaround, though... As Tim Fountain pointed out, my events are dynamic (I load them from a database), so I can't hardcode it. Also, my current implementation prevents me from having to hardcode every module/controller/action combination.
I'd just like to know if there's a way to avoid using a plugin.
EDIT²: I'm not doing that crappy plugin thing anymore. I figured out what was causing the router error. My routing definition did not have a valid default value for variable 'eventName'. My fix was:
$router->addRoute(
'eventName',
new Zend_Controller_Router_Route(
'/:eventName',
array(
'module' => 'default',
'controller' => 'event',
'action' => 'detail',
'eventName' => ''
)
)
);
I am still unable to create routes with "conflicting" patterns, such as /admin and /:eventName. If only there was a way to make /admin override /:eventName...

Routes are applied/matched on a LIFO basis. As the routing docs note:
Note: Reverse Matching
Routes are matched in reverse order so make sure your most generic routes are defined first.
So, in order to have your "static" routes (static, in the sense that they do not pull from the db, /admin and the like) apply over your dynamic ones (/:eventName), make sure you define the static ones later in the execution flow.
In practical terms, this means that you cannot define your static routes during bootstrap, so you'll have to do it in a plugin with a routeStartup hook. Perhaps, two plugins: one for your dynamic routes, then another for the static ones, just make sure that the priority on the plugins is set so that the static ones are added later.

The error you are getting is probably coming from a URL helper call you have in your template. You need to specify the eventName param to this since you've made it required, e.g.:
Something
The answer to your other question depends a bit on whether you have a static, unchanging list of events or non-event URLs. You need to give the router a way to determine whether /foo is an event, or a controller. You do this by either hardcoding the possible events in to your event route, hardcoding routes for your other non-event URLs, or (if your events are dynamic and based on some database content) writing a custom route class for your event route which can do a lookup to see whether a given string is an event.

Since you are using Zend Framework 1.x
Here is the solution which I have added here : How to redirect Error Page and perform Routes in Zend Framework 1.x
Also, to make life easier... here it is:
I am still unable to create routes with "conflicting" patterns, such as /admin and /:eventName. If only there was a way to make /admin override /:eventName...
Once you are on the action which calls your eventName, you can put a check if that == admin, later you can define a re-route by specifying which action needs to be loaded, in that condition itself.
Simple? :)

define the eventName, and even if it's not required, just leave it blank.

Related

cakephp 3 prefix routing

I'm trying to set up a routing prefix in cakephp 3 so any URLs starting with /json/ get the prefix key set and I can change the layout accordingly in the app controller. Other than that, they should use the usual controller and action. I have added the following to routes.php
$routes->prefix('json', function($routes) {
$routes->connect(
'/:controller/:action/*',
[],
['routeClass' => 'InflectedRoute']
);
});
I want to direct all requests with json as first url segment to controller specified in second url segment. e.g. /json/users/add_account_type/ goes to users controller. However when accessing this URL I get the message:
Error: Create the class UsersController below in file:
src/Controller/Json/UsersController.php
whereas I want it to be using
src/Controller/UsersController.php
I think this should be possible but I can't quite see what I'm doing wrong when consulting the book. Have partly based my code on: CakePHP3.x controller name in url when using prefix routing
Thanks a lot in advance
That's simply how prefix routing now works in 3.x, as explained in the docs, prefixes are being mapped to subnamespaces, and thus to separate controllers in subfolders.
http://book.cakephp.org/3.0/en/development/routing.html#prefix-routing
If you'd wanted to change that behavior (I don't really see why), one way would be to implement a custom ControllerFactory dispatcher filter.
http://book.cakephp.org/3.0/en/development/dispatch-filters.html
On a side note, the RequestHandler component supports layout/template switching out of the box, so maybe you should give that a try.
http://book.cakephp.org/3.0/en/controllers/components/request-handling.html
http://book.cakephp.org/3.0/en/views/json-and-xml-views.html
Prefix routing is a way of namespacing parts of your routes to a dedicated controller. It seem that what you want is a scope and not a prefix, for what you describe:
Router::scope('/json', function($routes) {
$routes->fallbacks('InfledtedRoute')
});

Cakephp reverse routing : prevent fallback

In cakephp (branch 2.5), when trying to build an url from an array, cakephp will make up one if it does not find a matching one in Config/routes.php.
Maybe an example will be more useful :)
When I do this :
echo Router::url(array(
'controller' => 'some_non_existing_controller',
'action' => 'some_non_existing_action',
'fake_named_param' => 'blahblah'
));
I get that :
/some_non_existing_controller/some_non_existing_action/fake_named_param:blahblah
What I would like to get is an exception telling me "hey, this route does not exist". This would help me debugging my work, and let me know immediately when I break links when changing things in Config/routes.php.
When digging into cakephp core code, i found the responsible for this behaviour. It is located exactly here => http://api.cakephp.org/2.5/source-class-Router.html#921-921
But since I don't want to mess with core code, i'd like to know if anybody had an idea of how to do this properly?
Thanks !
Just delete this line from your routes.php.
require CAKE . 'Config' . DS . 'routes.php';
Now only explicitly connected routes will work.
As suggested Deimoks, I had a look at the custom Route class. First I didn't think it could resolve my problem because in cakephp custom Route class aims at defining how to parse an url to a routing array or how to convert a routing array to an url, for a given route. Yet my problem is precisely how cakephp handles reverse routing when there is no matching route.
So the idea was to create a new route at the end of Config/routes.php whose goal is only to catch reverse routing attempts that were not resolved before. If this route is solicited for reverse-routing it means something is wrong with the routing array because none of the other routes found an url for it.
This route is then handled by a custom route class that will log the reverse routing failure.
At the end of Config/routes.php :
App::uses('GarbageRoute', 'Routing/Route');
Router::connect('/', array(), array('routeClass' => 'GarbageRoute'));
In /Routing/Route/GarbageRoute.php :
<?php
class GarbageRoute extends CakeRoute {
public function match($url)
{
trigger_error(print_r($url, true) . 'does not match any url', E_USER_NOTICE);
return false;
}
}
I'm still surprised cakephp does not support it natively and that I had to create custom classes to get this behavior. If anybody has a better solution, feel free to share!

Route with name "HelloWorld" not found Zend Framework 2

I have created a new module in ZF2 named 'HelloWorld'. What I am trying to do is, simply printing HelloWorld when I click on the link 'HelloWorld':
I want to generate this link(http://mayukh.my.phpcloud.com/zf2test/HelloWorld/) by using this:
$this->url('HelloWorld', array('action' => 'index'))
But it is showing the error like this:
http://mayukh.my.phpcloud.com/zf2test/
Please suggest how to avoid this error..
This is perhaps related to one of ZF2’s “features.” It seems that if you use ZF2 functions to construct your links, the function will drop out any segment that matches the default value you have named in your router script. See How to write the ZF2 router script to allow parameters on the default action.
Temporarily change or remove the defaults from your router script and see if that doesn’t solve your issue. If it does, you might have to either reconsider the scheme for your router scripts or code your links without ZF2’s url function.

CakePHP (2.0) Dynamic URLs

I'm currently looking into CakePHP 2.0 and wanting to convert old 1.3 projects to 2.0. I'm going to start from scratch because there's a whole lot of code in the projects that could be a lot better.
One of those things is the dynamic URLs, the projects multilingual and even the URLs change to the chosen language. Eg:
English: /pages/new-article
Dutch: /paginas/nieuw-artikel
Both would go to PagesController::display();
Note: the URLs can be way longer, pages can have subpages and those will be added to the URL too. Eg: /pages/new-article/article-subpage
Now, the way I did it before is to have a route for everything going to a specific action. Like * going to PagesController::index();
However this seems to slow the apps down and it brings a lot of problems along with it.
So my question to you is, is there a simpler way to do this?
I do not want to hardcode anything, I should be able to change /pages/article to /page/article without needing to change the code.
Note: If you know a way to do it in 1.2 or 1.3, that would also be great, 2.0 isn't that different.
Well i figured it out, apparently CakePHP 1.3 and 2.0 allow you to create custom route classes. It's in the documentation here: http://book.cakephp.org/2.0/en/development/routing.html?highlight=route#custom-route-classes
So basically what you need to do is create a file APP/Lib/Routing/Route/UrlRoute.php with the following contents:
class UrlRoute extends CakeRoute{
public function parse($url){
$params = parent::parse($url);
# Here you get the controller and action from a database.
// tmp
$params['controller'] = 'pages';
$params['action'] = 'index';
return $params;
}
}
And in your APP/Config/routes.php you put the following:
App::import('Lib', 'Routing/Route/UrlRoute');
Router::connect('/*', array('controller' => 'tests', 'action' => 'index'), array('routeClass' => 'UrlRoute'));
I think the real challenge is getting the arguments that usually get passed to the functions back to work. func_get_args() now returns everything behind the domain name. And retrieving the URL from the database if you're using extra params. Might have to cache each URL.

Create very simple Named Route in Zend Framework, using its MVC

I've just put together a very basic site using the Zend Framework and its MVC. (Actually, I'm not even using models at the moment, it's all just Controllers/Views for static info so far).
When I started toying with the Forms I realized that in the examples for Zend_Form they use something like this this set the form's action:
$form->setAction('/user/login')
Which contains the URL. I understand that Zend Framework has Routes and that they can be named, but I can't seem to grasp from the manual how to create a simple route for certain Controller/Actions so that I could do something like this:
$form->setAction($named_route)
// or
$form->setAction('named_route')
I hope my question is clear. I wasn't able to locate any duplicate questions, but if you spot one and point it out I won't mind.
Links to resources are as good as examples, so don't waste your time if you know of a decent blog post somewhere. Thanks!
References:
http://framework.zend.com/manual/en/zend.controller.router.html#zend.controller.router.routes.standard - Look for "12.5.7.1. Zend_Controller_Router_Route" for a clearer explanation.
This is not the best way to do it, but I have a working example. I welcome corrections.
After seeing Shorten Zend Framework Route Definitions, I agree that named Routes should go in their own config (I use Django, and named Views/URLs are generally separated) - but here I'm just going to define Routes in my Bootstrap.
So, in Bootstrap.php, inside the Bootstrap Class of course, I've created an function that will be automatically run, like so:
public function _initRoutes()
{
$frontController = Zend_Controller_Front::getInstance();
$route = new Zend_Controller_Router_Route(
'login/', // The URL, after the baseUrl, with no params.
array(
'controller' => 'login', // The controller to point to.
'action' => 'index' // The action to point to, in said Controller.
)
);
$frontController->getRouter()->addRoute('loginpage', $route);
}
In the above example, "loginpage" will be the Name of the "Named Route".
So, inside my LoginController, (in a function that builds the form) instead of doing
$form->setAction('/blah/login')
I retrieve the URL of the named Route and pass that in, like so:
$form_action_url = $this->view->Url(array(), 'loginpage', true);
// -- SNIP --
$form->setAction($form_action_url) // ...
This may be pointless and wrong, but it seems to work at the moment.
My reason for wanting a named URL, when Zend Framework handles URLs as /Controller/View(Action)/ automatically is because I'm anal about that kind of thing. I've been using Django for awhile, where the URLs are predefined, and I like it that way.
The Zend Framework MVC urls working out of the box is nice, tho.
Feel free to add notes and corrections to how this should work!

Categories