Зібрати найкраще з двох світів - фреймворків та CMS (частина 2)

Попередня стаття зібрала досить багато, часом досить різких, коментарів, друга частина розповість про зміни які відбулися протягом наступних 4-х місяців і по можливості не буде повторювати першу частину, яка все ще вельми актуальна.

Для чого

З минулої статті не всім було зрозуміло, для чого все це створюється, конкретна проблема, яку вирішує продукт.
Найпростіше пояснювати такі речі на прикладі. CleverStyle CMS не підійде якщо:

  • Під ваше завдання є CMS, яка вирішує задачу повністю
  • Під ваше завдання є CMS, яка майже підходить, ви її підпиляєте, оновлення вас особливо не турбують
  • У вас Enterprise проект
Підійде ж коли у вас проект, для якого немає готового рішення, а перепиливание чогось віддаленого схожого буде купою милиць, які потім неможливо буде відновити.

Singleton



Так само в коментарях багато разів згадувався «антипаттерн» одинак, тим більше що назви системного трейта цього ходило.
У загальному і цілому це не зовсім той одинак, про який можна було подумати.
Насправді це трохи більш складна штука, що забезпечує:

  • єдину точку створення системних об'єктів та об'єктів модулів
  • кастомізацію системних класів, починаючи від повної заміни, і закінчуючи підтримкою патчінга одного системного класу відразу кількома компонентами (докладніше
  • кешує викликаються класи, щоб навіть патчінг системних об'єктів істотно не позначався на продуктивності
Спершу здається, що це жахливо негнучкий інструмент, але насправді він дозволяє творити різні корисні речі, і вам не доводиться про це турбується при використанні.
У самому простому вигляді:

$Session = \cs\Session::instance();

Все що клієнтського коду потрібно знати — він отримає об'єкт сесії з передбачуваним публічним інтерфейсом, але це може бути не зовсім оригінальний системний об'єкт, або навіть зовсім не він.
Так само це дозволяє без будь-яких плагінів і додаткових анотацій генерувати підказки в IDE по всім публічним методів і властивостей системних об'єктів, що надзвичайно зручно.
Аналогія з Laravel:

$Session = $app->make('session')

От тільки тут для підказок IDE потрібно писати анотації.

А ще підмінений Singleton для тестів дозволяє замість повернутого об'єкта підсовувати що завгодно, і це активно використовується.

Composer



Було багато коментарів про Composer, PSR4 і з цим пов'язаних. Якщо трохи заглибитися в подробиці того, як встановлюються компоненти і на що впливають їх залежності, стає зрозуміло, що Composer м'яко кажучи не найкраще рішення для упаковки компонентів.
«Але ж він так зручний для установки бібліотек!» — скажете ви, і будете безсумнівно праві.
Підключати одну і ту ж бібліотеку кілька разів в складі різних компонентів і страждати з-за різних версій не кошерно.
Тому додатково до підтримки composer.json, composer.lock vendor в корені проекту з'явився окремий компонент з несподіваною назвою Composer!
У процесі використання взаємодія з самим Composer за умови що залежності не конфліктують зводиться до нуля.
Для того, щоб скористатися цією красою потрібно додати залежність від composer meta.json компонента, і прописати самі залежності, приклад для модуля WebSockets:

{
"package" : "WebSockets",
"category" : "modules",
"version" : "0.29.0+build-45",
"description" : "WebSockets server based on Ratchet and React with client-side bindings as well",
"author" : "Nazar Mokrynskyi",
"website" : "cleverstyle.org/cms",
"license" : "MIT License",
"db" : [
"метро"
],
"db_support" : [
"MySQLi"
],
"provide" : "websockets",
"require" : [
"System>=2.1",
"System<=3.0",
"composer"
],
"require_composer" : {
"cboden/ratchet" : "0.3.*",
"ratchet/pawl" : "0.1.*"
},
"multilingual" : [
"interface"
],
"hide_in_menu" : 1
}

В процесі установки компонента будуть зібрані Composer залежно всіх компонентів, складений фінальний composer.json, і якщо не виникне конфліктів — все встановиться саме, якщо виникнуть — консольний вивід Composer буде переформатований у HTML, і надано користувачу, нехай вирішує що з цим робити.

Ось такий composer.json генерує модуль для установки всіх залежностей:

{
"repositories" : [
{
"type" : "package",
"package" : {
"name" : "modules\/Http_server",
"version" : "0.8.0+build-13",
"require" : {"react\/http" : "0.4.*"},
"dist" : {
"url" : "\/web\/cscms.org\/www\/components\/modules\/Composer\/empty.zip",
"type" : "zip"
}
}
},
{
"type" : "package",
"package" : {
"name" : "modules\/WebSockets",
"version" : "0.24.0+build-38",
"require" : {
"cboden\/ratchet" : "0.3.*",
"ratchet\/pawl" : "0.1.*"
},
"dist" : {
"url" : "\/web\/cscms.org\/www\/components\/modules\/Composer\/empty.zip",
"type" : "zip"
}
}
}
],
"require" : {
"modules\/Http_server" : "0.8.0+build-13",
"modules\/WebSockets" : "0.24.0+build-38"
}
}

Віртуальні пакети оголошуються на місці, від них же відразу ставиться залежність, таким чином дозвіл конфліктів повністю лежить на стандартних механізми Composer (zip файл це єдине що потрібно мати реальне мати у файловій системі, він абсолютно порожній всередині).

Поділ логіки та подання




В ідеалі на сервері жодного уявлення.
Поки готово як приклад у клієнтській частині модуля магазину (нижче), хоча і буде оновлюватися з використанням JSON-LD для мінімального обсягу серверного коду і кращої індексації.
Зараз сторінка товару магазину в коді виглядає так:

<section data date="0" data-id="1" data-in_stock="24" data-price="20" data-soon="0" is="cs-shop-item">
<div id="images">
<img alt="" src="http://cscms.org/storage/public/Plupload/2015-01-03/18/2_031854a812c6b264b.jpg">
<img alt="" src="http://cscms.org/storage/public/Plupload/2015-01-03/18/2_035654a812ec26d24.jpg">
<img alt="" src="http://cscms.org/storage/public/Plupload/2015-01-03/18/2_035654a812ec1c834.jpg">
</div>
<div id="videos">
<a href="https://www.youtube.com/watch?v=rHBxJCq99jA"> </a>
<a href="https://www.youtube.com/watch?v=bmtbg5b7_Aw"> </a>
</div>
<h1>Boots</h1>
<div id="description">
<p>Nice boots</p>
</div>
<div id="attributes">
<table>
<tr>
<td>Size</td>
<td>2</td>
</tr>
</table>
</div>
</section>

Тобто не має нічого спільного з тим, як воно виглядає на сторінці, як це влаштовано теж згадувалося.

Стиль кодування




Те, що пропонують PSR мені не дуже подобається, тому стиль кодування був трохи оновлений вікі, додатково тепер в репозиторії лежать файли конфігурації стилю кодування та інспекцій PhpStorm, при відкритті проекту він відразу буде налаштовано належним чином.
Всі нові файли форматуються цим стилем, старі файли при редагуванні теж.
Прохання поважати стиль автора проекту)

