H Slim framework или как мы отказались от CMS в черновиках Из песочницы. Пишем простую энциклопедию на Slim Framework Копирование Slim Framework в общедоступное место

Эта публикация будет интересна небольшим компаниям по разработкам сайтов с использованием CMS. Небольшая предыстория: мы — это небольшой отдел, который занимается разработкой веб-сайтов. Очень долгое время мы разрабатывали сайты только на системах управления (OpenCart, WordPress, MODX и самописная), которые по своей сути были простые и однотипные, но с лета прошлого года пришёл тренд на разработку сайтов, которые не просто были в интернете лицом компании, но одним из инструментов бизнеса.

Так, например, был заказ для транспортной компании, которая осуществляет рейсовые маршруты и хотела бы, чтобы всё управление (бронирование и оплата билета, в том числе через кассира) происходила через сайт.

Как вы можете догадываться, большой пользы от CMS тут ждать не приходится. Даже наоборот — любой алгоритм, которому она следовала, нам мешал. Через несколько дней на первом же таком сайте были одни костыли и практически вся обработка шла исключительно на javascript, а CMS использовалась как прослойка для записи и выборки из базы данных.

Терпеть такое мы долго не смогли и, посовещавшись, решили, что для таких проектов мы будем использовать miсroframework — и сразу же положили глаз на Slim.

Как гласит официальный сайт:

Slim — это микро фреймворк, который поможет вам быстро писать простые, но мощные веб-приложения.

И это действительно так, вы можете скачать его вручную архивом или воспользоваться Composer. После этого создайте index.php со следующим содержанием:

//Подключаем фреймворк require "Slim/Slim.php"; //Регистрируем автозагрузку \Slim\Slim::registerAutoloader(); $app = new \Slim\Slim(); $app->get("/hello/:name", function ($name) { echo "Привет, $name"; }); $app->run();
Это простое приложение которое выводит привет {{username}} при переходе на url.
Но как же мы были разочарованы, что на этом большинство статей в интернете заканчивается и на данном этапе многое остается для нас непонятным.

Сам Slim не задает чёткой системы распределений файлов на диске, поэтому мы не нашли лучшего способа, чем иклюдить каждый роутинг. На следующий день, поняв, что что-то идёт не так, было решено создать отдельную папку и класть туда файлы по группам. В файл index.php добавилось следующее

Foreach (glob("Routes/*.php") as $file) include($file);
Со временем каждый такой файл стал слишком большим, но посмотрев официальную документацию , ничего не обнаружили. Решение было найдено на github, где было сказано, что надо делать:

$app->get("post/:type/:id", "\Controller\Post:onePost");
Где \Controller\Post — класс, который, как я понимаю, добавлен в соответствии с RSP-0. А onePost — это его метод.
Таким образом наша файловая структура обновилась ещё одной директории Controller, в которую мы записывали действия, которые могли использовать сразу в нескольких вариантах роутинга. Я считаю хорошим примером данный роутинг, который заключён в группу, стиль, который почему-то не описан в той же документации.

$app->group("/", function () use ($app) { $app->get("post/:type/:id", "\Controller\Post:onePost") ->conditions(array("type" => "{3,}", "id" => "{1,}")) ->setParams(array("app" => $app, "type" => $type = NULL, "id" => $id = 0)) ->name("onePost"); });
Где conditions — валидация по регулярному выражению, setParams — передача параметров методу onePost, а name — имя для возможного редиректа на данную страницу (Например $app->redirectTo("onePost");)

Не лишним будет проводить проверку на доступность не в самом контроллере, а на уровне роутига, благодаря «Middleware». Например, для панели администратора сразу же можно поставить на целую группу такую как:

$app->group("/admin", $authenticateForRole($app, "admin"), function () use ($app) { ... });
Где вторым аргументом является присвоенная анонимная функция переменной. В моём случае она выглядит таким образом:

$authenticateForRole = function ($app, $role = "admin") { return function () use ($app, $role) { \Controller\Autch::chekUserRole($app, $role); }; };
К сожалению, а для некоторых, может, и к счастью, в slim нет встроенной работы с базой данных, но этот вопрос достаточно просто решается, когда мы создаём объект App. Мы можем передавать некоторые аргументы, которые будут им использоваться.

