Это новый MVC фреймворк для языка PHP, в рамках которого реализовано несколько интересных и уникальных идей, которые вы с малой вероятностью встретите в других PHP фреймворках. На проект большое влияние оказал Play! framework и язык Java.
В двух словах, Regenix это фреймворк, который ориентирован на контроль ошибок, на жесткие рамки, который часто не приемлет множества решений для одной задачи. Таким образом обеспечивается согласованность в большой команде разработчиков.
- Классическая MVC Архитектура
- Поддержка нескольких проектов на одном ядре без лишних манипуляций
- Гибкий роутинг на основе конфигурационных файлов
- Умный анализ кода для выявления runtime ошибок
- Приятный и подробный вывод ошибок
- Менеджер зависимостей для assets, модулей и зависимостей composer
- Ленивая загрузка классов, сканер классов
- Для моделей интегрирован Propel ORM
- CLI для управления проектами
- А также DI контейнер (похожий на Guice), i18n, логирование, свой простой шаблонизатор и многое другое …
Так сложилось, что я работаю в компании где часто используют Java в качестве backend языка и PHP в качестве frontend языка. В мире PHP достаточно много известных фреймворков, однако многие из них не подходят нам по многим критериям. К тому же, после года программирования на Java и Play я сильно привык к другой идеологии и примерно 8 месяцев назад начал разработку Regenix в свободное время.
Далее я расскажу об особенностях фреймворка более подробнее…
Вступление
Regenix требует PHP 5.3+ и любой web сервер (Nginx+FastCGI, Apache + mod_rewrite, и др.), является
полностью Open Source проектом и размещен на GitHub’e (https://github.com/dim-s/regenix). Также частично доступна актуальная документация на английском языке, которую можно найти на гитхабе (русская версия уже устарела).
MVC Архитектура
В Regenix реализована классическая архитектура MVC — Модели, Представления и Контроллеры. Контроллер это класс унаследованный от базового класса regenix\mvc\Controller
, все его публичные нестатичные методы могут быть действиями (actions). Чтобы связать URL с методами контроллеров (routing) используется специальный файл конфигурации с легким для чтения синтаксисом, который очень похож на роутинги из Play framework.
Представление (или Шаблоны) реализованы через специальный шаблонизатор с простым синтаксисом, который частично похож на Smarty. Шаблонизатор по-умолчанию экранирует html символы.
Модели — реализованы с помощью стороннего проекта — Propel ORM, это достаточно известная и популярная ORM, с поддержкой миграций, генерацией схем и моделей и нескольких БД — Postgres, MySQL и т.д.
Контроль Качества — Runtime ошибки
PHP динамический язык программирования, а это означает, что часто ошибка возникает в момент выполнения. Однако, Regenix смог частично решить эту проблему. Во фреймворк встроен анализатор кода, который обнаруживает множество ошибок еще до выполнения самого кода. Для примера возьмем использование несуществующего класса в use (вывод ошибок во фреймворке):
Важно заметить, что фреймворк находит эти ошибки не в момент выполнения! Проверяются абсолютно все исходники проекта при каждом открытии страницы (конечно это происходит в DEV режиме), а также можно запустить анализ из CLI. В общем, фреймворк поддерживает следующие типы ошибок:
- Несуществующие классы — в new, use, аргументах функций и методов, в implements, extends и т.д.
- Проверка на корректность implements и extends
- Проверка на корректность синтаксиса (parse errors)
- Проверка на существование статических метод в местах их вызова
- Соблюдение PSR-0 стандарта именования пакетов и классов
- Возможность блокировать некоторые опасные фичи языка — goto, globals или даже объявление именованных функций
- Возможность блокировать использование супер-глобальных переменных ($_GET, $_POST, etc) и набор функций
При этом есть возможность писать свои анализаторы под свои нужды. Также планируется написать анализаторы для проверки совместимости исходников с разными версиями PHP. Как все это стало возможным? Для этого используется специальный PHP парсер (проект) и Class Scanner, о котором я расскажу ниже.
Class Сканер вместо Загрузчика
Regenix использует нестандартную модель загрузки классов, он не использует имена классов и их namespace для поиска их местоположения как сейчас принято делать в PHP. Class Scanner сканирует папки исходников на наличие в них классов. Что это означает? Для фреймворка есть понятия class paths (привет из Java), при добавлении нового источника классов (т.е. папки с исходниками), фреймворк производит сканирование и записывает всю найденную информацию о классах в кеш.
Особенности сканера классов:
- Нахождение классов вне зависимости от их именования
- Ленивая загрузка классов
- Возможность получить информацию о классе без его загрузки
- Возможность получить, например, всех наследников определенного класса (удобно для модулей)
Хочу заметить, что Class Scanner сохраняет всю найденную информацию в кеш и не сильно влияет на производительность. Вот так, например, можно найти всех наследников класса за достаточно быстрое время (стоимость этой функции доли миллисекунды):
// пример из шаблонизатора, который регистрирует все классы тегов $meta = ClassScanner::find('regenix\libs\RegenixTemplateTag'); foreach($meta->getChildrensAll() as $class){ if (!$class->isAbstract()){ $instance = $class->newInstance(); $this->registerTag($instance); } }
Данный подход освобождает разработчика от ручного регистрирования каких-то классов-расширений и это довольно удобно.
Роутинг, URL, ЧПУ
Еще одной важной особенностью фреймворка является роутинг. Regenix использует отдельный файл для настроек роутинга, давайте рассмотрим пример такого файла:
# comment GET / Application.index GET /{action} Application.{action} POST /api/{method} api.Api.{method} * /clients/{id<[0-9]+>} Clients.detail
Выше описывается 4 правила для ройтинга, первая колонка это метод HTTP (POST, GET, PUT, PATCH и т.д.), вторая — путь к странице, который может состоять из динамичных частей, третья — название контроллера и его метод (разделяется через точку, можно использовать namespaces). Как видно из примера, поддерживаются регулярные выражения, а все динамические части передаются в контроллер в виде аргументов методов, например контроллер Clients:
<?php namespace controllers; use regenix\mvc\Controller; class Clients extends Controller { public function detail($id){ // $id придет из ройтинга } }
Кроме того, в фреймворке есть возможность писать шаблоны для роутинга в отдельных файлах, размещая их в папке /conf/routes/<name>.route
. Представим ситуацию, когда в REST архитектуре нам нужно постоянно объявлять похожие правила для роутинга, у нас имеются ресурсы с похожими по названию URL. Чтобы избавиться от дублирования кода, объявим новый шаблон для роутинга conf/routes/resource.route
:
GET / .index POST /create .create GET /{id} .show PUT /{id}/update .update DELETE /{id}/destroy .destroy
Далее, мы в главном файле роутинга можем использовать эти правила:
# PostApi и CommentApi это контроллеры * /posts/ resource:PostApi * /comments/ resource:CommentApi
Правила с префиксом resource
будут развернуты так как описано в шаблоне resource.route
.
Regenix также умеет проверять ошибки роутинга в случаях когда это явно можно проверить (например на существование класса и метода).
Контроллеры
Контроллеры в Regenix наследуются от общего класса regenix\mvc\Controller
. У всех контроллеров могут быть определены специальные методы для отлова событий: onBefore, onAfter, onFinally, onException, onHttpException, onReturn, onBindParams
. С помощью этого можно легко контролировать логику работы контроллеров. В добавок к этому, все контроллеры создаются с помощью DI. Давайте рассмотрим пример контроллера:
<?php namespace controllers; class Clients extends Controller { private $service; public function __construct(MyService $service){ // внедрение зависимости через DI $this->service = $service; } public function index(){ .... $this->put("var_name_for_template", $value); // добавляем переменную в шаблон $this->render(); // рендерим шаблон, в данном случае будет рендерится "Clients/index.html" } public function detail($id){ // $id - придет из данных роутинга или из $_GET параметра // также нам доступны: $this->request, $this->response, $this->body, $this->session, $this->flash, etc. } }
У базового класса контроллера есть набор методов render*
для вывода контента в различных форматах.
Интересная особенность этих методов в том, что они прерывают выполнения кода, использовать конструкцию return
нет необходимости.
Управление assets
А это отдельная история. Меня, как разработчика, утомляет постоянно искать различные клиентские библиотеки и постоянно их вставлять в каждый проект, запоминая их физический адрес. Поэтому в Regenix был встроен менеджер assets, чтобы избавить разработчика от этой рутины. Вы просто прописываете в конфигурации conf/deps.json список клиентских библиотек (jQuery, Angular, etc) и их версии, после чего набираете regenix deps update
и получаете все эти библиотеки. Вот пример файла deps.json:
{ "repository": "github:dim-s/regenix-repository/master", "assets": { "jquery": {"version": "1.*"}, "bootstrap": {"version": "2.*|3.*"} }, "modules": { }, "composer": { "require": { } } }
Здесь мы подключили jQuery и Bootstrap (хотя зависимость Bootstrap уже тянет jQuery). Как вы наверно заметили, в качестве источника зависимостей указывается репозитарий на github, да зависимости будут загружаться оттуда, а версии это регулярные выражения (всегда выбирается самая максимальная версия из возможных). Это довольно удобно, вы можете форкнуть официальный репозитарий и собрать свой набор клиентских библиотек, формат репозитария довольно прост. Также из примера видно, что есть возможно прописать конфигурацию для Composer, все его зависимости будут находится в папке src/vendor
отдельного проекта.
Для того чтобы подключить assets-зависимости в шаблон, есть специальная конструкция:
<html> <head> {deps.asset 'jquery'} <!-- будет подключен jquery --> {deps.asset 'bootstrap'} <!-- ... --> </head> </html>
При этом разрешаются конфликты и повторное подключение зависимостей. И это очень удобно!
Шаблонизатор
Шаблонизатор в Regenix имеет лаконичный синтаксис и компилируется в PHP код, при этом практически не происходит потери производительности. Основные фичи шаблонизатора Regenix:
- Экранирование HTML символов — любая динамическая вставка по-умолчанию экранирует вывод для безопастности
- Короткий и упрощенный синтаксис для PHP вставок — вместо
<?= ... ?>
->{ ... }
- Наследование, теги (html и php), различные include-подобные конструкции
- Фильтры (встроенные, возможность писать свои)
Приведу пример шаблона:
<!DOCTYPE HTML> <html> <head> <title>{get 'title'}</title> <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> {deps.asset 'jquery'} {deps.asset 'bootstrap'} {html.asset 'css/main.css'} {html.asset 'js/main.js'} </head> <body> <h1 class="title">{get 'subTitle'}</h1> <div id="content"> {content} </div> <div class="language"> <a href="{path 'Application.index', _lang: 'ru'}">Russian Version</a> / <a href="{path 'Application.index'}">Default Version</a> </div> {debug.info} </body> </html>
Почти заключение
Все возможности фреймворка описать в рамках одной статьи невозможно, поэтому я описал самые интересные и необычные возможности Regenix. Поэтому, далее я опишу как создать тестовый проект, с помощью которого вы сможете узнать о других более стандартных возможностях фреймворка, к тому же можно почитать документацию.
Создаем первый проект
Небольшая инструкция — как быстро установить и попробовать фреймворк. На данный момент Regenix можно скачать только через git, поэтому перед инструкцией его необходимо установить. Скопируйте все исходники фреймворка Regenix из репозитария с помощью git-bash:
cd <root_of_your_server> git clone https://github.com/dim-s/regenix.git ./ git submodule init git submodule update
После этих действий, у вас в папке должны появится следующие директории: framework — ядро фреймворка, apps — директория для ваших приложений. Все остальное не так важно. Фреймворк не требует какой-либо установки. Далее зайдите через консоль в папку веб сервера и используйте CLI чтобы создать новый проект из шаблона:
cd <root_of_your_server> # если вы под unix chmod +x install.sh ./install.sh #### regenix new
После выполнения regenix new
появится папка с вашим новым приложением в папке apps, оно будет открываться по адресу localhost/[name]
.
Структура проекта
Regenix предлагает свою структуру приложения, которую не всегда можно изменить. Да, в данном случае фреймворк главнее приложений, и не он встраивается в приложения, а наоборот. Это один из основных пунктов в идеологии Regenix.
Проекты находятся в папке /apps/
и каждая новая папка является новым проектом. Структура проекта следующая:
apps/<appName>/ * src/* # исходный код приложения src/controllers/ # контроллеры src/models/ # модели src/views/ # представления src/* # любые другие исходники и пакеты conf/ # папка с конфигурациями conf/application.conf # главный конфигурационный файл conf/route # конфигурация для роутинга conf/deps.json # описание зависимостей assets, модулей и composer conf/analyzer.conf # конфигурация анализатора исходного кода conf/orm/* # конфигурации Propel ORM assets/ # папка с клиентскими ресурсами css, js, images vendor/ # папка с библиотеками composer Bootstrap.php # файл bootstrap с классом Bootstrap, необязательный
Также за пределами папки проекта (в root директории) находятся другие директории:
/public/<appName>/* # папка с upload ресурсами проекта /logs/ # папка с логами /assets/ # assets зависимости /modules/ # модули фреймворка
Заключение
Это первое публичное освещение данного фреймворка. Сам проект еще находится в стадии разработки, у него еще нет своего сайта и полной документации, но 90% задуманных вещей уже функционируют и проверены небольшим временем.
Приглашаю всех кому понравился фреймворк к участию в проекте на Github: https://github.com/dim-s/regenix.
Документация: https://github.com/dim-s/regenix-documentation/
P.S. В проекте используются некоторые другие внешние библиотеки (vendors) — Symfony (Console, Process), Doctrine (только Cache), PHP-Parser, KCaptcha, Imagine, Propel ORM. Авторам этих библиотек огромная благодарность.
ссылка на оригинал статьи http://habrahabr.ru/post/196604/
Добавить комментарий