Рефакторинг




У проміжку від версії 1.0 до порядку наводилося ядро, в результаті обширного рефакторінгу система стала істотно зрозуміліше і більш передбачувана, а так само стали можливими деякі функції, як робота в Request/Response режимі (про що далі).

Глобально:

  • клас cs\Trigger був перейменований в cs\Event, щоб більше не збивати з пантелику, так само був спрощений і з'явилися нові можливості, як то одноразова підписка на подію, як jQuery.fn.one()
  • додатково з'явився cs.Event на фронтенде з тими ж методами, порядком аргументів що і cs\Event на сервері
  • cs\Session утворився після чергового рефакторінгу cs\User, дозволяє додатково прискорити роботу в асинхронному режимі
  • cs\Route об'єднав функціональність, що відповідає за маршрутизацію, яка з історичних причин була одночасно в cs\Config cs\Index, що було далеко не очевидно
  • $_SERVER обертається в массиво-подібний об'єкт для простоти отримання потрібної інформації незалежно від конфігурації, це дозволило позбутися від дублювання коду
  • \ExitException використовується замість exit/die в тих рідкісних місцях, де вони були, сторонні бібліотеки легко патчатся автоматичним пошуком та заміною для підтримки цієї функціональності, критична фіча для режиму Request/Response
  • деякі вбудовані функції, які працюють з глобальним контекстом, були замінені на обгортки (header() -> _header()), сторонні бібліотеки легко патчатся автоматичним пошуком та заміною для підтримки цієї функціональності (або якщо використовуються простору імен — просто оголошується користувацька header() в тому просторі), критична фіча для режиму Request/Response