Например:

$app = new \Slim\Slim(array("templates.path" => "Views", "debug" => TRUE, "mode" => "development", "BDbase" => "localhost", "BDuser" => "username", "BDpassword" => "password", "BDname" => "basename"));
После этого мы сможем спокойно воспользоваться Dependency Injection для работы с базой данных, обращаясь к параметрам, переданным при создании с помощью метода $app-config("Имя");

$app->database = new mysqli($app->config("BDbase"), $app->config("BDuser"), $app->config("BDpassword"), $app->config("BDname")); if ($app->database->connect_errno) { echo "Не удалось подключиться к MySQL: (" . $app->database->connect_errno . ") " . $app->database->connect_error; die(); } $app->database->query("SET NAMES "utf8""); $app->database->query("SET CHARACTER SET "utf8""); $app->database->query("SET SESSION collation_connection = "utf8_general_ci"");
Все остальные возможности Slim достаточно хорошо описаны в документации. В заключении хочу сказать, что для нашей команды, которая никогда раньше не работала с различными framrwork"ами, это был хороший опыт, который мы уже используем в проектах. Возвращаться на какую-либо CMS желания не возникает.

  • Tutorial

В этой заметке мы рассмотрим процесс создания очень простой электронной энциклопедии с применением Slim Framework. Предположим, что у вас есть таблица базы данных, которая содержит огромное количество энциклопедических заметок и статей. Нам нужно показывать пользователю соответствующую заметку в красивом шаблоне.

Может быть, наша энциклопедия содержит ответы на часто задаваемые вопросы об автомобилях, а может это медицинский справочник. Не суть дела. Главное, что нам не нужен CRUD, так как за наполнение таблицы базы данных будет отвечать другая система. Но нам очень важна стабильность, скорость и простота поддержки этого нехитрого приложения.

Подобную энциклопедию можно очень легко создать средствами других фреймворков и CMS, но я попробую использовать микрофреймворк Slim. Почему? Всё очень просто: настоящая заметка рассчитана на начинающего программиста, который хочет начать изучение Slim Framework.

