One way is to use .htaccess
or equivalent tools to redirect from server (apache is not the only webserver) and force a redirect. It's already covered in other answers. But there is a different approach to. One that actually would utilize MVC: do not redirect at all.
Brief background on MVC design pattern
In correctly implemented MVC, view instances would contain all the UI logic. They would acquire data from model layer (the "how" constitutes most of the difference between Model2, MVP and MVVM), decide from which templates to assemble the response or even if the response need anything more then an HTTP location header.
The difference between mobile and desktop version would be contained to the view instances, assisted by controllers, which in correct MVC structure would only change the state of model layer and current view. What changes it makes should depend on user input.
Setting it all up
The following code would be part of bootstrap.php
or init.php
:
// the request instance acts like abstraction for all the user input
$request = new Request;
$request->setUri();
// instantiate the routing mechanism
$router = new Router( new RouteBuilder );
$router->import('/path/to/config.file');
// apply rules from router so that request instance now
// contains the parsed values from URI
$router->route( $request );
// handling of model layer
$serviceFactory = new ServiceFactory;
// since in MVC the controllers are closely tied to views
// (1 controller for 1 view), usually it is convenient to use same class names
$resource = $request->getParameter('resource');
// instantiation of view and controller
$class = '\\View\\' . $resource;
$view = new {$class}( $serviceFactory );
$class = '\\Controller\\' . $resource;
$controller = new {$class}( $serviceFactory, $view);
// i find it convenient to have controller's action be made from
// both REQUEST_METHOD and command name
$action = $request->getMethod() . $request->getParameter('command');
// run it all
$controller->{$action}( $request );
echo $view->render();
In this way, when execution hits the controller's action, it is provided with a fully prepared instance of Request
. Said instance is what determines the details about user's equipment and provides a simple interface for reading these details.
The controller also has access to the model layer and current view, both of which are injected in it through the constructor.
Deciding what to show.
The most straight-forward way is the let the controller alter the state of current view.
namespace Conroller;
class SomeThing
{
public function getUserDetails( $request )
{
if ( $request->isFromMobile() )
{
$this->view->adjustFor( $request->getDeviceType() );
}
$community = $this->serviceFactory->create('Community');
$community->loadUser( $request->getParameter('id'));
}
}
The adjustFor()
method in this case informs the current view instance, that it will need use the templates, that are meant for some non-default device.
There is one very important downside for this approach: it violates OCP from SOLID principles (for lazy people: the short version), because you would have to rewrite each controller method, if you decided to add mobile version for an existing project.
.. there is a better way
While the following code is relatively easy to understand, it is a bit flawed:
$resource = $request->getParameter('resource');
// instantiation of view and controller
$class = '\\View\\' . $resource;
$view = new {$class}( $serviceFactory );
It starts to break down even when the you only have to provide both HTML and JSON/XML response. The view starts to accumulate same repeating IF
s all over the code. That is a clear sign that you should have used polymorphism, and these lines would be where to do it.
Instead of the above shown code, you could use something like:
$resource = $request->getParameter('resource');
$class = '\\View\\' . $request->getDeviceType . $resource;
$view = new {$class}( $serviceFactory );
Now, when you are having mobile/desktop application you have two classes: \View\DekstopSomething
and \View\MobileSomething
. They each can have separate logic and request completely different data from model layer.
In the meanwhile, the rest of your code is completely decoupled from the output form.
What are the benefits ?
Few reasons why, instead of using server redirects, you should better choose this approach:
Your application becomes independent from server software
Not everywhere you will have Apache (high-load sites often use Nginx or Lighttpd instead) and even if you have Apache, your ability to use mod_rewrite would depend on server's configuration.
Unified scheme for all the links in your site
The link for viewing some news item is always the same, no matter on what device you use it. It makes fro much easier sharing and bookmarking of URLs.
Single point of change
This approach lets you initially make the site for desktop users and then add the mobile/tablet support without rewriting any of the existing code.
You might also be interested in reading two older post on the subject about implementation of model layer and access control in context of MVC.