Безліч інших змін перераховувати немає сенсу, release-notes.md понад 480 рядків з детальним описом ключових змін і рекомендаціями до плавного оновлення.

Частково отрефакторен системний модуль, але тільки частково. Більше рефакторінгу красивого і різного ще буде.

Статичний аналіз




Раніше весь статичний аналіз полягав в інспекціях IDE PhpStorm, зараз же кожен отримати додатково перевіряють SensioLabsInsight і Scrutinizer.
Ці два інструменти творять чудеса статичного аналізу. На поточний момент виправлені всі Major недоліки, які вони понаходили, і частково Minor/Warning.
Інструменти активно використовуються, їх звіти будуть зменшуватися з кожним комітом.

Релізи




Починаючи з 1.110 всі збірки автоматизовані, у разі проходження тестів після кожного коміта нічна збірка відлітає на SourceForge в папку nightly, якщо це реліз — збирається релізна версія і падає в stable/{version} там же.
Це спрощує релізи та прибирає всі ті незручності, які виникали з публікацією релізів у вигляді сторінки з посиланнями на файли в Dropbox.

Нові фічі




По-перше, деякі компоненти, які вже досить давно розроблялися і вважаються стабільними зросли до версії 1.0.
По-друге, було б прикро констатувати що з коробки ніякої нової функціональності за 4 місяці не з'явилося.

Http сервер
Одного разу вже згадувалося тут. Це модуль, що реалізовує Http сервер на PHP, що дозволяє в рамках одного процесу обробляти безліч запитів і досить непогано позначається на продуктивності (в кілька разів).
Якщо дотримуватися кілька нескладних правил, то всі компоненти будуть працювати в цьому режимі без змін.

WebSockets
Теж було тут, тісно інтегрує WebSockets з CleverStyle CMS, дозволяючи відправляти дані клієнта і назад практично в реальному часі без зайвого навантаження, за принципом пристрою схоже на модуль Http сервера.

Магазин
З'явився модуль магазину. Зроблена спроба створення модуля загального призначення, тобто з коробки немає функціоналу накопичувальних знижок, акцій, спецпропозицій і всіляких інших речей.
Тим не менш модуль має набір подій, за допомогою яких все це досить просто можна реалізувати саме в тому вигляді, який вам потрібен.
Так само вся клиенсткая частина побудована на веб-компонентах, і змінюється абсолютно будь-яким можливим способом, ви обмежені лише своєю фантаизей (при цьому ніяких традиційних шаблонів немає і не буде).

Оплата Bitcoin
Модуль магазину підтримує підключаються системи оплати за допомогою інтерфейсу досить загального призначення. Цей модуль першим реалізує цей інтефейс, надаючи можливість оплати Bitcoin (присутній автоматична конвертація деяких валют за поточним курсом).

Підсвічування синтаксису
Як-то в блозі потрібна була підсвічування синтаксису, з'явилася інтеграція бібліотеки Prism для цих цілей. Бібліотека, як і всі інші, пропатчена для роботи з веб-компонентами, дружить з візуальними редакторами.

Наостанок




Система активно розвивається, код стає чистішим, простіше, зрозуміліше, обростає новою функціональністю, постійно поповнюється і підтримується актуальною документація.

Зворотна сумісність зберігалася всю гілку версій 1.x, версія 1.110 була останньою з цієї серії.
Застарілий код нещодавно був вилучений у зв'язку з переходом на 2.х версії, так само мінімальна вимога до версії тепер PHP 5,5+.
За умови, що всі рекомендації по оновленню виконувалися, оновлення з 1.110 до 2.x досить тривіальне.

Найпростіше запустити і спробувати з допомогою Docker
Весь вихідний код на GitHub, там же wiki з документацією.

Джерело: Хабрахабр

0 коментарів

Тільки зареєстровані та авторизовані користувачі можуть залишати коментарі.