Правила перенаправления на субдомен

Кто определяет URL-адреса для перенаправления на мобильную версию?

Давайте возьмем твиттер в качестве примера:

  • https://twitter.com → перенаправить мобильные устройства
  • https://dev.twitter.com → не перенаправлять мобильные устройства

В приложении MVC, который будет отвечать за перенаправление правил?
Может быть все в www перенаправлено на мобильное устройство?

Ответ 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.

Ответ 2

Это зависит от того, как вы хотите обнаружить мобильного пользователя. Это можно сделать с помощью веб-сервера с использованием правила перезаписи. Он может быть обнаружен с помощью user-agent script в вашем PHP-коде, и в этом случае это будет сделано контроллером. Это может сбивать с толку в основном потому, что существует так много вариантов. У Google есть много особенностей на этом.

Переписать ex:

RewriteCond %{HTTP_USER_AGENT}  ^.*iPhone.*
RewriteRule ^(.*)$         m.site.com/$1

Ответ 3

Как указано в @Supericy, в большинстве случаев интерфейс (представление) отвечает за обнаружение, потому что, как указывает его имя, это то, что отображается пользователю.

Например, если вы используете класс обнаружения , вы просто напишите в верхней части вашего index.php или аналогичного файла, если вы намерены использовать функцию header().

<?php
include 'Mobile_Detect.php';
$detect = new Mobile_Detect();

if ($detect->isMobile()) {
    // Any mobile device. Do stuff
} else {

}

?>

На странице класса мобильного обнаружения еще есть примеры https://github.com/serbanghita/Mobile-Detect. Вы можете очень точно относиться к устройствам.

Есть много других способов достичь этого, но это самый простой, на мой взгляд.

Ответ 4

Обнаружение пользователей мобильных устройств лучше всего предоставить вашему серверу, поскольку он должен управлять всем трафиком. Если ваш код уходит в разные веб-сайты или вам не нужно показывать одинаковые страницы пользователю с настольными и мобильными устройствами, то вот часть конфигурации apache, которая решит вашу проблему. Не забудьте посетить http://detectmobilebrowsers.com/, чтобы захватить новую версию мобильного определения regexp.

# if already mobile - skip this (usually there are will be another config for mobile)
RewriteCond %{HTTP_HOST} !^mobile\.
# put all sites you don't want to redirect here, or compose a regex that will match sites
RewriteCond %{HTTP_HOST} !(dev.twitter.com) 

# taken from http://detectmobilebrowsers.com/
RewriteCond %{HTTP_USER_AGENT} (android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od|ad)|iris|kindle|lge\ |maemo|midp|mmp|netfront|opera\ m(ob|in)i|palm(\ os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows\ (ce|phone)|xda|xiino [NC,OR]
RewriteCond %{HTTP_USER_AGENT} ^(1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a\ wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r\ |s\ )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1\ u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp(\ i|ip)|hs\-c|ht(c(\-|\ |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac(\ |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt(\ |\/)|klon|kpt\ |kwc\-|kyo(c|k)|le(no|xi)|lg(\ g|\/(k|l|u)|50|54|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-|\ |o|v)|zz)|mt(50|p1|v\ )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v\ )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-|\ )|webc|whit|wi(g\ |nc|nw)|wmlb|wonu|x700|yas\-|your|zeto|zte\-) [NC]

# rewrite only sites.
RewriteCond %{HTTP_HOST} (\.|)([^\.]+\.[^\.0-9]+)$

#redirect to mobile
RewriteRule ^(.*)$ http://mobile.twitter.com$1 [L,NS]