ZExt PHP Framework

Данным постом хочу представить IT-сообществу свой давний проект: PHP фреймворк «ZExt».

В результате многолетней работы в различных проектах у меня накопилась библиотека, так сказать, всяческих полезностей, облегчающих повседневный труд программиста. Некоторые компоненты данного фреймворка являются частями корпоративного фреймворка компании viboom.ru в которой я проработал продолжительное время создавая эти компоненты. От руководства компании было полученно согласие на публикацию части исходного кода фреймворка. В последнее время я провёл определённую работу по «причёсыванию» фреймворка и теперь готов его представить сообществу в надежде, что вы найдёте чего либо полезное для себя в компонентах фреймворка.

Фреймворк представляется «как есть» и его автор не несёт ответственности за его использование.
Репозиторий на GitHub.

Фреймворк требует PHP версии не ниже 5.4.
Для работы компонентов требуется добавить пространство имён «ZExt» в автозагрузку классов (PSR-0) по пути: «my_app_library/ZExt».

Можно воспользоваться собственным автозагрузчиком классов фреймворка:
require 'my_app_library/ZExt/Loader/Autoloader.php';

ZExt\Loader\Autoloader::registerDefaults();


Так же можно добавить фреймворк через Composer:
{
	"require": {
		"zext/zext": "dev-master"
	}
}


Возможности


Фреймворк предоставляет средства работы с базами данных: ORM для работы с MongoDB, надстройка над Phalcon ORM.
Кеширование данных с поддержкой тегов.
Конфигурация приложения.
Средства работы с зависимостями компонентов приложения (Dependency Injection).
Средства отладки и профилирования приложения.
Форматирование чисел, дат.
Подстветка кода.
Помощники построения HTML-кода и вывода информации в консоль.
Средства интернационализаци.
Средства страничной навигации.
Автозагрузчик классов.
Ряд архитектурных компонентов: система мапперов, моделей и коллекций, валидация в моделях, ряд трейтов упрощающих работу с зависимостями, кешированием, логгированием, помощниками и т.д.

Теперь немного о его компонентах:

Debug


Компонент представляющий набор средств для отладки PHP-приложений.
Может использоваться в любом приложении вне зависимости от используемых в нём фреймворков и прочих технологий.
Использует jQuery подключенный в вашем проекте или, при его отсутствии, подключает сам через GoogleApis.

Подключение отладочной панели с параметрами по умолчанию:
$debug = ZExt\Debug\DebugBar::initDefaults();

Вывод информации производится в нужном месте (на пример в скрипте вида (view)) через приведение объекта отладчика к строке:
echo $debug;

Результатом работы отладчика будет вот такая панель:


Попробуем бросить исключение:
throw new Exception('Looks like an error occurred...', 100);

При этом отладчик, перехватив его, вернёт отладочную информацию в качестве ответа на запрос:

Слева появился элемент «Exception» с информацией о брошенном исключении.

Совершим не фатальные ошибки:
echo $undefinedVar;

trigger_error('something wrong');



Profiler


Компонент отвечает за профилирование различных действий приложения и представляет информацию о времени и результате выполнения этих действий.

Сымитируем обращение к некому сервису приложения и добавим профилировщик в панель отладки:
$profiler = new ZExt\Profiler\Profiler();

$profiler->startRead('Database read');
sleep(1); // Read from some service
$profiler->stopSuccess();

$profiler->startWrite('Database write');
sleep(1); // Write to some service
$profiler->stopError();

$profiler->setName('Database')
         ->setIcon('db');

$debug->addProfiler($profiler);

Теперь посмотрим результаты:


Html


Компонент призван облегчить создание различных HTML-конструкций.

Возмём тег с большим количеством атрибутов:
$tag = new ZExt\Html\Tag('iframe');

$tag->width       = 640;
$tag->height      = 480;
$tag->frameborder = 0;
$tag->scrolling   = 'no';
$tag->src         = 'page.php';
$tag->id          = 'frame';

echo $tag;

<iframe width="640" height="480" frameborder="0" scrolling="no" src="page.php" id="frame"></iframe>

Список:
$list = new ZExt\Html\ListUnordered();

$list->id    = 'list';
$list->title = 'My list';

$list[] = 'Item 1';
$list[] = 'Item 2';
$list[] = 'Item 3';
$list[] = 'Item 4';

echo $list;

<ul id="list" title="My list">
<li>Item 1</li>
<li>Item 2</li>
<li>Item 3</li>
<li>Item 4</li>
</ul>


Планы развития


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

Если сообществу будет интересен представленный проект, я буду продолжать публиковать гайды по работе с компонентами фреймворка и архитектурными решениями в которых фреймворк участвовал.
Поделиться публикацией
Похожие публикации
AdBlock похитил этот баннер, но баннеры не зубы — отрастут

