Are PHP MVC Controllers implemented by url rewrite? - php

The controller in a Java EE
application may be represented by a
servlet, which may be currently
implemented using JavaServer Faces
(JSF).
But in PHP there is no such servlet,so I guess is it implemented by url rewrite?
So that every request is directed to that controller?

It can be done with mod_rewrite but mostly in php there is a front-controller mechanisim which does all controlling through a single file. In this way, all controllers are specified in the url. See this for more explanation about controllers and mvc in php.

I think that's called the Front Controller pattern http://en.wikipedia.org/wiki/Front_controller and usually is achieved via mod_rewrite rules that any requests for phisically nonexisting files is redirected to index.php which then decides what to do.

MVC in PHP typically makes use of a front controller, which serves as the only entry point into the application.
This is usually implemented by using mod_rewrite to point all requests to a php file containing your bootstrap code.
This bootstrap code will contain your front controller.
The front controller takes it from there, redirecting the request based on the input parameters to the appropriate controller. Your target controller is usually specified as one of the parameters.
So, when you hit:
http://yourdomain.com/blog/new
The application would redirect the request to your bootstrap code with your front controller, which will interpret this input to mean 'blog' is the requested controller, 'new' is the action. It would then instantiate the 'blog' controller, pass it the 'new' action, and the rest is standard MVC.

As most of the other answers have shown, usually mod_rewrite is the way to do it. But, if you don't want to use mod_rewrite, you can let your bootstrap file actually configure variables from the URL itself.
I use a couple of my own functions which creates an array from a URL, so:
site.com/page/welcome/param1/param2
becomes
$url[0] = 'page'
$url[1] = 'welcome'
$url[2] = 'param1'
$url[3] = 'param2'
and then I can pass the $url array to my Router and it decides which parts of the Controller/Action/Param call each element belongs to.
The same URL request shown above creates the Controller/Action/Param call:
// http request for site.com/page/welcome/param1/param2
$controller = new Page_Controller('param1', 'param2');
$controller->welcomeAction();
while, depending on the settings in my Router object, I can create subdirectories, such as for calls to 'admin/':
// http request for site.com/admin/page/welcome/param1/param2
$controller = new Admin_Page_Controller('param1', 'param2');
$controller->welcomeAction();
With url_rewrite I think it would be harder (still possible though) to add those reroutes in, and with my method (Some frameworks might also do it, not too sure) it allows you to customize it more, ie you can edit the $url array if needed before passing it to the Router object.
I'm not sure what the negatives are in using this method, but it works pretty well for me!

You would use mod_rewrite to redirect everything to the index.php file. So you use mod_rewrite if you want this:
http://example.com/page/welcome
and not
http://example.com/index.php?page/welcome
or
http://example.com/index.php?controller=page&action=welcome

Related

Make title string the entire URI for all pages using CodeIgniter

With CodeIgniter I'm trying to create a URL structure that uses a title string as the entire URI; so for example: www.example.com/this-is-a-title-string
I'm pretty confident I need to use the url_title() function in the URL Helper along with the routes.php config folder but I'm stuck bringing it all together.
Where do I define the URI and how is it caught by the routes folder?
Seems to be a straight forward problem but I'm getting stuck creating the URLs end-to-end. What am I missing?
I thought about a catch-all in the routes folder: $route['(.*)'] = "welcome/controller/$1"; ....but how would this work with multiple functions inside a particular controller? ...and maybe it's not even the right way to solve.
You can send all requests to a driver with something like this:
$route['(:any)'] = "welcome/function";
Then use the _remap function to route requests inside the controller.
However, using URL's as you suggest limits the CI functionality. Try something better like www.example.com/article/this-is-a-title-string
$route['article/(:any)'] = "articles/index";
and in article (controller), use _remap...
If you're going to re-route every request, you should extend CI_Router.
The actual implementation depends on what you're doing. If you customize CI_Router, you can do it AFTER the code that checks routes.php, so that you can keep routes.php available for future customization.
If the URI contains the controller, function, and parameters, you can parse it within your extended CI_Router and then continue with the request like normal.
If the URI is arbitrary, then you'll need something (file, db, etc) that maps the URI to the correct controller/function/parameters. Using blog posts as an example, you can search for the URI (aka post-slug in WordPress) in the db and grab the corresponding record. Then forward the request to something like "articles/view/ID".

How do extended urls work