Приступим к написанию кода. Единственная задача энциклопедии - выводить содержимое в красивом шаблоне. Этот аскетичный функционал похож на API справочной системы. Начнём с реализации модели и всего, что с ней связано. Уникальное имя страницы будет единственным аргументом, который понадобится упомянутому в интерфейсе методу:
interface IPortal { public function getContentByAlias($alias); }
Далее необходимо реализовать класс, содержащий метод «getContentByAlias». Так как заметка рассчитана на начинающий уровень читателя, то я специально напомню о необходимости наложить индекс на столбец «alias». При большом количестве материалов в энциклопедии, индекс (по нему будет поиск) позволит повысить скорость работы сервера базы данных. Таких вопросов как кэширование (например, memcached или средствами nginx) мы касаться не будем, так как это отдельная и очень большая тема. А вот про базовые требования безопасности есть смысл упомянуть: переложите ответственность за экранирование на драйвер, например, таким образом:
class Portal implements IPortal { private $_pdo; private $_sqlGetContentByAlias = "SELECT `title`, `content` FROM `pages` WHERE `alias` = ? LIMIT 1;"; /** * Constructor */ public function __construct($_pdo) { $this->_pdo = $_pdo; } /** * Get content by alias */ public function getContentByAlias($alias) { $stm = $this->_pdo->prepare($this->_sqlGetContentByAlias); $stm->bindParam(1, $alias, PDO::PARAM_STR); $stm->execute(); return $stm->fetch(); } }
Обратите внимание, что в запросе я достаточно явно указал подсистемам MySQL, что мне нужна только одна запись («LIMIT 1»), и получил данные с использованием «fetch», т.е. только одну запись. Я использую PDO, а соединение передаю через конструктор класса. Так как Slim Framework не содержит встроенных возможностей для работы с базами данных (в отличие от моих любимых Laravel и Yii 2.0), то нам придётся написать ещё один небольшой класс. Как вы успели заметить, нам понадобится Singleton, который позволит заполучить столь нужное соединение с базой данных. По моему субъективному мнению, подходящий способ реализации выглядит следующим образом:
class Connect { private static $_instance; private $_pdo; private $_pdoUrl = "mysql:host=localhost;dbname=kalinin;charset=utf8"; private $_pdoUser = "root"; private $_pdoPassword = ""; private $_pdoPrm = ; /** * Constructor */ private function __construct() { $this->_pdo = new PDO($this->_pdoUrl, $this->_pdoUser, $this->_pdoPassword, $this->_pdoPrm); } /** * Singleton */ private function __clone() {} private function __wakeup() {} public static function getInstance() { if (self::$_instance === null) { self::$_instance = new self; } return self::$_instance; } /** * Get connection */ public function getConnection() { return $this->_pdo; } }
Вот и настало время реализации самой фабрики. С большой вероятностью такая электронная энциклопедия не будет развиваться (в смысле нового функционала), однако, вероятность вовсе не нулевая, следовательно, нужно предусмотреть на самом начальном этапе проектирования возможность дорабатывать и развивать проект. Реализация фабрики получилась такой:
require "./app/models/iportal.php"; require "./app/models/portal.php"; require "./db/connect.php"; class Factory { public static function create($type) { $connection = Connect::getInstance()->getConnection(); switch ($type) { case "simple": return new Portal($connection); break; } } }
Я ничего не забыл? Ах, да. Где же сам Slim? Первым делом нам нужно подключить файлы, необходимые для нашего простого приложения - очень аскетичной электронной энциклопедии. На этом этапе мы укажем в настройках режим «debug»:
require "Slim/Slim.php"; require "./app/models/factory.php"; \Slim\Slim::registerAutoloader(); $app = new \Slim\Slim(); $app->config("debug", true); $app->config(["templates.path" => "./app/views/"]); $conf["url"] = "http://127.0.0.1:8098/";
Помните, что мы должны показывать содержимое в шаблоне в зависимости от алиаса страницы? Посредством второго аргумента метода «render» осуществляется передача данных в представление (View в паттерне MVC). А ещё у нас было требование перенаправлять пользователя на главную страницу в том случае, если нет искомой записи в базе данных. Метод «redirect» решает эту задачу. С использованием «use» мы передаём в область видимости анонимной функции (замыкание или лямбда-функция появилась в PHP начиная с версии 5.3) требуемые массивы и другие переменные. Попробуем:
$app->get("/kalinin/:alias", function ($alias) use ($app, $conf) { $model = Factory::create("simple"); $content = $model->getContentByAlias($alias); if(empty($content)) { $app->redirect($conf["url"], 301); } $app->render("page.php", $content); });
В тех случаях, когда представление является статическим контентом достаточно использовать такую реализацию:
$app->get("/", function () use ($app) { $app->render("main.php"); });
Давайте подумаем о печальном. Ошибки могут случиться, а значит, мы обязательно должны продумать поведение электронной энциклопедии в подобных ситуациях. Как говорили древние мудрецы: «не единым XDEBUG-ом жив программист», что значит: «в реальных проектах есть смысл подробно логировать некоторые ошибки». Согласно рекомендациям поисковых систем необходимо выдавать 404-ый код ошибки при неудачной попытке найти страницу, однако, в данном примере, в случае любых ошибок я просто перенаправлю пользователя на главную страницу. Для работы с ошибками используйте следующие два замыкания (для примера у меня просто перенаправление с 301-ым кодом ответа):
$app->notFound(function () use ($app, $conf) { $app->redirect($conf["url"], 301); }); $app->error(function (\Exception $e) use ($app, $conf) { $app->redirect($conf["url"], 301); });
Всё готово, осталось только вызвать метод «run»:
$app->run();
Просто? Хорошая документация поможет вам понять все возможности Slim Framework. Разумеется, я описал только один из возможных подходов. Необходимость применения того или иного фреймворка определяется программистом самостоятельно (или группой разработчиков на совещании).

В этой статье мы обсудим, что такое микрофреймворк Slim Framework и где он может быть полезен.

Slim - это PHP микрофреймворк , предназначенный для быстрого написания простых, но в тоже время мощных web приложений и API . В своей основе фреймворк Slim - это диспетчер, который получает HTTP запрос , вызывает назначенную данному запросу callback-функцию и возвращает HTTP ответ . Вот и все.

