Ответ 1
Один из способов - использовать
.htaccess
или эквивалентные инструменты для перенаправления с сервера (apache - не единственный веб-сервер) и принудительное перенаправление. Он уже рассмотрен в других ответах. Но есть и другой подход. Тот, который на самом деле будет использовать MVC: не перенаправляет вообще.
Краткий справочник по шаблону проектирования MVC
В правильно реализованном MVC экземпляры представлений будут содержать всю логику пользовательского интерфейса. Они будут получать данные с уровня модели ( "как" составляет большую часть разницы между Model2, MVP и MVVM), решить, из каких шаблонов собирать ответ или даже если для ответа требуется нечто большее, чем заголовок местоположения HTTP.
Разница между мобильной и настольной версиями будет содержаться в экземплярах представления, с помощью контроллеров, которые в правильной структуре MVC будут только изменять состояние уровня модели и текущего представления. Изменения в нем должны зависеть от ввода пользователем.
Установка всех настроек
Следующий код будет частью bootstrap.php
или 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 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();
Таким образом, когда выполнение попадает в действие контроллера, оно снабжается полностью подготовленным экземпляром Request
. Указанный пример определяет детали пользовательского оборудования и предоставляет простой интерфейс для чтения этих деталей.
Контроллер также имеет доступ к слою модели и текущему представлению, оба из которых вводятся в него через конструктор.
Решение о том, что показывать.
Самый простой способ - позволить контроллеру изменить состояние текущего вида.
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'));
}
}
Метод adjustFor()
в этом случае информирует текущий экземпляр представления, что ему понадобятся шаблоны, предназначенные для некоторых нестандартных устройств.
Существует один очень важный недостаток для этого подхода: он нарушает OCP из принципов SOLID (для ленивых людей: короткая версия), потому что вам придется переписать каждый метод контроллера, если вы решили добавить мобильную версию для существующего проекта.
.. есть лучший способ
В то время как следующий код относительно легко понять, он немного испорчен:
$resource = $request->getParameter('resource');
// instantiation of view and controller
$class = '\\View\\' . $resource;
$view = new {$class}( $serviceFactory );
Он начинает разрушаться, даже когда вам нужно предоставить как ответ HTML, так и JSON/XML. Представление начинает накапливать все повторяющиеся IF
по всему коду. Это явный признак того, что вы должны были использовать полиморфизм, и эти строки были бы , где, чтобы сделать это.
Вместо приведенного выше кода вы можете использовать что-то вроде:
$resource = $request->getParameter('resource');
$class = '\\View\\' . $request->getDeviceType . $resource;
$view = new {$class}( $serviceFactory );
Теперь, когда у вас есть мобильное/настольное приложение, у вас есть два класса: \View\DekstopSomething
и \View\MobileSomething
. Каждый из них может иметь отдельную логику и запрашивать совершенно разные данные из уровня модели.
В то же время остальная часть вашего кода полностью отделена от выходной формы.
Каковы преимущества?
Немного причин, почему вместо использования перенаправления серверов вам лучше выбрать такой подход:
-
Ваше приложение становится независимым от серверного программного обеспечения
Не везде вы будете иметь Apache (на сайтах с высокой нагрузкой часто используются Nginx или Lighttpd), и даже если у вас есть Apache, ваша способность использовать mod_rewrite будет зависеть от конфигурации сервера.
-
Единая схема для всех ссылок на вашем сайте
Ссылка на просмотр некоторых новостей всегда одинакова, независимо от того, какое устройство вы используете. Это упрощает совместное использование и закладки URL-адресов.
-
Единая точка изменения
Этот подход позволяет вам сначала сделать сайт для пользователей настольных компьютеров, а затем добавить поддержку мобильных/планшетов, не переписывая какой-либо существующий код.
Вам также может быть интересно прочитать две старшие статьи по теме о реализации уровня модели и контроль доступа в контексте MVC.