Slim — это микрофреймворк, который предлагает возможности маршрутизации для простого создания небольших PHP-приложений. Но интересной и мощной функцией является концепция Middleware. Slim реализует протокол Rack, конвейерную архитектуру, общую для многих сред Ruby. Таким образом, может быть написано промежуточное программное обеспечение, которое оборачивает приложение, имеет доступ и может влиять на среду приложения и объекты запросов и ответов в цепочке.
Я обнаружил, что промежуточное ПО является красноречивым решением для реализации различных сервисов, подобных фильтрам, в приложениях Slim, таких как аутентификация и кэширование. В этой статье я объясню, как работает промежуточное ПО, и поделюсь с вами простым примером кэширования, который показывает, как вы можете реализовать свое собственное промежуточное ПО.
Понимание тонкого промежуточного программного обеспечения
Документация Slim сравнивает приложение Slim с луком, где каждый слой лука является промежуточным программным обеспечением. Это подходящая метафора. Чтобы лучше понять это, давайте предположим, что мы пишем приложение, которое использует аутентификацию и кэширование. Наша архитектура может выглядеть следующим образом:
Код, который отвечает за генерацию контента страницы, обернут в несколько уровней промежуточного программного обеспечения, наиболее важно логика аутентификации и логика кэширования.
Поток выполнения проходит через каждый уровень, и ему либо разрешается переходить на следующий уровень, либо он перенаправляется. Сначала выполняется проверка, чтобы убедиться, что пользователь аутентифицирован. Если нет, поток прерывается и возвращается статус HTTP 401. Затем проверяется, доступна ли кэшированная копия содержимого. Если это так, поток прерывается кэшированной копией возвращаемой страницы. Другие уровни промежуточного программного обеспечения могут существовать до тех пор, пока поток, наконец, не достигнет логики, отвечающей за генерацию страницы.
Когда наши методы промежуточного программного обеспечения возвращаются, поток выполнения пузырится обратно через них. Например, оставшаяся логика промежуточного программного обеспечения для кэширования кэширует содержимое страницы для последующего просмотра.
Реализация промежуточного программного обеспечения
Чтобы увидеть, как можно реализовать собственную промежуточную программу, давайте посмотрим на код, который может служить промежуточной программой для кэширования, упомянутой выше.
Требования для реализации любого базового компонента промежуточного программного обеспечения Slim на самом деле весьма минимальны. Нам нужно только написать класс, который расширяет SlimMiddleware и переопределяет метод call()
. Точкой входа промежуточного программного обеспечения является метод call()
, который мы можем либо вернуть (тем самым прерывая поток выполнения), либо вызвать следующий уровень.
<?php namespace MyMiddleware; class Cache extends SlimMiddleware { protected $db; public function __construct(PDO $db) { $this->db = $db; } public function call() { $key = $this->app->request()->getResourceUri(); $rsp = $this->app->response(); $data = $this->fetch($key); if ($data) { // cache hit... return the cached content $rsp["Content-Type"] = $data["content_type"]; $rsp->body($data["body"]); return; } // cache miss... continue on to generate the page $this->next->call(); if ($rsp->status() == 200) { // cache result for future look up $this->save($key, $rsp["Content-Type"], $rsp->body()); } } protected function fetch($key) { $query = "SELECT content_type, body FROM cache WHERE key = " . $this->db->quote($key); $result = $this->db->query($query); $row = $result->fetch(PDO::FETCH_ASSOC); $result->closeCursor(); return $row; } protected function save($key, $contentType, $body) { $query = sprintf("INSERT INTO cache (key, content_type, body) VALUES (%s, %s, %s)", $this->db->quote($key), $this->db->quote($contentType), $this->db->quote($body) ); $this->db->query($query); } }
Метод call()
сначала проверяет, доступно ли содержимое в кэше. Если это так, он устанавливает заголовок и тело Content-Type ответа, а затем возвращает его, закорачивая конвейер. Если кэш отсутствует, то вызывается $this->next->call()
для вызова следующего уровня промежуточного программного обеспечения. Когда поток возвращается к этой точке из-за других вызовов промежуточного программного обеспечения, выполняется быстрая проверка состояния запроса, и соответствующие данные кэшируются для будущих поисков.
Поскольку класс расширяет класс Middleware
Slim, он имеет доступ к экземпляру приложения Slim через $this->app
и, таким образом, косвенно получает доступ к объектам ответа и запроса. Мы можем повлиять на заголовки ответа, рассматривая его как массив, а тело ответа — через метод body()
.
Методы fetch()
и save()
являются защищенными помощниками, которые просто переносят запросы к базе данных для поиска и сохранения содержимого. Я включил их сюда только для завершения примера. Предполагается, что cache
таблицы существует с key
столбцов, content_type
и body
. Ваш механизм настойчивости может отличаться в зависимости от ваших потребностей. Кроме того, здесь не показано (для простоты) истечение срока действия кэша, хотя его легко включить самостоятельно.
Регистрация и настройка промежуточного программного обеспечения
Регистрация промежуточного программного обеспечения осуществляется с помощью метода add()
Slim.
<?php require_once "../vendor/autoload.php"; $app = new SlimSlim(); $app->add(new MyMiddlewareCache($db));
Конечно, последующие вызовы add()
могут зарегистрировать более одного промежуточного программного обеспечения. Поскольку новое промежуточное программное обеспечение окружает любое ранее добавленное промежуточное программное обеспечение, это означает, что они должны быть добавлены в обратном порядке их вызова.
<?php $app = new SlimSlim(); $app->add(new MyMiddlewareCache($db)); $app->add(new MyMiddlewareAuth($db)); // ...
В приведенном выше примере промежуточное ПО Cache оборачивает приложение Slim, а затем промежуточное ПО Auth оборачивает Cache. Когда $app->run()
, поток выполнения будет похож на тот, что показан на иллюстрации выше, сначала войдя в промежуточное ПО аутентификации и проложив путь вниз по маршруту.
Настройка промежуточного программного обеспечения обычно выполняется через конструктор службы. В нашем примере я просто передал активное соединение с базой данных, чтобы оно могло обращаться к таблице кеша, но вы можете написать свой класс, чтобы принимать любую информацию, которая может вам понадобиться для настройки его поведения. Например, компонент может быть переписан для принятия объекта-обработчика, который предоставляет метод fetch()
и save()
; это позволило бы нам удалить примеры методов (или использовать их как запасной вариант по умолчанию), а разработчик конечного пользователя предоставил бы функциональность в соответствии с их требованиями как часть конфигурации компонента.
Вывод
Я обнаружил, что промежуточное ПО является красноречивым решением для реализации различных аспектов приложения Slim. В этой статье я объяснил, как работает архитектура промежуточного программного обеспечения и что необходимо для реализации собственного промежуточного программного обеспечения. Существует небольшое хранилище дополнений с некоторыми базовыми примерами промежуточного программного обеспечения, такими как защита CSRF и HTTP-аутентификация. Я реорганизовал приведенный здесь пример и отправил запрос на извлечение , поэтому, если вы пишете полезный сервис промежуточного программного обеспечения, почему бы не подумать о том, чтобы отправить его в проект, чтобы другие также могли получить пользу?
Изображение через Fotolia