Jak działa routing MVC?

Więc zacząłem studiować MVC (real MVC, a nie Framework MVC) nieco bardziej dogłębnie i próbuję opracować mały framework. Pracuję czytając inne frameworki, takie jak Symphony i Zend, widząc, jak wykonują swoją pracę i próbując ją zaimplementować.

Miejscem, w którym utknąłem, był system routingu adresów 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)"
    }
},

 */
Po prostu nie mogę mieć głowy owiniętej wokół tego prawidłowo. Jaki jest stąd przepływ pracy aplikacji?

Wzór jest generowany, prawdopodobnie Route obiekt do trzymania pod Request Obiekt czy coś, to co? Jak to działa?

P. S. Szukam tutaj prawdziwej, dobrze wyjaśnionej odpowiedzi. Naprawdę chcę zrozumieć ten temat. Byłbym wdzięczny, gdyby ktoś poświęcił czas na napisanie naprawdę rozbudowanej odpowiedzi.

Author: PeeHaa, 2012-09-14

2 answers

Klasa Router (lub Dispatcher jak niektórzy by ją nazwali) bada adres URL żądania HTTP i próbuje dopasować jego składowe do konkretnej Controller i metody (zwanej akcją lub poleceniem) zdefiniowanej w tym kontrolerze. Przekazuje również argumenty do żądanej metody Controller, jeśli są obecne w adresie URL.

Standardowy URL: query String Format

W Apache HTTP Server , bez użycia mod_rewrite , URL w żądaniu HTTP prawdopodobnie będzie w formacie ciągu zapytania:

http://localhost/index.php?route=news/economics/param1/param2

Przepisanie adresu URL: pożądany Format

W przeciwieństwie do innych serwisów internetowych, nie można ich używać.]}
http://localhost/news/economics/param1/param2

Bez przepisywania URL, będziesz potrzebował klasy, która rozwiązuje route param w żądaniu zapytania ze standardowego adresu URL. To jest pierwsza rzecz, jaką może zrobić klasa Routing. W tym przypadku rozwiązuje param do:

  • controller = NewsController
  • metoda = Ekonomia ()
  • parametry: [param1, param2]

Jeśli wszystko pójdzie dobrze, stanie się coś podobnego:

$controller = new NewsController();
$controller->economics([param1, param2])

A Router Klasa tworzy instancję żądanego, konkretnego potomka Controller, wywołuje żądaną metodę Z instancji kontrolera i przekazuje metodę kontrolera jej argumenty (jeśli istnieją).

Klasa, którą pokazujesz, rozwiązuje żądaną 'trasę' do właściwego kontrolera / akcji. Tak więc, na przykład adres URL poniżej:

http://localhost/index.php?route=news/economics/param1/param2

... jest angielskim adresem URL. Stąd słowo news w łańcuchu zapytania. Załóżmy, że chcesz, aby URL działał w języku niderlandzkim.

http://localhost/index.php?route=nieuws/economie/param1/param2

Oznaczałoby to, że beton Controller nosiłby nazwę nieuwsController.php, ale nie istnieje. Oto, gdzie twój przykład przychodzi do gry: klasa RouteBuilder.

1) Twoja Router klasa powinna najpierw sprawdzić, czy istnieje konkretny Controller, który może utworzyć instancję (używając nazwy znalezionej w adresie URL, plus słowa "Kontroler"). Jeśli kontroler zostanie znaleziony, przetestuj na obecność żądanej metody (akcja).

2) Jeśli Router nie może znaleźć i załadować wymaganego PHP w czasie wykonywania (zaleca się użycie autoloadera {39]}), aby utworzyć instancję konkretnego potomka Controller, należy sprawdzić tablicę (Zwykle znajdującą się w innej nazwie klasy Route), aby sprawdzić, czy żądany adres URL pasuje do , używając wyrażeń regularnych, któregokolwiek z elementów zawartych w środku. Podstawowy szkielet następuje Klasa Route.

Uwaga: .*? = Zero lub więcej dowolnego znaku, nie przechwytywanego.

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

    public function __contstruct()
    {

    }

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

Po co używać wyrażenia regularnego? Jedno z nich prawdopodobnie nie uzyska wiarygodnego dopasowania do danych po drugim ukośniku w adresie URL.

/controller/method/param1/param2/..., gdzie param [x] może być cokolwiek !

Warning: dobrą praktyką jest zmiana domyślnego ogranicznika wzorca wyrażenia regularnego ( ' / ' ), gdy kierowanie danych zawiera ogranicznik wzorca (w w tym przypadku, forward tnie"/". Prawie każdy nieprawidłowy znak URL byłby doskonałym wyborem.

Metoda klasy Router będzie iterować nad tablicą Route::routes, aby sprawdzić, czy istnieje dopasowanie wyrażenia regularnego między docelowym adresem URL i string wartość związana z indeksem drugiego poziomu url. Jeśli dopasowanie zostanie znalezione, Router wtedy wie, który konkretny Controller utworzyć instancję i późniejszą metodę do wywołania. Argumenty zostaną przekazane do metody w razie potrzeby.

Zawsze należy uważać na przypadki brzegowe, takie jak adresy URL reprezentujące następujące.

`/`   // Should take you to the home page / HomeController by default
`''`  // Should take you to the home page / HomeController by default
`/gibberish&^&*^&*%#&(*$%&*#`   // Reject
 27
Author: w00,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-07-18 23:59:24

Klasa routera, z mojego frameworka. Kod opowiada historię:

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;
  }
 3
Author: JvdBerg,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-09-15 11:51:25