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.
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
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;
}
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