Подробнее
Реклама
Комментарии 24
  • +4
    Насколько я понял по описанию — фреймворк предоставляет средства отладки и хелперы html. =)

    Предлагаю хотя бы кратко описать возможности, т.к. репозиторий не маленький и работы судя по всему было проделано много: github.com/mikemirten/ZExt/tree/master/library/ZExt
    • 0
      Вы правы. Добавил краткое описание возможностей.
      В будущем планирую подробно осветить возможности компонентов и их использование.
    • +5
      Может кто объяснить, в чем профит конструирования HTML через объекты? Это же медленно и неудобно. Скажем тот же пример с iframe или списками. Никакой критики, просто любопытство.
      • 0
        Ну это абстракция. При конструировании, допустим форм — можно аттачить на лету данные из моделей, как реализовано в Laravel, автоматом добавляется csrf токен и прочие мелочи.
        • 0
          Вы предлагаете верстальщикам писать код, а не делать верстку?
          • –1
            Это всё таки инструмент программиста, а не верстальщика. Он может быть использован на пример в каком либо декораторе, абстрагируя логику от представления.
            • +1
              Может быть пример просто слишком простой, но даже по API это констркутор HTML. Да, можно добавлять свои штуки туда, инджектить дополнительное поведение — но это можно делать и с шаблонами и не извращаться до такой степени.
            • 0
              Я предлагю верстальщикам использовать то, что им будет удобнее в том или ином случае.
            • 0
              С формами все понятно и все ясно. Но там так же HTML выносится в шаблоны, абстракции обычно над типами инпутов и основная цель таких абстракций — биндинг данных модели на формы и обратно. А то что у вас — это ИМХО избыточная абстракция, PHP ради PHP.
              • 0
                Ну, допустим, не у меня ( у автора) и мне подход выкидывания всего в php не нравится, но постараться оправдать (или предположить) могу — просто обычный принцип разделения кода (что бы не смешивать html и php — раз в 100 лет такое бывает надо), доведённый до абсурда =)
                • 0
                  Я понимаю вашу точку зрения и во многом согласен с ней.

                  Но иногда, на пример, возникает дилема: создать шаблон ради вывода одного тега, передав в него значения атрибутов, или описать всё в хэлпере или декораторе. Количества кода в последнем будет практически одинаковым, так же будет абстракция от представления, а вот создание шаблона ради вывода одного тега действительно может попасть под определение «PHP ради PHP».

                  Всё зависит от ситуации. Я лишь предложил один из вариантов решения.
              • +1
                Иногда возникает потребность собрать некоторые HTML-конструкции с большим количеством аттрибутов, часть из которых добавляется по различным условиям, значения которых могут подставлятся из моделей и прочих провайдеров данных. Получается нечто находящееся на стыке бизнес-логики и представления. Если разместить это в скрипте представления, он будет перегружен конструкциями вида "<?php if (condition): ?>", "<?= $model->property ?>" внутри тэга. Если разместить в контроллере или хэлпере, получится каша из конкатенций частей HTML-кода.

                Для примера:
                $tag = '<div attr1="value"';
                
                if ($needAttr2) {
                    $tag .= ' attr2="' . $attr2Value . '"';
                }
                
                $classes = [];
                
                if ($active) {
                    $classes[] = 'active';
                }
                
                if ($warning) {
                    $classes[] = 'warning';
                }
                
                if (! empty($classes)) {
                    $tag .= ' class="' . implode(' ', $classes) . '"';
                }
                
                $tag .= '></div>';
                


                Против:
                $tag = new Tag('div');
                
                $tag->attr1 = 'value';
                
                if ($needAttr2) {
                    $tag->attr2 = $attr2Value;
                }
                
                if ($active) {
                    $tag->addClass('active');
                }
                
                if ($warning) {
                    $tag->addClass('warning');
                }
                
                • +2
                  Вы бы сделали Fluent интерфейс для тегов. Было бы здорово:

                  $tag->attr1('value')->attr2($needAttr2, 'value')->addClass('class3');
                  

                  • 0
                    Уже реализованн в следующем виде:

                    $tag = new Tag('p');
                    
                    $tag->setAttr('data-pk', 123)
                        ->setAttr('data-name', 'John')
                        ->addClass('has-comments');
                    


                    На счёт варианта с именами аттрибутов в качестве имён методов подумаю.
                    Спасибо за идею.
                  • 0
                    А если третий вариант?

                    <div data-attr1="value" 
                             {% if needAttr2 %} data-attr2="value" {% endif %} 
                             class="{{ className({active: active, warning: warning})  }}">
                    </div>
                    


                    // экстеншен-хелпер
                    // ключь - имя нашего класса, значение - условие, когда его нужно отображать
                    function className(array $classes = array()) {
                        return array_keys(array_filter($classes, function ($enabled) {
                            return $enabled;
                        }));
                    
                    }
                    
                    • 0
                      Вообще лично я не так уж частно сталкивался с подобным (кучи условий и прочее) и обычно я решал эту проблему за счет выноса всего этого в макрос, или нечто подобное (в зависимости от проекта). Таких ситуаций у меня было… ну несколько, и чаще всего это были формы. Так вот, если брать тот же Twig, за счет наследования шаблонов, возможность импорта различных макросов, гибкости в плане расширения синтаксиса — все эти архаичные классы типа CHtml/Tag и прочее не нужны. Да они и раньше не особо то нужны были.
                      • 0
                        Вариант конечно имеет право на жизнь, но вы не находите, что в сумме это более сложная конструкция и менее «читабельная»?
                        • 0
                          эта конструкция намного проще вашей (что вариант с конкатенацией, что вариант с конструктором), метод хэлпер реализуется один раз, покрывается тестами и уходит на покой и больше не мельтишит. А количество кода на тэг существенно уменьшается, что должно давать профит при поддержке. По сути ваш вариант помогает избежать ошибок конкатенации, это единственный вариант при котором я вижу существенный профит. Но если избавиться от канкатенации на корню, проблемы такой и не будет вовсе.

                          По сути ваш код — это прокси-код, который можно генерировать автоматически на основе шаблонов, таким образом избегая потенциальных ошибок.
                          • 0
                            Хорошо, давайте разберём вашу конструкцию.

                            Где и как будет распологаться логика определяющая появления классов в конструкции ниже?
                            {{ className({active: active, warning: warning}) }}

                            Аттрибут «class» будет висеть всё время, даже пустой?
                            Я конечно понимаю, что он ничего не испортит, но по моему это не есть хорошая практика.

                            Если вы полностью опишите необходимую логику, кода в шаблоне станет заметно больше, читаемости меньше.
                            И вам в любом случае нужен шаблон, даже ради вывода единственного тега.
                            Да ещё и екстеншн, пусть и написанный один раз.

                            Нет уж, извините, но я в этом не вижу более простого решения.

                            Я предлогаю описать в неком декораторе, а именно для таких случаев предлогается моё решение, несколько вызовов устанавливающих аттрибуты и классы с нативными PHP-условиями и всё.
                            Вы же предлогаете создать шаблон, поместить в него эту логику, создать хэлпер, поместить в него ещё часть логики и вызывать хэлпер из шаблона а шаблон из декоратора.

                            Ок. Давайте сойдёмся на том, что у нас с вами разный взгляд на решение одного и того же вопроса и оба решения имеют право на жизнь.
                  • –2
                    Отличный фреймворк, уже год с ним работаю, действительно облегчает жизнь php программиста ))
                    • 0
                      Это мое ИМХО, я действительно пользуюсь этим фреймворком и я написал об этом.
                      Фреймворк обкатан на продакшене, под нагрузками, mysql + memcache + mongo, проект крутится на нескольких серверах, настроена репликация, лоад балансеры, работаем в моного с коллекциями по 500Гб.
                      Так же, в этом фреймворке, есть хороший удобный профилер, который очень облегчает жизнь в бою.
                      Лучше бы вопросы по работе либы задавали и чего в документации не хватает.
                      Не хотите разбираться? Не хотите доку читать? Так не кто ж не навязывает, — просто пройдите мимо ))
                    • 0
                      1) Какого рода проекты делаются на этом фреймворке: хайлоад, сайты со сложной бизнес-логикой, обычные сайтики?
                      2) Что с шаблонизатором?
                      3) Опубликуйте на packagist что ли. А то так несерьезно.
                      4) Зачем свой автозагрузчик, если есть в Composer?
                      5) composer.json гол как сокол. Неужели все компоненты сами честно свелосипедили? Зачем?
                      • 0
                        1) Основной проект указан в тексте поста. В двух словах: относительно хайлоад со сложной бизнес-логикой.

                        2) Использовался шаблонизатор стороннего фреймворка, в частности: Phalcon. В посте описанно, что фреймворк изначально был не более чем библиотекой расширяющей возможности некоторых фреймворков.

                        3) Согласен. Это в ближайших планах.

                        4) На пример, что бы дать возможность использовать фреймворк в проекте без композера. Были и другие причины.

                        5.1) Чего конкретно вам не хватает в composer.json?
                        5.2) Что именно вас удивляет? Что можно вот так взять и самому, честно писать код? )
                        5.3) Это была моя работа, за это платили деньги. Кроме того я люблю своё дело.
                      • +1
                        >> 4) На пример, что бы дать возможность использовать фреймворк в проекте без композера

                        По мне, так всех надо насильно пересаживать на composer. Всем лучше будет, если он будет стандартом веб-разработки.

                        >> 5.1) Чего конкретно вам не хватает в composer.json?

                        Есть посмотреть даже такого монстра как Laravel, то там огромный список внешних зависимостей. А у вас прямо совсем все свое))

                        >> 5.1 5.2 5.3

                        Я понимаю, когда пишут свой IoC.
                        Я очень понимаю, когда пишут свою реализацию MVC, Requesting, Routing.
                        Но честно, никогда не понимал, зачем пишут свои Cache, Session, Validator и прочее, не говоря уже об ORM или шаблонизаторе. Чем ваша реализация Cache, Session, Validator принципиально отличается от тонны подобных либ на гитхабе? Не проще было взять готовые решения? Тем более выбор-то достойный.

                        Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.