CakePHP (2.0) Dynamic URLs - php

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.

Related

create a dynamic url in codeigniter like facebook

I need to create a dynamic url in codeigniter like the facebook application. Is it possible to create such url using the codeigniter framework?
eg:
1. www.facebook.com/nisha
2. www.facebook.com/dev
You need to set up custom routing for the controller in application/config/routes.php. Like:
$route['([a-zA-Z]+)'] = "controller_name/function/$1";
This makes urls like the way you want, but it makes all of your controller inaccessible, that is because any '/controllername/parameter/' format will match with '(:any)' and will be redirected to our 'controller_name/function/'.
To stop controllers redirected by the CI router, you will have to explicitly define all of your controllers on the routes.php first then add the above mentioned routing rule at last line. Thats how i made it to work.
Hope that helps you in some way.
Its pretty easy to setup this by the use of routes. Read their routing guide
$route['([a-zA-Z]+)'] = "controller/user/$1";
However, if their is only one way of accessing the website, is like domain.com/username then its ok, otherwise, this will prove be a hard catch on the long run. On that case, limit the Route to a limited scope like
$route['users/([a-zA-Z]+)'] = "controller/user/$1";
This will help in the extending the system in numerous way
Try this way. it will reduce a lot of repetitive line if you have lots of controller but i don't know does it violate any CI rules.
//this code block should be placed after any kind of reserved routes config
$url_parts = explode('/',strtolower( $_SERVER['REQUEST_URI']) );
$reserved_routes = array("controller_1", "controller_2", "controller_3" );
if (!in_array($url_parts[1], $reserved_routes)) {
$route['([a-zA-Z0-9_-]+)'] = "controller_1/profile/$1";
}

Route random strings to a specific controller in CodeIgniter?

