За последние 24 часа нас посетили 53852 программиста и 1710 роботов. Сейчас ищут 859 программистов ...

Маршрутиризатор PHP

Тема в разделе "PHP для новичков", создана пользователем Alex5646, 29 дек 2015.

  1. mahmuzar

    mahmuzar Старожил

    С нами с:
    6 апр 2012
    Сообщения:
    4.631
    Симпатии:
    425
    Адрес:
    РД, г. Махачкала.
    Я тоже замечал их объявления раньше. Обратился - не подошел. Вот недавно опять увидел объявление, опять не взяли.))
    Написано, что берут по результатам пройденного тестового задания. У меня просят портфилио, а у меня его практически нету).
    И за отсутствие опыта работы в в других местах не взяли). Короче, надо расти!

    Но тестовое задание решил допилить.
     
  2. artoodetoo

    artoodetoo Суперстар
    Команда форума Модератор

    С нами с:
    11 июн 2010
    Сообщения:
    11.128
    Симпатии:
    1.248
    Адрес:
    там-сям
    По теме: если задачу решать сверху-вниз, поcтепенно конкретизируя, то маршрутизатор + ошибка 404 могут выглядеть как-то так:

    Код (PHP):
    1. $action = findRoute($request, $matches); // return parameters into $matches by reference
    2. if ($action) {
    3.     call_user_func($action, $matches);
    4. } else {
    5.     error404();
    6. }
    Это в первом приближении. А дальше начинается конкретика реального приложения. Например может присоседиться проверка на реферальный код, разворачивание сокращенного URL, правила доступа и т.д.
     
  3. Alex5646

    Alex5646 Новичок

    С нами с:
    29 дек 2015
    Сообщения:
    277
    Симпатии:
    4
    Адрес:
    От верлюда
    Ну в принципе я доделал класс только есть одно но я не очень плохо разбираюсь в регулярных выражениях и хотелось бы услышать критики, особенно по методу SearchVariables().

    Код (PHP):
    1. <?php
    2. /**
    3.  * Class Router Класс маршрутизатора
    4.  * Пример работы:
    5.  *   // Где то мы уже создали объект регистра $registry
    6.  *   $router = new Router($registry);
    7.  *   $router->SetPath(Путь к папке с контролерами);
    8.  *   // Устанавливаем правила маршрутизации
    9.  *   $router->Set(null, 'index');
    10.  *   $router->Set('404', '404');
    11.  *   $router->Set('{name}/{id:([0-9]+)}', function ($name = 'Lexa', $id = '5') {
    12.  *     echo '<b>Name</b>: ' . $name . '<br>';
    13.  *     echo '<b>Id</b>: ' . $id . '<br>';
    14.  *   });
    15.  *   // Старт
    16.  *   $router->Start();
    17.  *
    18.  * @version 1.0 (29.12.2015)
    19.  * @license http://opensource.org/licenses/gpl-license.php GNU Public License
    20.  */
    21.  
    22. Class Router {
    23.  
    24.     /**
    25.      * Класс хранилища
    26.      * @var object
    27.      * @access private
    28.      */
    29.     private $registry;
    30.  
    31.     /**
    32.      * Путь к папке с контроллерами
    33.      * @var string
    34.      * @access private
    35.      */
    36.     private $path;
    37.  
    38.     /**
    39.      * Правила для маршрутизации
    40.      * @var array
    41.      * @access private
    42.      */
    43.     private $rules;
    44.  
    45.     /**
    46.      * Инициализация
    47.      * @access public
    48.      * @param object $registry Объект хранилища
    49.      */
    50.     function __construct($registry) {
    51.         $this->registry = $registry;
    52.     }
    53.  
    54.     /**
    55.      * @method SetPath(string $path) Установка директории с контролерами
    56.      * @access public
    57.      * @param string $path Путь к директории с контроллерами
    58.      * @return true|false В зависимости от существования папки
    59.      */
    60.     public function SetPath($path) {
    61.         $path = trim($path, '/\\');
    62.  
    63.         if (!is_dir($path))
    64.             return false;
    65.  
    66.         $this->path = $path . DIRECTORY_SEPARATOR;
    67.         return true;
    68.     }
    69.  
    70.  
    71.     /**
    72.      * @method Start() Запуск маршрутизатора
    73.      * @access public
    74.      */
    75.     public function Start() {
    76.         $this->ParseURL($controller, $action, $variables);
    77.  
    78.         // Вывод контролера
    79.         if (is_string($controller))
    80.             if($this->CallController($controller, $action, $variables))
    81.                 echo $controller;
    82.         else if (is_callable($controller))
    83.             $this->CallFunction($controller, $variables);
    84.         else
    85.             $this->CallController('404');
    86.     }
    87.  
    88.     /**
    89.      * @method ParseURL(mixed &$controller = null, string &$action = 'index', array &$variables = array()) Парсит URL
    90.      * @access private
    91.      * @param mixed &$controller Имя контроллера или функция
    92.      * @param string &$action Имя метода
    93.      * @param array &$variables Переменные метода
    94.      */
    95.     private function ParseURL(&$controller, &$action, &$variables) {
    96.         $route = isset($_GET['route']) ? rtrim($_GET['route'], '/') : 'index';
    97.  
    98.  
    99.         // Проверяем все ЧПУ правила на совпадения
    100.         foreach ($this->rules as $rules => $array) {
    101.             if ($rules == '/' or $rules == '/index' or $rules == 'index' or !$rules)
    102.                 $rules = 'index';
    103.  
    104.             // Ищем переменные
    105.             $this->SearchVariables($rules, $route, $variables, $regex);
    106.  
    107.             // Ищем совпадения
    108.             if(preg_match($regex, $route)) {
    109.                 // Сохраняем контроллер и экшен
    110.                 $controller = $array['controller'];
    111.                 $action = $array['action'];
    112.             }
    113.         }
    114.     }
    115.  
    116.     /**
    117.      * @method SearchVariables(string &$rules, string $route, array &$variables, string &$regex) Ищет переменные
    118.      * @access private
    119.      * @param string &$rules Правило ЧПУ
    120.      * @param string &$route URL
    121.      * @param array &$variables Переменные метода
    122.      * @param string &$regex Регулярное выражение для URL
    123.      */
    124.     private function SearchVariables($rules, $route, &$variables, &$regex) {
    125.         $regex = $rules;
    126.         $variables = array();
    127.  
    128.         // Формирую регулярное выражение и запоминаю имена переменных
    129.         $varNames = array();
    130.         preg_match_all('/{(.+)}/U', $rules, $matches);
    131.         foreach($matches[1] as $key => $value) {
    132.             // Записываю имя переменной и регулярное выражение в массив
    133.             $varInfo = explode(':', $value);
    134.             $varInfo[1] = isset($varInfo[1]) ? $varInfo[1] : '(.+)';
    135.  
    136.             // Создаю регулярное выражение
    137.             $regex = preg_replace('/' . preg_quote($matches[0][$key]) . '/U', $varInfo[1], $regex);
    138.             // Записываю имя переменной
    139.             $varNames[] = $varInfo[0];
    140.         }
    141.         // Регулярное выражение для ЧПУ
    142.         $regex = '/^' . preg_replace('/\//U', '\/', $regex) . '$/i';
    143.  
    144.         // Записываю переменные
    145.         preg_match($regex, $route, $varValues);
    146.         if(!empty($varValues))
    147.             foreach ($varNames as $key => $value)
    148.                 $variables[$value] = $varValues[$key + 1];
    149.     }
    150.  
    151.     /**
    152.      * @method CallController(string $controller, string $action = 'index', array $variables = array()) Вызывает контроллер
    153.      * @access public
    154.      * @param string $controller Имя контроллера
    155.      * @param string $action Имя метода
    156.      * @param array $variables Переменные метода
    157.      * @return true|false
    158.      */
    159.     public function CallController($controller, $action = 'index', $variables = array()) {
    160.         $controller_path = $this->path . $controller . '.php';
    161.  
    162.         // Подгружаем файл контроллера
    163.         if (is_file($controller_path))
    164.             require_once($controller_path);
    165.         else
    166.             return false;
    167.  
    168.         // Запоминаю класс контроллера
    169.         $controllerClass = 'controller_' . $controller;
    170.  
    171.         // Если класс существует
    172.         if (class_exists($controllerClass)) {
    173.             // Обращаюсь к методу через Reflection API
    174.             $reflection = new ReflectionMethod($controllerClass, $action);
    175.             $reflection->invokeArgs(new $controllerClass($this->registry), $variables);
    176.             return true;
    177.         }
    178.  
    179.         return false;
    180.     }
    181.  
    182.     /**
    183.      * @method CallFunction(callable $controller, array $variables) Вызывает функцию
    184.      * @access public
    185.      * @param callable $function Функция
    186.      * @param array $variables Переменные функции
    187.      * @return true Если всё хорошо
    188.      */
    189.     public function CallFunction($function, $variables) {
    190.         // Обращаюсь к функции через Reflection API
    191.         $reflection = new ReflectionFunction($function);
    192.         $reflection->invokeArgs($variables);
    193.         return true;
    194.     }
    195.  
    196.     /**
    197.      * @method Set(string $rules, mixed $controller, string $action = 'index') Добавление правил для ЧПУ
    198.      *
    199.      * $router->Set(Правило ЧПУ, Контролер|Функция, Экшен);
    200.      *   В правиле ЧПУ можно записывать будущие переменные которые
    201.      *   потом передадутся в функцию,
    202.      *     Синтаксис:
    203.      *       {Имя:Регулярное выражение}
    204.      *     Пример:
    205.      *       {id:([0-9]+)}
    206.      *   Регулярное выражение обязательно должно быть
    207.      *   обвёрнуто круглыми скобками.
    208.      *
    209.      *   Пример маршрута:
    210.      *     Router->Set('{name}/{id:([0-9]+)}', function ($name = 'Lexa', $id = '5') {
    211.      *       echo '<b>Name</b>: ' . $name . '<br>';
    212.      *       echo '<b>Id</b>: ' . $id . '<br>';
    213.      *     });
    214.      *
    215.      *   Для маршрута главной страницы в правиле ЧПУ можно
    216.      *   писать '/', '/index', 'index', '', null и т.д.
    217.      *
    218.      * @access public
    219.      * @param string $rules Правило ЧПУ
    220.      * @param mixed $controller Имя контроллера или функция
    221.      * @param string $action Метод контроллера
    222.      * @return true Если всё хорошо
    223.      */
    224.     public function Set($rules, $controller, $action = 'index') {
    225.         // Удаляем лишние слэши
    226.         $rules = trim($rules, '/');
    227.  
    228.         // Запоминаем
    229.         $this->rules[$rules]['controller'] = $controller;
    230.         $this->rules[$rules]['action'] = $action;
    231.         return true;
    232.     }
    233.  
    234.     /**
    235.      * @method Get(string $rules) Получение контролера для правила ЧПУ
    236.      * @access public
    237.      * @param string $rules Правило ЧПУ
    238.      * @return string|null
    239.      */
    240.     public function Get($rules) {
    241.         return $this->rules[$rules];
    242.     }
    243.  
    244.     /**
    245.      * @method Remove(string $rules) Удаление правил для ЧПУ
    246.      * @access public
    247.      * @param string $rules Правило ЧПУ
    248.      * @return true Если всё хорошо
    249.      */
    250.     public function Remove($rules) {
    251.         unset($this->rules[$rules]);
    252.         return true;
    253.     }
    254. }