Подтвердить что ты не робот

Как работает маршрутизация MVC?

Итак, я начал изучать MVC (реальный MVC, а не фреймворк MVC) немного более подробно, и я пытаюсь разработать небольшую структуру. Я работаю, читая другие фреймворки, такие как Symphony и Zend, видя, как они выполняют свою работу, и пытаюсь реализовать ее самостоятельно.

Место, где я застрял, - это система маршрутизации URL:

<?php
namespace Application\Common;

class RouteBuilder {

    public function create($name, $parameters) {
        $route           = new Route($name);
        $route->resource = array_keys($parameters)[0];
        $route->defaults = $parameters["defaults"];
        $notation        = $parameters["notation"];
        $notation = preg_replace("/\[(.*)\]/", "(:?$1)?", $notation);
        foreach ($parameters["conditions"] as $param => $condition) {
            $notation = \str_replace($param, $condition, $notation);
        }

        $notation = preg_replace("/:([a-z]+)/i", "(?P<$1>[^/.,;?\n]+)", $notation);

        //@TODO: Continue pattern replacement!!
    }
}
/* How a single entry looks like
 * "main": {
    "notation": "/:action",
    "defaults": {
        "resource"  :   "Authentication",
    },
    "conditions":   {
        ":action"   :   "(login)|(register)"
    }
},

 */

Я просто не могу получить свою голову, обернутую вокруг. Что такое рабочий процесс приложения отсюда?

Создается шаблон, возможно, объект Route, который хранится под объектом Request или что-то в этом роде, а что? Как это работает?

P.S. Ищите настоящий, хорошо объясненный ответ здесь. Я действительно хочу понять эту тему. Я был бы признателен, если бы кто-то нашел время, чтобы написать настоящий подробный ответ.

4b9b3361

Ответ 1

Класс MVC Router (который является частью более широкого Front Controller) разбивает URL-адрес HTTP-запроса, в частности, компонент пути (и, возможно, строку запроса).

Router пытается сопоставить первую или две части компонента пути с соответствующей комбинацией маршрутов (Controller/Действие [метод], или просто с Controller который выполняет действие (метод) по умолчанию.

Действие или команда - это просто метод от определенного Controller.

Обычно существует abstract Controller и много дочерних элементов Controller, по одному для каждой веб-страницы (вообще говоря).

Некоторые могут сказать, что Router также передает аргументы нужному методу Controller, если таковые имеются в URL.

Примечание: пуристы объектно-ориентированного программирования, следуя принципу единой ответственности, могут утверждать, что компоненты маршрутизации URL-адреса и диспетчеризация класса Controller являются двумя отдельными обязанностями. В этом случае класс Dispatcher фактически создает экземпляр Controller и передает одному из его методов любые аргументы, полученные из клиентского HTTP-запроса.

Пример 1: Controller, но нет действий или аргументов.

http://localhost/contact При запросе GET может отображаться форма.

Контролер = Контракт

Действие = по умолчанию (обычно метод index())

======================

Пример 2: Controller и действие, но без аргументов.

http://localhost/contact/send При запросе POST это может привести к отказу от проверки на стороне сервера и попытке отправить сообщение.

Контролер = Контракт

Действие = отправить

======================

Пример 3: Controller, действие и аргументы.

http://localhost/contact/send/sync При запросе POST это может привести к отказу от проверки на стороне сервера и попытке отправить сообщение. Однако, в этом случае, возможно, JavaScript не активен. Таким образом, чтобы поддерживать постепенную деградацию, вы можете указать ContactController использовать View который поддерживает перерисовку экрана и отвечает HTTP-заголовком Content-Type: text/html вместо Content-Type: application/json. sync будет передана в качестве аргумента ContactConroller::send(). Обратите внимание, мой пример sync был абсолютно произвольным и составленным, но я подумал, что он отвечает всем требованиям!

Контролер = Контракт

Действие = отправить

Arguments = [sync]//Да, передайте аргументы в массиве!

Класс Router создает экземпляр запрашиваемого конкретного дочернего Controller, вызывает запрашиваемый метод из экземпляра контроллера и передает его методу контроллера его аргументы (если есть).

1) Ваш класс Router должен сначала проверить, существует ли конкретный Controller который он может создать (используя имя, указанное в URL, плюс слово "Controller"). Если контроллер найден, проверьте наличие запрошенного метода (действия).

2) Если Router не может найти и загрузить необходимый PHP во время выполнения (используя автозагрузчик рекомендуется) для создания экземпляра конкретного Controller ребенка, он должен затем проверить массив ( как правило, находятся в другом имени класса Route), чтобы увидеть, если запрашиваемые URL спичек используя регулярные выражения, любые элементы, содержащиеся в. Ниже приведен базовый скелет класса Route.

Примечание:. .*? = Ноль или более любого символа, без захвата.

class Route
{
    private $routes = [
        ['url' => 'nieuws/economie/.*?', // regular expression.
         'controller' => 'news',
         'action' => 'economie'],
        ['url' => 'weerbericht/locatie/.*?', // regular expression.
         'controller' => 'weather',
         'action' => 'location']
    ];

    public function __contstruct()
    {

    }

    public function getRoutes()
    {
        return $this->routes;
    }
}

Зачем использовать регулярное выражение? Вряд ли можно получить надежное сопоставление данных после второй косой черты в URL.

/controller/method/param1/param2/..., где param [x] может быть чем угодно!

Предупреждение. Рекомендуется изменять разделитель шаблона регулярного выражения по умолчанию ('/'), если при таргетинге на данные содержится разделитель шаблона (в этом случае косая черта вперед /'). Подойдет практически любой недопустимый символ URL.

Метод класса Router будет выполнять итерацию по массиву Route::routes routs, чтобы определить, совпадает ли регулярное выражение между целевым URL-адресом и string значением, связанным с индексом url 2-го уровня. Если совпадение найдено, то Router знает, какой конкретный Controller нужно создать и последующий метод вызвать. Аргументы будут переданы методу по мере необходимости.

Всегда будьте осторожны с крайними случаями, такими как URL, представляющие следующее.

'/'   // Should take you to the home page / HomeController by default
''''  // Should take you to the home page / HomeController by default
'/gibberish&^&*^&*%#&(*$%&*#'   // Reject

Ответ 2

Класс маршрутизатора из моей структуры. Код рассказывает историю:

class Router
{
  const default_action = 'index';
  const default_controller = 'index';

  protected $request = array();

  public function __construct( $url )
  {
    $this->SetRoute( $url ? $url : self::default_controller );
  }

  /*
  *  The magic gets transforms $router->action into $router->GetAction();
  */
  public function __get( $name )
  {
    if( method_exists( $this, 'Get' . $name ))
      return $this->{'Get' . $name}();
    else
      return null;
  }

  public function SetRoute( $route )
  {
    $route = rtrim( $route, '/' );
    $this->request = explode( '/', $route );
  }

  private function GetAction()
  {
    if( isset( $this->request[1] ))
      return $this->request[1];
    else
      return self::default_action;
  }

  private function GetParams()
  {
    if( count( $this->request ) > 2 )
      return array_slice ( $this->request, 2 );
    else
      return array();
  }

  private function GetPost()
  {
    return $_SERVER['REQUEST_METHOD'] == 'POST';
  }

  private function GetController()
  {
    if( isset( $this->request[0] ))
      return $this->request[0];
    else
      return self::default_controller;
  }

  private function GetRequest()
  {
    return $this->request;
  }