Соответствующий параметр в URL в PHP-маршрутизаторе - PullRequest
1 голос
/ 18 марта 2019

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

Я застрял в части маршрутизатора, где у параметра Route есть параметр в URL, например:

example.com / применить / {переменная}

Это классы:

Класс маршрутизатора:

<?php

class Router
{
    private $request;

    private $supportedHttpMethods = array("GET", "POST");

    function __construct(RequestInterface $request)
    {
        $this->request = $request;
    }

    function __call($name, $args)
    {
        list($route, $method) = $args;
        if (!in_array(strtoupper($name), $this->supportedHttpMethods)) {
            $this->invalidMethodHandler();
        }
        $this->{strtolower($name)}[$this->formatRoute($route)] = $method;
    }

    /**
     * Removes trailing forward slashes from the right of the route.
     *
     * @param route (string)
     */
    private function formatRoute($route)
    {
        $result = rtrim($route, '/');
        if ($result === '') {
            return '/';
        }

        return $result;
    }

    private function invalidMethodHandler()
    {
        header("{$this->request->serverProtocol} 405 Method Not Allowed");
    }

    private function defaultRequestHandler()
    {
        header("{$this->request->serverProtocol} 404 Not Found");
    }

    /**
     * Resolves a route
     */
    function resolve()
    {
        $methodDictionary = $this->{strtolower($this->request->requestMethod)};
        $formatedRoute = $this->formatRoute($this->request->requestUri);
        $method = $methodDictionary[$formatedRoute];
        if (is_null($method)) {
            $this->defaultRequestHandler();

            return;
        }
        echo call_user_func_array($method, array(
            $this->request
        ));
    }

    function __destruct()
    {
        $this->resolve();
    }
} 

Класс запроса:

<?php

include_once 'RequestInterface.php';

class Request implements RequestInterface
{
    private $params = [];

    public function __construct()
    {
        $this->bootstrapSelf();
    }

    private function bootstrapSelf()
    {
        foreach ($_SERVER as $key => $value) {
            $this->{$this->toCamelCase($key)} = $value;
        }
    }

    private function toCamelCase($string)
    {
        $result = strtolower($string);

        preg_match_all('/_[a-z]/', $result, $matches);
        foreach ($matches[0] as $match) {
            $c = str_replace('_', '', strtoupper($match));
            $result = str_replace($match, $c, $result);
        }

        return $result;
    }

    public function isPost()
    {
        return $this->requestMethod === "POST";
    }

    /**
     * Implemented method
     */
    public function getParams()
    {
        if ($this->requestMethod === "GET") {
            $params = [];
            foreach ($_GET as $key => $value) {
                $params[$key] = filter_input(INPUT_POST, $key, FILTER_SANITIZE_SPECIAL_CHARS);
            }
            $this->params = array_merge($this->params, $params);
        }
        if ($this->requestMethod == "POST") {
            $params = [];
            foreach ($_POST as $key => $value) {
                $params[$key] = filter_input(INPUT_POST, $key, FILTER_SANITIZE_SPECIAL_CHARS);
            }
            $this->params = array_merge($this->params, $params);
        }

        return $this->params;
    }
}

Вот как я бы назвал Маршрутизатор:

$router->get('/apply/{code}', function($request) use($myClass) {});

Какой подход будет лучше? Я не знаю, как решить это.

1 Ответ

2 голосов
/ 19 марта 2019

Я бы настоятельно рекомендовал взглянуть на существующие http фабричные реализации , прежде чем изобретать велосипед с нуля. Даже пользовательские реализации могут выглядеть так, как будто они обеспечивают некоторую гибкость и преимущества в краткосрочной перспективе, вы можете легко сделать ставку на ногу в среднесрочной / долгосрочной перспективе, создав приложение, основанное на таком подходе.

Как сам язык, так и экосистема PHP сильно эволюционировали, мы в 2019 году, у нас есть десятки хорошо написанных, многократно используемых библиотек. Просто возьмите свое оружие и сфокусируйтесь на своей настоящей цели. Любой код без тестов, включающий магию, не нуждается в композиторе, надлежащем механизме автозагрузки, хорошо написанном маршрутизаторе или быстром движке шаблонов; в большинстве случаев это вызовет больше боли, чем ценность, которую он обеспечивает. Мы должны перестать повторяться.

Насколько я понимаю, ваша цель - обслуживать контент JSON по определенному пути URI, но вы пытаетесь изобрести маршрутизатор. Если вашей целью является написание правильного маршрутизатора, то нет ничего общего с интерфейсами запроса / ответа, о которых упоминалось в вопросе. Я бы посоветовал взглянуть на реализации некоторых повторно используемых фреймворк-независимых маршрутизаторов, таких как FastRoute , Zend Router , Aura Router и т. Д. Внедрение правильного маршрутизатора - это, конечно, не ракетостроение, но это не так просто, как вы уже поняли. Тем не менее, попытка написать этот компонент может быть и образовательной, и если ваша цель заключается в этом, сделайте это.

Вот пара советов (и новые проблемы, о которых нужно подумать):

  • Существует стандарт обработки PSR-15 . Отправка заголовков в закрытых методах с именем requestHandler может быть плохой идеей.
  • Обработчики запросов и маршрутизаторы являются разными компонентами и требуют разных рабочих процессов. Вы смешиваете их в своем коде, и это предупреждающий знак.
  • Любой код, включающий __magic, создает ловушку для вас и потенциальных будущих разработчиков.
  • Я не уверен в результате строки include_once 'RequestInterface', но у нас есть Интерфейсы HTTP-сообщений . Я хотел бы рассмотреть возможность импорта use Psr\Http\Message\ServerRequestInterface в любой тип пользовательской реализации при работе с запросами.
  • Эхо в __destruct тоже интересно. Здесь вам нужен излучатель. Несколько примеров: Http Emitter , Zend Http Runner
  • А вот ответ высокого уровня на ваш актуальный вопрос: вам нужно реализовать механизм (возможно, с использованием регулярных выражений), чтобы перехватывать шаблоны в частях URI и анализировать и обнаруживать необязательные или требуемые именованные части в «путях».

Лично я бы рекомендовал взглянуть на Zend Expressive . Это очень помогает разработчикам при написании легких приложений на основе промежуточного программного обеспечения. Лучшая особенность Expressive - вы можете выбрать любое оружие в соответствии с вашими потребностями. Это не полноценная инфраструктура MVC, она предоставляет новый способ написания веб-приложений, и это чертовски быстро. Вы можете свободно выбирать любой компонент, который хотите, например; Twig для нужд рендеринга, Symfony Console для CLI, Zend Service Manager в качестве контейнера внедрения зависимостей, Aura Router для маршрутизации и т.д ..

Вы можете попробовать его, используя всего несколько команд (при условии, что у вас есть глобально установленный композитор ):

composer create-project zendframework/zend-expressive-skeleton my-app
cd my-app
composer run --timeout=0 serve

И откройте ваш браузер: http://localhost:8080

Удачи!

...