Комментарии 77
"Современненько", но слишком усложнено
Не "есть хорошо" во View делать вот такие вызовы
$data = (new EntityCommentData($comment, false))->make();
Во View (шаблона фактически) лучше отправлять уже "рассчитанные" данные контроллером
Т е архитектура все равно с "костылями"
Данный участок кода будет переработан, везде модели инициируются и выполняют все необходимые действия в рамках контроллера.
Я бы еще советовал сделать переносимый контроллерами registry обьектов
Чтобы не было вот такого: Str::likeEmpty($tagName)
Тогда будет $this->registry->str->likeEmpty($tagName)
Как то архитектура будет более унифицирована
И тогда не надо будет делать в контролерах new… (new там тоже как то коряво выглядит)
Короче есть еще над чем подумать вам
Значит я очень невнимательно прочёл
# установим глобальный asset плагин
composer global require "fxp/composer-asset-plugin:1.2.*"
# выполняем установку ffcms в ./path/to/root
composer create-project phpffcms/ffcms ./path/to/root 3.0.0 --keep-vcs
# загрузка последних обновлений
composer update
# инициализация консольного установщика
php console.php main:install
Развлекайтесь ;)
В e-commerce фактически кроме Magento и Opencart ничего стоящего по архитектуре нет
Остальные — сплошной архитектурный говнокод
Но составить им конкуренцию уже практически невозможно, уж очень они хороши
Это вы не заглядывали в него. Я с ним каждый день "сплю". Вот не рассказывайте мне про opencart и тем более про г… престу, cs… и т.п. Вы еще скажите что в битрикс "архитектура" есть...:)
лапша код там в опенкарте, млять тонна одинаковых шаблонов распиханных по папкам, 6 шагов регистрации юзеру, 5 форм отображения одних и тех же данных "информация о пользователе".
нет быстрого заказа, а править корзину нааяксенную через все ядро...
Престашоп не имеет в коробке самовывоз. Я промолчу.
Ну сразу видно что в opencart вы полный дилетант.
Даже и комментировать не буду
Видел звон — не знаю где он. "Раз установил"
В общем, не хочу материться, но на этой штуке можно что-то сделать, красивый MVC, да, но поддерживать её — свят-свят-свят!
Opencart приведен в соответствии с законодательствам многих стран, где обязательным считается поэтапное оформление заказа и регистрация данных о покупателе. Быстро учить мат. часть e-commerce систем а не умничать здесь
В opencart существует большое множество модулей одно страничного оформления заказов как и быстрая регистрация в "пару" полей. Если законодательством вашей страны разрешено одно страничное оформление заказа с минимальными данными о покупателе — устанавливайте, там сложного ничего нет, таких модулей валом
Я работал несколько лет с опенкартом, сопровождал пару магазинов, прочувствовал все прелести обточки напильником этого "алмаза" с модулями и без модулей, платными и не платными. Работал и с битриксом.
Напомните, в каком году OC вышел, в 2011? С тех пор он не поменялся вообще, если не считать бутстрапа со 2 версии и мелочей, которые ничего не сменяют кардинального. То что он рука об руку идет с vqmod уже все объясняет.
Серьезно? :) Не менялся?
Ну конечно, не специалист кроме boostrap-a больше ничего не увидит.
Там глобальные изменения на уровне архитектуры, кода.
И нету vQmod -а уже, уже забыли про него давно.
Знаете, судя по вашим ответам, вы всё видели "издалека" и "пару раз"
Мне если честно, как руководителю IT проектов e-commerce систем (senior), смешно читать ваши ответы. Ну ладно бы студент такое писал, но в профиле у вас стоит "тех. директор" (чего правда?) И такие ляпы выдаете.
В общем то я вас понимаю. Если вы руководитель — веры терять нельзя. Пишу без сарказма.
У меня с этим делом все самоубийственно плохо.
Это демагогия с вашей стороны.
Когда за спиной 20 лет разработок и большое портфолио в веб разработке (и кстати своя cms как у автора тоже есть, и на которой десятки проектов крутились) и работа на всех cms и fw — то здесь нет выбора — он один в e-commerce: Magento или opencart
Всё
Magento для серьезных проектов
Opencart для простых и средних (которых 99%)
Конкурентов то нету :)
woocommerce с его неандертальским говнокодом? Или битрикс у которого понятие архитектура отсутствует напрочь, но агрессивный маркетинг. Преста с говно архитектурой? Остальные я рассматривал детально — там вообще ужас.
Никто и близко не встал по архитектуре с opencart и magento
Но вы не специалист в области архитектуры — это и так видно. Вам она просто не понятна. Для вас архитектура — это код. Не путайте грешное с праведным.
Дискуссии над предметом, который приносит хлеб, заведомо бессмысленны. Вы его всегда будете защищать выдавая личные предпочтения и опыт за плюсы, а если кто-то несогласен — дилетантство.
Работать с битриксом мне куда удобнее, хоть я его терпеть не могу.
Умоляю!
Займите нишу!
Это дерьмо вроде опенкарта и престы ожирело и застряло в норе как винни-пух! Я кровью обливаюсь когда меня просят совета, а что я скажу? Шлю к мерчиуму какому нибудь. Хоть глаза бы не видели мои больше кода этих cms.
Из опенсурсного в екоммерсе НЕТУ НИЧЕГО нормального вообще! Кучу лет!
Толпа просто попрет как только пойдут слухи о минимальстичном современном движке интернет магазина.
Если вы не работали с opencart — то давайте не умничать.
По вашим ламерским ответам об opencart я очень быстро понял "who is who" вы. А о наборе кармы по "перепечаткам" тем более "всё с вами ясно"
Либо у вас какой-то другой opencart, либо развился стокгольмский синдром. Можно говорить, что опенкарт лучше <другой ecommerce solution name>, но код оставляет желать лучшего.
Несколько примеров:
- контроллеры прибиты гвоздями к вью, к конкретному шаблону. Пример: попробуйте разобрать ajax-овый аккордеон в чекауте на отдельные странички, и посмотрите, сколько придется править в контроллерах.
- в каждом методе каждого контроллера есть десятки строк кода, просто пробрасывающие строки из language во view
- километры копипащенных полей в формах view безмолвно вопиют. Обработка custom fields в тех же вью добавляет свою мощную ноту в том хоре.
- используется давняя хорошая традиция защищаться от XSS путем HTML-эскейпа записей в базе данных
- как устанавливаются 100500 обещанных нам расширений? Путем накатывания патча на код!
Всё закончили. Ваш бред, даже не хочу комментировать
Вы даже не понимаете о чем пишите
О стандартизации и унификации вы даже понятия не имеете. И для вас в шаблонах таскать "вычисления" — это нормальное дело я так понял, но только не для профи, и не для нормальной архитектуры
И ничего править не надо — перехватил хуком loader и подставляй любые свои значения, любые шаблоны.
Да это и не надо. Так как все унифицировано и стандартизировано.
Насчет патча на код — это уж вообще рассмешили. Сразу видно "смотрел поверхностно давно".
Там давно уже есть система ивентов, а оверлорд хуки можно было делать еще в 1.5,x. (в архитектуре это заложено — но вам это не понятно видно было) Хочешь пользуйся не хочешь не пользуйся — есть выбор. Есть квалификация — пользуешься всей мощью архитектуры, нету — пишешь "ваш" бред. И причем здесь escape XSS к БД, все параметры очищаются еще на точке входа, escape — это просто контрольный выстрел и признак хорошего тона, там большего и не надо уже ничего
Если вы не специалист то даже не поймете, что opencart даже в 1.5.x можно было не использовать vqmod. vqmod — это для учеников, домохозяек, дилетантов, блондинок и за счет них популяризации opencart
Я не спец по OC, но вот открыв рандомный файл, я как-то уже не очень горю желанием его изучать:
https://github.com/opencart/opencart/blob/master/upload/catalog/controller/product/product.php
Ну а с точки зрения архитектуры. Давайте пообщаемся про разделение и связывание, очередя, микросервисы, котейнеры, масштабирование. А так: с какой-то то там версии добавили систему ивентов. Это вряд ли можно назвать архитектурой, просто костыли, которые лучше оверлоад и которые были проверены и вдоль и поперек откатаны задолго до 2011 года, не понятно почему они не использовались в проекте изначально.
Давайте вы вначале изучите и поработаете хотя бы годик с opencart — потом обсудим
Ok
А так это бесполезный треп — как с Alexufo — который поверхностно с ним знаком
ну как поверхностно. Я перепиливал шаблон полностью, прокидывал новые поля в адмику, и удивился как в битриксе удобнее вставлять компоненты вместо правки сотен вьюх с их сотнями контроллеров. Я устал просто бродить по иерархии OC.
Нельзя просто так взять и сделать тему с 0 в OC. Я не понимаю предназначение тем, где обязательными являются одновременно сотня файлов.
И сделал вывод — OC не сделан для кастомизациии тем, если не считать кастомизацией перебивание цветов в css.
Почему? Можно спокойно делать css только или для одного файла
Поверхностно видно и из этого поста
Делаете папку с темой но не все файлы переписывает а только header.tpl и stylesheet
В header.tpl меняете только путь к stylesheet
Всё
Не знаю что вы там чудили еще
В контроллерах стоит же проверка есть ли файл в папке кастомной темы если нет брать с default
Надо изменить какой то шаблон в своей теме — берете только нужный файл
Какие проблемы то :)
Мне нужна тема которую я сам хочу. Никакие другие папки и шаблоны не нужны. В теме 170 файлов вьюх Это для кого?)
Мне нужно пара другая шаблонов куда я хочу прикрутить компоненты типа корзин, каталога, правки профиля с адресом, и еще несколько форм. А ОС не позволяет ни менять название шаблонов ни удалять их, я уж молчу про соблюдение папочной структуры и бесконечного прыгания по ним в поисках нужного места в шаблоне. Там профиль юзера выводится разными вьюхами в разных местах.
Либо переписывай все ядро, либо вся кастомизация это правка цветов в css. Меня это не устраивает. Меня темизация в wordpress устраивает.
Мне не нужно ни сравнение товара, ни страница производителей, тьма каких то шаблонов оплаты которой нет. я хочу сделать чистый шаблон который меня устраивает а не архитектуру движка. В OC с этим плохо. Поэтому все темы выглядят 1 к 1 — так дешевле.
а что же тогда, если она контент менеджмент товаров позволяет делать?
По сути то одна фигня, сущность — товар или запись.Ввод и вывод. А дальше куча возможных сортировок, группировок, фильтров на отображении.
:) А что это? Ой… как с "вами" тяжело (у одного квалификации ноль в opencart — уже раздает "советы" и строит "мнения", второй просто "умник", теритий не читает мат. часть, но зато все "вопят")
Вы вообще знаете что такое CMS?
"система управления содержимым" — понимаете?
opencart — управляет содержимым.
Это CMS
PHP e-commerce CMS
Я же написал как, в чем проблема то
Новая тема — переписываете туда только файлы которые изменяете — всё
Вы понимаете суть унификации и стандартизации? Я вижу что нет, как и 99.99% здесь. Я как то статью писал здесь — " Мы плюём на стандарты" — 99% ответов было "а зачем они надо" и куча малолеток нах… ла минусов
Если вы хотите вообще сделать поля шаблонов для контроллеров — не вопрос. Есть куча модулей бесплатных которые это делают. Но это костыльно и НЕ правильно. И они не нужны (можно даже посмотреть по количеству скачиваний их
О какой унификации речь)))))))))))), если 99% тем для опенкарта это "замаскируй под современный магазин OC c помощью css"?
Хочешь перенести поиск в футер? лезть в контроллер, назначай вывод туда!
И так абсолютно с каждым выводом.
А теперь вспомни что и контроллер это тоже 170 файлов в 9 папках!
Итого: для кастомизации темы нужно работать минимум с 300 файлов раскиданных в 18 папках!
Показатель гибкости — это обьем тем, по которым не ясно, что за движок. В случае ОС это определяется сразу. Как таковых тем по ОС нет и не было, есть костыли над теми же 170 файлами в 9 папках.
Меня не устраивает ни привязка к папкам, ни огромное количество копипаста, ни разделение шаблонов. Про отсутствие ЧПУ я даже не говорю. Я знаю что значит делать темы для OC и пресса. И последний даже рядом по гибкости ставить не хочеться.
Можно назвать это унификацией, стандартизацией, дилетанством. Да. Только это не снимает абсолютно никаких вопросов.
:)
Смешно — хочешь перенести поиск вниз — не надо ничего править. Кто вас такому "учил"?
Сразу видно — не специалист
Далее даже не хочется и читать ваши "потуги" чего то "понять"
Глянул…
https://github.com/opencart/opencart/blob/master/upload/catalog/controller/product/product.php#L229
$data['text_select'] = $this->language->get('text_select');
$data['text_manufacturer'] = $this->language->get('text_manufacturer');
$data['text_model'] = $this->language->get('text_model');
$data['text_reward'] = $this->language->get('text_reward');
$data['text_points'] = $this->language->get('text_points');
$data['text_stock'] = $this->language->get('text_stock');
$data['text_discount'] = $this->language->get('text_discount');
$data['text_tax'] = $this->language->get('text_tax');
$data['text_option'] = $this->language->get('text_option');
$data['text_minimum'] = sprintf($this->language->get('text_minimum'), $product_info['minimum']);
$data['text_write'] = $this->language->get('text_write');
$data['text_login'] = sprintf($this->language->get('text_login'), $this->url->link('account/login', '', true), $this->url->link('account/register', '', true));
$data['text_note'] = $this->language->get('text_note');
$data['text_tags'] = $this->language->get('text_tags');
$data['text_related'] = $this->language->get('text_related');
$data['text_payment_recurring'] = $this->language->get('text_payment_recurring');
$data['text_loading'] = $this->language->get('text_loading');
$data['entry_qty'] = $this->language->get('entry_qty');
$data['entry_name'] = $this->language->get('entry_name');
$data['entry_review'] = $this->language->get('entry_review');
$data['entry_rating'] = $this->language->get('entry_rating');
$data['entry_good'] = $this->language->get('entry_good');
$data['entry_bad'] = $this->language->get('entry_bad');
$data['button_cart'] = $this->language->get('button_cart');
$data['button_wishlist'] = $this->language->get('button_wishlist');
$data['button_compare'] = $this->language->get('button_compare');
$data['button_upload'] = $this->language->get('button_upload');
$data['button_continue'] = $this->language->get('button_continue');
$this->load->model('catalog/review');
$data['tab_description'] = $this->language->get('tab_description');
$data['tab_attribute'] = $this->language->get('tab_attribute');
$data['tab_review'] = sprintf($this->language->get('tab_review'), $product_info['reviews']);
$data['product_id'] = (int)$this->request->get['product_id'];
$data['manufacturer'] = $product_info['manufacturer'];
$data['manufacturers'] = $this->url->link('product/manufacturer/info', 'manufacturer_id=' . $product_info['manufacturer_id']);
$data['model'] = $product_info['model'];
$data['reward'] = $product_info['reward'];
$data['points'] = $product_info['points'];
$data['description'] = html_entity_decode($product_info['description'], ENT_QUOTES, 'UTF-8');
Вам вопрос, как специалисту по архитектуре, такое в каждом контролере?
:) Вот я так и знал про этот вопрос
Да по "детству" его часто задают — но там все продумано и сделано согласно стадартов
Если сами ответите поставлю пятерку
Что здесь не понятного "почему"?
Детский вопрос.
Даю наводку — "мухи отдельно — котлеты отдельно", "безопасность" (это же e-commerce решение, а не солянка обьявления обьектов в шаблонах и таскания обьектов по шаблонам ;) )), "парадигма MVC" и т п
Вопрос был об архитектуре, котлетах и мухах.
То, что я вижу в коде, это помойка в одном месте.
О DataMapper нет, не слышали?
И как приведенный код улучшает «безопасность»?
То что и услышал в ответ — вы кодер а не архитектор и не понимаете стандартов архитектур
Даже не понимаете элементарный код из архитектуры и почему он такой
Ну да все привыкли таскать и вызывать обьекты в шаблонах, плюя при этом на стандарты
Еще раз даю наводку — в шаблонах не должна быть логика взаимодействия с обьектами, только с выводом массива данных. Ресурсы должны быть разделены. Шаблон — это "конечная" View — там уже никакого взаимодействия обьектов быть не должно (оно во View должно быть, а не в шаблонах). "безопасность" если таскать обьекты по всему коду mvc — могут быть проблемы утечек памяти, переполнение памяти и связанных с этим проблем и атак. Четкое разделение ресурсов снижает вероятность такой атаки. Своего рода "песочницы" если примитивно обьясняться
Что вы слышали о маппинге?
Как этот конкретный код улучшает безопасность?
Разбираем этот кусок кода частично
$this->document->addScript('catalog/view/javascript/jquery/magnific/jquery.magnific-popup.min.js');
$this->document->addStyle('catalog/view/javascript/jquery/magnific/magnific-popup.css');
$this->document->addScript('catalog/view/javascript/jquery/datetimepicker/moment.js');
$this->document->addScript('catalog/view/javascript/jquery/datetimepicker/bootstrap-datetimepicker.min.js');
$this->document->addStyle('catalog/view/javascript/jquery/datetimepicker/bootstrap-datetimepicker.min.css');
А если я хочу подменить шаблон и использовать другой? Мне копипастить весь action контроллера?
Скрипты, связанные с шаблоном, обязаны быть связаны только с ним, а не с action контроллера
А если я захочу выводить не html, а отдавать json? Опять копипаст?
$data['heading_title'] = $product_info['name'];
$data['text_select'] = $this->language->get('text_select');
$data['text_manufacturer'] = $this->language->get('text_manufacturer');
$data['text_model'] = $this->language->get('text_model');
$data['text_reward'] = $this->language->get('text_reward');
$data['text_points'] = $this->language->get('text_points');
$data['text_stock'] = $this->language->get('text_stock');
$data['text_discount'] = $this->language->get('text_discount');
$data['text_tax'] = $this->language->get('text_tax');
$data['text_option'] = $this->language->get('text_option');
$data['text_minimum'] = sprintf($this->language->get('text_minimum'), $product_info['minimum']);
$data['text_write'] = $this->language->get('text_write');
$data['text_login'] = sprintf($this->language->get('text_login'), $this->url->link('account/login', '', true), $this->url->link('account/register', '', true));
$data['text_note'] = $this->language->get('text_note');
$data['text_tags'] = $this->language->get('text_tags');
$data['text_related'] = $this->language->get('text_related');
$data['text_payment_recurring'] = $this->language->get('text_payment_recurring');
$data['text_loading'] = $this->language->get('text_loading');
$data['entry_qty'] = $this->language->get('entry_qty');
$data['entry_name'] = $this->language->get('entry_name');
$data['entry_review'] = $this->language->get('entry_review');
$data['entry_rating'] = $this->language->get('entry_rating');
$data['entry_good'] = $this->language->get('entry_good');
$data['entry_bad'] = $this->language->get('entry_bad');
$data['button_cart'] = $this->language->get('button_cart');
$data['button_wishlist'] = $this->language->get('button_wishlist');
$data['button_compare'] = $this->language->get('button_compare');
$data['button_upload'] = $this->language->get('button_upload');
$data['button_continue'] = $this->language->get('button_continue');
$this->load->model('catalog/review');
$data['tab_description'] = $this->language->get('tab_description');
$data['tab_attribute'] = $this->language->get('tab_attribute');
$data['tab_review'] = sprintf($this->language->get('tab_review'), $product_info['reviews']);
$data['product_id'] = (int)$this->request->get['product_id'];
$data['manufacturer'] = $product_info['manufacturer'];
$data['manufacturers'] = $this->url->link('product/manufacturer/info', 'manufacturer_id=' . $product_info['manufacturer_id']);
$data['model'] = $product_info['model'];
$data['reward'] = $product_info['reward'];
$data['points'] = $product_info['points'];
$data['description'] = html_entity_decode($product_info['description'], ENT_QUOTES, 'UTF-8');
Не, явное лучше неявного… Но не до такой же степени…
Кто мешал сделать так?
$translator = new Translator($this->request->get('lang'));
// спорный момент, ну ок, пусть у нас маппер попутно дергает еще и переводчик
// хотя лично я бы вопрос перевода оставил бы на намного более поздний этап
// при выводе в шаблоне
$mapper = new ProductTemplateMapper($translator);
$queryMapper = new ProductQueryMapper($translator);
$validator = new ProductQueryValidator($translator);
$data = [];
$data = $mapper->map($data, $product_info);
$queryData =$queryMapper->map([], $this->request->getQueryParams());
if (!$validator->isValid($queryData)) {
throw new Exception($validator->getMessage());
}
$data = $mapper->map($data, $queryData)
Йо, диджей…
- Мы имеем переиспользуемый код.
- Мы не имеем лапши в контроллере и логика стала намного чище и прозрачнее. Буде нам захочется деталей мы преспокойно погрузимся в мапперы и валидатор.
- Мы можем валидировать данные в другом месте тем же самым кодом.
- Мы можем маппить одни структуры и входные параметры в другие где нам угодно, если захотим.
Безопасность?
Мы добавили валидацию данных, которую я не видел в исходном коде…
Осталось написать корректно валидатор.
Бред. Набирайтесь опыта и поработайте с opencart
Вы неосознанный бред несете
Даже без комментариев, это просто смешно и по детски
Я вам не мальчик далеко а в отцы гожусь скорее всего
У меня сыну наверно больше чем вам
Не надо панибратства, я с вами не "пил"
Одно дело выявлять ламеров, которые "кричат" соврешнно при этом не знакомые с продуктом и не могут анализировать и тем более делать "выводы", а другое личное оскорбление
Да вы у нас скорострел… Как я погляжу…
И ламер наблюдается пока один — это конкретно вы.
Основная ваша проблема в том, что знаний у вас близко к нулю.
Рассуждать о безопасности с таким кодом…
// это вызов в контроллере
$category_info = $this->model_catalog_category->getCategory($path_id);
// а это сам метод...
public function getCategory($category_id) {
$query = $this->db->query("SELECT DISTINCT * FROM " . DB_PREFIX . "category c LEFT JOIN " . DB_PREFIX . "category_description cd ON (c.category_id = cd.category_id) LEFT JOIN " . DB_PREFIX . "category_to_store c2s ON (c.category_id = c2s.category_id) WHERE c.category_id = '" . (int)$category_id . "' AND cd.language_id = '" . (int)$this->config->get('config_language_id') . "' AND c2s.store_id = '" . (int)$this->config->get('config_store_id') . "' AND c.status = '1'");
return $query->row;
}
Ну, наверное, конечно можно… местами…
Но я бы не стал
Реализация opencart имеет право на жизнь как коробочное нерасширяемое приложение для конечного пользователя.
Когда вся кастомизация заключается в смене «шкурки».
Вопрос «безопасности» очень сильно открыт…
Вопрос расширяемости… увольте.
Рот закрой хорошо "обученный" идиот
Собрались два тролля с нулем мозгов и шаловливыми руками говнокодинга
не можешь атаковать мысль, атакуй мыслителя ©
Начнем с того что этот дебил, подъехавший на "блатной" козе, первым перешел на личные оскорбления (посмотрите исходный пост чей он)
Вот и получил ответ адекватный
И в табло бы за такое получил
Все предельно просто.
То что он нес бред — это и так видно
Я тоже с 20 летним опытом работы в web разработке когда родился opencart тоже так "подьезжал" к Даниэлю (разработчику opencart) с детскими (это я уже вижу по прошествии времени) вопросами в таком же стиле как ваши или того "гражданина". Но после многих лет работы с opencart — v понял насколько гениально простое это архитектурное решения а самое главное очень функциональное и гибкое
Я бы даже сказал — высеченный в граните при помощи зубила
Совершенно верно — все гениальное просто
opencart архитектура простая как "доска", но при этом очень стандартная, функциональная, гибкая, унифицированная и безопасная
Поэтому и популярная среди разработчиков и пользователей
Что вы имеете в виду под «контейнером зависимостей», применение паттерна DI?
да, это и имеется в виду. я обычно для мелких домашних проектов, которые собираю из разных пакетов, использую https://github.com/auraphp/Aura.Di — простой, легкий и удобный, а еще не тянет кучу всего за собой
еще вопрос — а как экранируете вывод в шаблонах? например тут
с твигом по этому поводу париться бы не пришлось, да и вот такого тоже не было бы
По твигу — действительно, ескейп решается |e насколько помню, но от назначения переменных и операций с ними вряд ли бы спасло (phpdoc там сделан для автокомплита). По поводу эскейпа — в большинстве случаев при отображении используются атрибуты моделей, которые завернуты в html purifier в зависимости от определенных types() входящих пользовательских данных (если для атрибута не указан принудительный тип[text|html|!secure], он автоматом упадет в очистку).
да конечно нода! Ага! Для кого она? На пыхе просто без вариантов, если цель — большая аудитория. Семерка вышла, все, стесняться больше нечего.
Как вы определяете, что является форматом habrahabr? Или я ошибся с тегами публикации и она ни коем образом не относится к php, cms и ооп?
Релиз FFCMS 3.0.0 — новая переработанная система