I am trying to create short links to my application in codeigniter but I've met a kind of a problem when designing my route. The problem is that I want a route which will take a string containing a-Z and numbers and redirect that to a controller called image with the string after. Like this: app.com/randomstring -> app.com/image/randomstring. But when I am trying to do this in the routes config file with a regular expression it disables my application and I am unable to enter "normal" urls with controllers that already exist.
How my route looks like right now (I know it's probably very wrongly made):
$route['(^[A-Za-z0-9]+$)'] = "image/$1";
Is there any easy way to redirect with that short url without using another fake controller first like this: app.com/i/randomstring -> app.com/image/randomstring
And could you maybe help me improve and tell me what part of my regexp is failing?
As I mentioned in the comments, without a clearly defined spec on what the image urls will be, there's no comprehensive way to solve this. Even YouTube (related to the library you linked to) uses urls like /watch?v=h8skj3, where "watch" is the trigger.
Using a i/r4nd0m$tring would make this a non-issue, and it's what I suggest, but I had another idea:
$route['(:any)'] = "image/$1";
// Re-Route all valid controllers
foreach (array('users', 'login', 'blog', 'signup') as $controller)
{
$route[$controller] = $controller;
$route[$controller.'/(:any)'] = $controller.'/$1';
}
unset($controller);
You might need the image route last, I'm not 100% sure. This should route everything to image/ except the controllers you define. You could even use glob() or something to scan your controller directory for PHP files to populate the array.
Another way to get one character shorter than i/string could be to use a character trigger, like example.com/*randomstring, but that's a little silly, i/ is much cleaner and obviously, easier to deploy.

MVC - No Controller in the URI?

Let's pretend I'm trying to learn CI, and as my test project I am building a group-buying site.
What I'd like is to have a different page for each city, e.g.:
http://www.groupon.com/las-vegas/
http://www.groupon.com/orlando/
I'd also like to have different pages such as:
http://www.groupon.com/learn
http://www.groupon.com/contact-us
If I am building this in CI and following the MVC ideology, how would this work? I'm having difficulty seeing how to accomplish the desired URL's with the concept of:
http://www.domain.com/controller/view/segment_a/segment_b/etc...
What I would do is create a custom 404 controller that acts as a catch-all for non-existent routes.
It would take the URI, possibly validate it, and re-route it to the (e.g.) "city" controller.
If the city controller can't find the city (whatever string was specified), then it needs to issue a proper 404. Otherwise, you're good to display your information for that city.
Also, once you create your custom 404 controller, you can send all 404 errors to it by specifying a route named '404_override'.
That's where URI Routing comes in. But in your case you'll probably will have to be carefull defining your routes as the first and only part of your route is a variable part already.
This really has nothing to do with MVC, and much more to do with good URL.
You're looking for URLs that are both (a) clear from the user's point of view and (b) that give hints to your application as to how it's meant to be handled.
What I'd do in this case is redesign your URLs slightly so that rather than:
http://www.groupon.com/las-vegas/
http://www.groupon.com/orlando/
You would have URLs that looks like this:
http://www.groupon.com/destinations/las-vegas/
http://www.groupon.com/destinations/orlando/
The bit at the beginning--/destinations/--can be used by your URL routing code to decide what controller should be dealing with it. If your routing code is URL-based, you might have an array like this:
$routes = array(
'/destinations/' => 'on_destination_list',
'/destinations/(.+)' => 'on_destination',
'/(.*)' => 'on_page');
// Basic URI routing code based off of REQUEST_URI
foreach ($pattern => $func) {
if (preg_match("`^$pattern$`", $_SERVER['REQUEST_URI'], $placeholders)) {
array_shift($placeholders);
call_user_func($func, $placeholders);
}
}
Keep in mind that I wrote that routing code off the top of my head and it may not be absolutely correct. It should give you the gist of what you need to do.
Doing things this way has the added benefit that if somebody goes to http://www.groupon.com/destinations/, you'll have the opportunity to show a list of destinations.

Zend framework facebook redirect URL to canvas application URL

I am currently developing a facebook canvas (iframe) based application. Is there any way to get Zend framework to output URLs like this:
http://app.facebook.com/appName/controller/action
intead of getting
http://www.domain.com/controller/action ?
It is not so important because due to iframe based app everything is working fine, but I'd like to provide better user experince and getting the url
http://app.facebook.com/appName/
is not user friendly at all. Probably the solution is very easy but I am completely "stack". The application is devided to modules so I can change sth in Boostrap.php which is probably to hold the solution underneath my nose but I can not see it..:-/
EDIT:
Maybe i did not expressed it as I should have. The problem is not within facebook. The problem is in zend itself. It outputs the original application (e.g. myapp.example.com) URL and I want it to output http://app.facebook.com/myapp
Thanks in advance.
Lukas
I'm not sure what your question is but Facebook already maps the URLs it receives to your application.
For example if your canvas URL is set to http://domain.com/ and a user goes into http://apps.facebook.com/appName/controller it will get mapped to http://domain.com/controller by Facebook.
It works this way for both canvas/fbml and iframe applications.
To make Zend Framework generate URLs with an alternate base (ie: http://apps.facebook.com/appName) you can do this in your bootstrap:
protected function _initBaseUrl() {
$front = $this->getResource('frontcontroller');
$front->setBaseUrl('http://apps.facebook.com/appName/');
}
If you are not using the bootstrap, you can get an instance of your front controller in an alternate way and do this:
$front = Zend_Controller_Front::getInstance();
$front->setBaseUrl('http://apps.facebook.com/appName/');
Finally, I managed to solve this issue. So for fellow developers I am posting here my solution.
The soulition is to be honest a bit complicated but:
Use Zend_Controller_Router_Route_Hostname
The example of usage can be found in http://framework.zend.com/manual/en/zend.controller.router.html the and then Chain it with classic route like:
$hostnameRoute = new
Zend_Controller_Router_Route_Hostname(
':username.users.example.com',
array(
'controller' => 'profile',
'action' => 'userinfo'
)
);
$plainPathRoute = new Zend_Controller_Router_Route_Static('');
$router->addRoute('user', $hostnameRoute->chain($plainPathRoute);

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