Для чего он нужен?

Slim Framework - это идеальный инструмент для создания API , которые используют, переиспользуют какие-либо данные или же предоставляют к ним доступ. Также это прекрасный инструмент для быстрого прототипирования, когда задумка требует скорейшей реализации. Кроме того, с помощью микрофреймворка Slim можно создавать полнофункциональные web-приложения с пользовательским интерфейсом. Он очень быстрый, имеет небольшую кодовую базу - только то, что нужно и больше ничего.

Как запустить?

Для начала необходимо иметь установленный web-сервер. Web-сервер необходимо настроить так, чтобы все запросы он посылал к фронт-контроллеру, т.е. к index.php . В фронт-контроллере создается, настраивается и запускается приложение. Приложение содержит маршруты (URL-адреса ) , которые соответствуют конкретным HTTP запросам. Затем каждый маршрут запускает соответствующий обработчик, представляющий функцию обратного вызова, и возвращает HTTP ответ.

Запрос и ответ

При создании PHP Slim приложения, почти всегда приходиться взаимодействовать с объектами Request и Response . Эти объекты инкапсулируют HTTP запросы получаемые сервером и ответы возвращаемые им в сущности, с которыми удобно работать посредством объектно-ориентированного стиля. У каждого маршрута есть собственная callback-функция которая выполняется, если запрошенный адрес соответствует маршруту. В каждую callback-функцию предаются объекты Response и Request . Они реализуют популярный стандарт PSR 7 . После получение запроса функция ДОЛЖНА вернуть объект Response , соответствующий этому стандарту.

Работа с внешними компонентами

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

Установка

Для работы с Slim Framework необходимо иметь PHP 5.5 и новее, а также нужно иметь настроенные правила конфигурации сервера, для перенаправления всех запросов на index.php . Установку будем выполнять с помощью пакетного менеджера Composer . Если вы не знаете, что такое пакетный менеджер Composer , то на сайте есть о нем. Далее необходимо создать папку, например, MyProject .

Открываем консоль команд и вводим следующее:

$ cd путь-к-папке/MyProject
$ composer require slim/slim "^3.0"

Последняя команда установит сам фреймворк и все его зависимости. После этого в папке MyProject необходимо создать папку public , которая будет являться корневой директорией нашего сайта доступной извне, там же надо создать два файла: index.php и .htaccess , последний файл конфигурации Apache нужен для перенаправления всех запросов к index.php .

Содержимое файла .htaccess :

RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d

RewriteRule ^ index.php

А вот непосредственно код нашего приложения:

Use \Psr\Http\Message\ServerRequestInterface as Request;
use \Psr\Http\Message\ResponseInterface as Response;

Require __DIR__ . "/../vendor/autload.php";

// создаем и настраиваем приложение
$config = ["settings" => [
"addContentLengthHeader" => false,
]];

// передаем массив настроек в конструктор класса Slim\App
$app = new \Slim\App($config);

// определяем маршруты
// главная страница
$app -> get("/",function($request, $response)) {
return $response -> write("Добро пожаловать на мою страницу");
});

// страница с адресом localhost:9090/hello/Alex
$app -> get("/hello/{name}", function ($request, $response, $args) {
return $response->write("Hello " . $args["name"]);
});

// Запускаем приложение
$app->run();

Поясню код выше. С помощью директив use мы импортируем необходимые нам классы из стандарта PSR 7 о котором я говорил выше. Затем включаем в наш index.php файл автозагрузки классов. Такой порядок может показаться несколько необычным, однако он легален с точки зрения языка. После этого создаем массив строк представляющих собой настройки нашего web-приложения . И, наконец, добавляем маршруты с помощью метода get класса Slim\App . Запускаем встроенный в PHP web-сервер с помощью следующих команд:

$ php -S localhost:9090 -t public public/index.php

Открываем браузер по адресу localhost:9090 и смотрим.

Таким образом сегодня мы с Вами познакомились с PHP микрофреймворком Slim Framework . Узнали в каких случаях его можно и стоит использовать. Создали тестовое приложение. Спасибо за внимание.