Создание собственного обработчика аргументов для моей собственной PHP-фреймворка

Я решил создать свою собственную мини - фреймворк для PHP, которую я собираюсь использовать для реальной работы, создание веб-сервиса для социального приложения.

Я начал с руководства Фабьена Потенсьера по созданию вашей собственной платформы поверх компонентов Symfony - http://symfony.com/doc/current/create_framework/index.html. Мне очень понравились его библиотеки classLoader и http-foundation и я решил их интегрировать.

Я прочитал весь учебник, но решил прекратить интеграцию компонентов Symfony до пятой части учебника, где он попадает в ядро ​​Symfony http, средство сопоставления маршрутов и преобразователь контроллеров (исключая те).

Есть вопрос о фронт-контроллере и картографическом маршруте моего фреймворка, о котором идет речь.

front.php (фронт-контроллер)

<?php 

        require 'config/config.php';
        require 'config/routing.php';
        require 'src/autoloader.php';

        use Symfony\Component\HttpFoundation\Request;
        use Symfony\Component\HttpFoundation\Response;

        $request = Request::createFromGlobals();

        $response = new Response();


        $path = $request->getPathInfo();

        if(isset($siteMap[$path])) {
            call_user_func_array('src\Controllers' .'\\' . $siteMap[$path]['controller'] . '::' . $siteMap[$path]['action'], array($siteMap[$path]['arguments']));
        } else {    
            $response->setStatusCode('404');
            $response->setContent('Page not found');
        }

    $response->send();
?>  

Мой файл маршрутизации:

/*  
    Map of routes
*/

$siteMap = array('/' => array('controller' => 'IndexController', 'action' => 'indexAction', 'arguments' => ''),
                    '/categories' => array('controller' => 'CategoriesController', 'action' => 'indexAction', '

То, что я хочу знать сейчас, это без дальнейшего использования компонентов Symfony, как я могу сделать что-то вроде этого:

В моем файле маршрутизации я хочу добавить URL-адрес, например '/hello', с Controller - Hello Controller и именем аргумента, возрастом, полом, который будет соответствовать запросу в браузере GET www.base/hello/samuel/11/male.

А в HelloController есть indexAction($name, $age, $ sex) { ... }. Я попытался посмотреть на исходные тексты Symfony, но до сих пор это ускользает от меня (я провел много времени, изучая исходный код библиотек). Я собираюсь модульно разделить функции переднего контроллера и контроллера, решая их еще дальше, но я хочу разобраться в этом.

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

2 ответа

Решение

Вы должны определить регулярные выражения для своих маршрутов и сопоставить их с запросами, если вы хотите знать, как Symfony преобразует свой собственный формат маршрута, например: '/path/to/{id}' в регулярное выражение, см. RouteCompiler:: compilePattern. Это выходит за рамки этого вопроса, и я не предоставлю никакого кода для него.

Регулярное выражение для вашего примера маршрута будет что-то вроде ^/hello/(\w*)/(\d*)/(\w*)/$, это будет соответствовать '/ привет / любая строка / любое число / любая строка /' например: /hello/samuel/11/male (не забудьте ^ и $они соответствуют началу и концу строки).

Вы должны предоставить регулярное выражение для каждого маршрута и сделать preg_match(rawurldecode($request->getPathInfo(), $regex /* as created earlier*/, $matches) против всех маршрутов (до совпадения) вместо isset($sitemap[$path]) если это возвращает false, маршрут не совпадает. в противном случае вы должны получить аргументы для вашего контроллера следующим образом:

preg_match(rawurldecode($request->getPathInfo(), $regex /* as created earlier*/, $matches)
$args = array();
// we omit the first element of $matches, since it's the full string for the match
for($i = 1; $i < count($matches); $i++){
  $args[] = $matches[$i];
}

Теперь вы можете объединить $args с аргументами по умолчанию и вызвать контроллер.


См. UrlMatcher:: matchCollection () о том, как Symfony сопоставляет каждый маршрут с регулярным выражением, и создает аргументы.

Я хотел бы добавить дополнительную информацию. В Symfony вы можете получить Аргументы вашего запроса в аргументы метода:

public function fooAction($bar);

В этом случае это будет выглядеть в $request->attributes за ключ с bar, если значение присутствует, оно добавит это значение в ваше действие. В Symfony 3.0 и ниже это делается через ControllerResolver::getArguments(), Начиная с Symfony 3.1 вы сможете реализовать или расширить ArgumentResolver,

Используя ArgumentResolver означает, что вы можете легко добавить свой собственный функционал в решение. Существующие преобразователи значений находятся здесь.

Другие вопросы по тегам