I know how these kind of URLs load the page ... based on their GET parameter.
http://www.bedupako.com/songs.php?page=show_song_details.php&songid=1167&n=0&back=no
and in the back-end roughly something like this:
<?php
switch($_GET['page']) {
case 'xx': include('my page');break;
.
.
.
default: include('default');break;
}
?>
But how do these kinds of URLs work? I mean, how is the data loaded dynamically?
www.dummysite.com/parm/subpage1/xyz
www.dummysite.com/parm/subpage2/xyz
How are these parsed similar to the GET param like websites?
In most cases this will be handled by the web server on-the-fly according to a set of rules. The specifics of it will vary from server to server and on a case-by-case basis. In Apache it is usually done using the mod_rewrite extension.
You can use mod_rewrite by itself as others have suggested, but most sites do not do this because its not very flexible, and can be annoying to maintain if you have more than a couple of these "pretty" URLS.
Instead they set up a basic rewrite rule to forward everything to a single index.php and then on the application side they parse the URI based on defined patterns - these are called "routes". Route parsing usually happens in some kind of routing class which process the defined routes and compares them to the URI, and then when it finds a match parses out the parameters for the matched route.
These all provide good examples of a router, but they are hard to understand without the other interacting classes:
Zend: Zend_Controller_Router_Rewrite
Symfony: sfPatternRouting
Cake: Router
CodeIgniter: CI_Router
You should look at http://httpd.apache.org/docs/2.0/misc/rewriteguide.html url rewriting if you're with apache (most likely)

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 application with login and signup pages on one domain and other pages on the subdomain

We develop a zend framework application and want that signup pages and login pages were on our domain for example http://domain.com (now all pages are on http://domain.com) and other pages (where you have to be redirected after authentification) on subdomain: http://subdomain.domain.com.
Could you please tell how to solve it?
Thank you for any ideas.
I've done this kind of thing in a major ZF app of mine. It's a complicated 3-part question, but hopefully this will get you started in the right direction.
First is the session cookie. You'll need to use a wildcard domain parameter when you set the session cookie. In your Bootstrap or somewhere prior to when you would normally start your session, include a line such as:
Zend_Session::start(array('cookie_domain' => '.domain.com'));
Note the dot (".") prior to "domain.com". This makes the cookie applicable for domain.com as well as all subdomains under it.
Second is the URL's throughout your site. You can use the Redirector action helper's gotoUrl() method. At the end of an action method when you want to redirect the user, use a line like this:
$this->_redirector->gotoUrl('http://domain.com/somewhere/else');
Of course, you may want to assemble the URL string by other means such as storing the domain in a configuration parameter and concatenating the path using one of ZF's native methods of generating a URL path. See the documentation for Zend_Controller_Action_Helper_Redirector for more. You'll also need to be careful about all URL's on your site and make sure the right domain is included in each link.
Third is how your app interprets routes when subdomains are involved. There are a few ways to accomplish this, but one is to create a module within your app that corresponds to each subdomain you want to use. Then use a Controller Plugin to intercept ZF's normal routing mechanism and set the module name appropriately based on the subdomain. Something like:
class My_Controller_Plugin_RouteMySubdomains extends Zend_Controller_Plugin_Abstract {
public function routeShutdown(Zend_Controller_Request_Abstract $request) {
$hostname = $request->getHttpHost();
if (strlen($hostname) > strlen('domain.com')) {
$moduleName = preg_replace("/\.domain\.com$/", '', $hostname);
$request->setModuleName($moduleName);
}
}
}
You'll need to tell ZF to use this plugin. If you're using Zend_Application with an application.ini file for basic configuration, you'll need to add a line like this:
resources.frontController.plugins.routeMySubdomains = "My_Controller_Plugin_RouteMySubdomains"
Good luck!

Understing URL routing in MVC

I am trying to create a very basic MVC framework to better understand the pattern.
I am having trouble understanding the URL routing part.
So far i've understood that the url carries 3 basic pieces of information in this format:
www.site.com/controller/method/querystring
So given the following URL:
www.site.com/user/delete/john
'user' is the controller
'delete' is the method of said controller
'john' is the query string
In my framework, i have it so if a controller is not specified in the URL, it defaults to 'index'.
If a method if not specified in the URL, it defaults to 'show'(which just outputs the html).
this way i can go to www.site.com and since it doesn't have a controller or method in the url, the
controller becomes 'index' and method 'show', thus just loading the index view.
But what if i don't want to provide a method in the url, but just www.site.com/controller/querystring
like so:
www.site.com/user/john
This would ideally load the profile for John.
But, the framework thinks 'john' in the url is the method to invoke, and not the query string.
What is the standard, a practical way to distinguish between the two?
ps:
I have this in my .htaccess
RewriteRule ^(.*)$ index.php?$1 [L,QSA]
echoing $_SERVER['QUERY_STRING'] in to http://site/profile/john gives 'profile/john'/
My controllers usually locate a handler method searching from more to less specific. If a method is found, it's called with the "tail" of parameters passed to it. For example, if user/delete/john is given, it attempts to call, in order:
action_user_delete_john()
action_user_delete('john')
action_user('delete/john')
generic_fallback_method('user/delete/john')
In your case, i'd define a set of user_<operation> methods (action_user_delete, action_user_edit etc) and a default action_user method which will be called when no operation param is provided and should handle urls like user/john
I find this technique quite flexible and powerful, but there's no standard, and you're free to invent your own.

Categories