Regenix: Новый нестандартный MVC фреймворк для PHP

от автора

Приветствую всех. Хочу представить вам свой проект под названием Regenix.
image

Это новый 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), при добавлении нового источника классов (т.е. папки с исходниками), фреймворк производит сканирование и записывает всю найденную информацию о классах в кеш.

Особенности сканера классов:

  1. Нахождение классов вне зависимости от их именования
  2. Ленивая загрузка классов
  3. Возможность получить информацию о классе без его загрузки
  4. Возможность получить, например, всех наследников определенного класса (удобно для модулей)

Хочу заметить, что 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:

  1. Экранирование HTML символов — любая динамическая вставка по-умолчанию экранирует вывод для безопастности
  2. Короткий и упрощенный синтаксис для PHP вставок — вместо <?= ... ?> -> { ... }
  3. Наследование, теги (html и php), различные include-подобные конструкции
  4. Фильтры (встроенные, возможность писать свои)

Приведу пример шаблона:

<!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/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *