Доброго времени суток обитатель habrahabr, сегодня я хочу тебе рассказать о новом релизе ffcms — 3.0.0 и кратко осветить кардинальные изменения, которые претерпела система с момента предыдущего релиза — 2.0.4.

Система сохранила бесплатную модель распространения и открытый исходный код (MIT), но исходный код был полностью переписан под MVC архитектуру и автозагрузку PSR-0. Многие «велосипеды» были убраны из системы, а их место заняли популярные компоненты: symfony http foundation, laravel eloquent и многие другие.


Переработка архитектуры системы


Обсуждая 2ую версию системы многие пользователи habrahabr советовали существенно переработать систему с учетом современных тенденций: добавить менеджер зависимостей и версий composer, ввести устоявшуюся MVC архитектуру и привести код к единому PSR-1/2 стилю. Код 2ой версии действительно имел достаточно низкое качество и об него можно было сломать ногу (а то и обе). Так же было отмечено, что модель разработки расширений 2ой версии является очень запутанной и избыточной, а вместе с синтаксисом api ядра у некоторых пользователей это вызывало душевную боль.

Внедрить современные инструменты и принципы разработки приложений было просто необходимо, однако переписывать существующий код было практически нереально — поэтому было принято решение переработать архитектуру системы «с нуля».

Система была разделена на несколько функциональных частей: базовая структура, ядро, консоль. Для каждой части был создан репозиторий, настроен composer и проект был опубликован на packagist. Все части связываются при помощи зависимостей в composer.json базового компонента.

Отказ от велосипедов


За последние годы разработки приложений я познакомился с большинством популярных фреймворков, такими как symfony, laravel, yii и codeigniter. Большинство «идей взаимодействий», которые я пытался самостоятельно реализовать в своей CMS, как не странно, уже были реализованы в популярных фреймворках — где то они монструозно сложны, где то — слишком просты и недостаточно функциональны. Многие из них мне понравились и я использую их по сей день, внедрив в ffcms.

Итак, следующие собственные части «велосипеда» были заменены на уже устоявшиеся популярные компоненты:

  • Работа с сетью (Networking): symfony http foundation
  • Работа с базой данных (DB manager): laravel eloquent
  • Безопасность HTML кода: HTML purifier
  • Работа с консолью: symfony console
  • Ядро кеширования (Caching): php fast cache
  • Отладка (Debugging): debugBar
  • Работа с почтой (Mailer): swiftmailer
  • oAuth 2.0 авторизация: hybridauth

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

Производительность и совместимость


А не ввести ли нам поддержку php-5.2 и не юзнуть ли polyfill? Нет, нет и еще раз нет. Сейчас, на волне выхода php 7.1 и движения к deprecated 5.5 нет абсолютно никакого смысла поддерживать устаревшие версии php. Соблазн использовать polyfill, конечно, велик, но и от него можно отказаться дабы не усложнять и без того непростую систему.

FFCMS 3 будет работать на любом интерпретаторе php начиная с версии 5.5, в связке nginx — php-fpm, apache2 — php или любыми другими связками (при условии переписания правил перезаписи uri).

Производительность системы существенно не пострадала, хотя расход ресурсов стал несколько большим, чем во 2ой версии (оно и не мудрено), но все же до уровня bitrix дотянуть не удалось. Загрузка страницы все так же < 0.1сек, потребление памяти — < 7mb (для php 5.6 без opcache). Последний performance тест можно найти на google.docs вместе с тестовым контейнером под virtualbox.

Шаблонизация (или голый php?)


В данном споре бойцы сломали немало мечей, но единого мнения в вопросе нет. Многие считают, что самого синтаксиса php вполне достаточно для шаблонизации, а некоторые без twig и blade не видят своей жизни. Во 2ой версии системы использовался twig, но мной было принято решение ограничиться классическим php синтаксисом для генерации html кода в представлениях.

Немножко кода для искушенных
// экшен контроллера:
public function actionIndex()
{
    // blablabla
    return $this->view->render('dir/file', [
        'param' => 'my value'
    ]);
}
// вьюшка
<h1>Demo view</h1>
<p>param value is: <?= $param ?>


С UI осталось все по прежнему — jquery & bootstrap вполне проверенная временем связка.

БД, запросы и ActiveRecords


Для взаимодействия с базой данных в рамках PHP существует множество различных путей. Кто то работает с голым PDO, кто то с Doctrine и QueryBuilder'ами. В FFCMS используется библиотека laravel eloquent, которая позволяет взаимодействовать с базой данных по средствам сборщика запросов (Query builder) а так же при помощи подхода ActiveRecords.

ActiveRecords очень удобны для работы с БД и существенно упрощает и сокращает синтаксис запросов. Конечно, это не полноценный ORM уровня Doctrine, однако для целей CMS его вполне достаточно.

Миграции


Без миграций и их дальнейшего «деплоя» сейчас никуда. Нет, есть конечно же люди использующие mysqldump/pg_dump но мы не будем следовать этим путем. В ffcms 3 присутствует стандартная реализация миграций — классы с 3мя методами up(), seed() и down(), возможность создания, применения и отката миграций. Стандартные миграции хранятся в /Private/Migrations, но при помощи MigrationsManager могут быть имплементированы миграции из любых директорий.

Отладка


Для удобства быстрой отладки и профилирования запросов в ffcms встроен функционал phpdebugbar. Данный механизм позволяет выполнять отладку «на скорую руку», когда нет возможности или времени на подключение xdebug/zenddebug. Отладчик выглядит в виде панели и доступен для включения в настройках админ панели.

Картинка с debugbar


Тестирование


Тестирование работоспособности продукта вручную не является тенденцией современной разработки. Для целей автоматического тестирования кода системы и UI была внедрена система автоматических тестов — codeception, которая сочетает в себе стандартное unit-тестирование и acceptance тестирование интерфейсов.

Тесты можно запустить из корня при помощи команды codecept run, предварительно запустив selenium с драйвером для chrome или другого браузера. Так же необходимо отредактировать конфиг тестового окружения (/tests/acceptance.suite.yml) под вашу прослойку. Для настройки тестов есть небольшой документ с инструкциями к применению (документ не был изначально предназначен для «всех глаз», уж простите).

Мотивирующая gif-ка с выполнением тестов (5Mb!!!)


Расширения


В виду наличия PSR-0 автозагрузки система расширений была пересмотрена. Сейчас все расширения разделены на 2 типа — приложения и виджеты, первые — занимают определенный корневой URI в зависимости от контроллера и при помощи actions обрабатывают те или иные запросы; вторые — предназначены для отображения в каком-либо месте представлений путем прямого обращения к классу виджета.

Кроме того, весь набор «реализаций» может быть завернут в один пакет и при помощи git-а и composer-а соблюдая стандарт автозагрузки может распространятся как самодостаточная реализация. Ярким примером является реализация форума или демо-пакет.

Что ж, мой рассказ достаточно затянулся, но пожалуй в одну статью все уместить невозможно. Буду рад ответить на ваши вопросы и выслушать ваши пожелания.

> Официальный сайт: ffcms.org (зеркало: ffcms.ru)
> Проект на github: phpffcms
> Документация администратора и разработчика: doc.ffcms.ru (в процессе доработки).
Поделиться с друзьями
-->

Комментарии (77)


  1. maxic
    17.01.2017 21:32
    +2

    "Современненько", но слишком усложнено
    Не "есть хорошо" во View делать вот такие вызовы
    $data = (new EntityCommentData($comment, false))->make();
    Во View (шаблона фактически) лучше отправлять уже "рассчитанные" данные контроллером
    Т е архитектура все равно с "костылями"


    1. zenn
      17.01.2017 21:41
      +1

      Спасибо что заметили, да, использовать во view инициацию модели, пусть она и является «сущностью» не есть хороший тон, видимо данный код избежал рефакторинга и был мной упущен (проверил «вьюхи» — на самом деле, это единичный случай и он будет исправлен).
      Данный участок кода будет переработан, везде модели инициируются и выполняют все необходимые действия в рамках контроллера.


      1. maxic
        17.01.2017 21:58

        Я бы еще советовал сделать переносимый контроллерами registry обьектов
        Чтобы не было вот такого: Str::likeEmpty($tagName)
        Тогда будет $this->registry->str->likeEmpty($tagName)
        Как то архитектура будет более унифицирована
        И тогда не надо будет делать в контролерах new… (new там тоже как то коряво выглядит)
        Короче есть еще над чем подумать вам


  1. Fortop
    17.01.2017 21:53

    Composer-то поддерживается или нет?


    1. zenn
      17.01.2017 22:03

      Конечно, это указано прям в статье и несколько раз. На всякий случай: composer.json / packagist


      1. Fortop
        17.01.2017 22:04

        Действительно указано, причём практически в самом начале.
        Значит я очень невнимательно прочёл


        1. zenn
          17.01.2017 22:08

          Ничего, бывает, у меня под вечер у самого глаза еле открыты после рабочего дня и пары публикаций. Зато теперь вы в этом точно уверены, а на последок подкину вам метод развертки проекта в 3 команды:

          # установим глобальный 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
          

          Развлекайтесь ;)


          1. Fortop
            17.01.2017 22:10

            Не-не-не :)

            Мне ближе фреймворки, а не cms

            Но код из любопытства гляну


  1. denisyukphp
    17.01.2017 22:51

    На своём сайте вы сравниваете свою CMS с Битриксом, Вордпрессом, Джумлой и другими. Не думали развиваться в сторону какой-нибудь нишевой CRM и дальше монетизировать её? Потому как рынок CMS сильно перегрет, куча документации и видео по ним, да и такую же систему можно быстро поднять на фреймворке или слепить из компонентов, если будет необходимость.


    1. zenn
      17.01.2017 22:58

      Я задумывался над этим вопросом, возможно действительно следует сделать уклон в какое-то определенное нишевое направление, хотя в самых перспективных (eCommerce) конкурентов еще больше.


      1. maxic
        17.01.2017 23:18

        В e-commerce фактически кроме Magento и Opencart ничего стоящего по архитектуре нет
        Остальные — сплошной архитектурный говнокод
        Но составить им конкуренцию уже практически невозможно, уж очень они хороши


        1. ustasby
          18.01.2017 02:29
          +2

          В опенкарте есть архитектура? Да вы явно не заглядывали в него, он из <цензура> и палок, из стоящих как минимум есть cs-cart, readyscript, prestashop. А Magento, вы представляете стоимость разработки и поддержки, да 99.9% всех магазинов никогда столько прибыли то не принесут.


          1. maxic
            18.01.2017 02:53

            Это вы не заглядывали в него. Я с ним каждый день "сплю". Вот не рассказывайте мне про opencart и тем более про г… престу, cs… и т.п. Вы еще скажите что в битрикс "архитектура" есть...:)


          1. Alexufo
            18.01.2017 03:53

            лапша код там в опенкарте, млять тонна одинаковых шаблонов распиханных по папкам, 6 шагов регистрации юзеру, 5 форм отображения одних и тех же данных "информация о пользователе".
            нет быстрого заказа, а править корзину нааяксенную через все ядро...


            Престашоп не имеет в коробке самовывоз. Я промолчу.


            1. maxic
              18.01.2017 04:30
              -1

              Ну сразу видно что в opencart вы полный дилетант.
              Даже и комментировать не буду
              Видел звон — не знаю где он. "Раз установил"


              1. v-derckach
                23.01.2017 15:20

                Вот не заглядывал в последние версии, но 1.х-2.0 — расширения — через патчинг исходных файлов? Серьёзно? И костыли для обхода этого, но никак не нормальная система хуков и автозагрузки… Совместимость тщательно тестировать приходится даже при обновлении на минорные версии…
                В общем, не хочу материться, но на этой штуке можно что-то сделать, красивый MVC, да, но поддерживать её — свят-свят-свят!


            1. maxic
              18.01.2017 04:48
              -1

              Opencart приведен в соответствии с законодательствам многих стран, где обязательным считается поэтапное оформление заказа и регистрация данных о покупателе. Быстро учить мат. часть e-commerce систем а не умничать здесь
              В opencart существует большое множество модулей одно страничного оформления заказов как и быстрая регистрация в "пару" полей. Если законодательством вашей страны разрешено одно страничное оформление заказа с минимальными данными о покупателе — устанавливайте, там сложного ничего нет, таких модулей валом


              1. Alexufo
                18.01.2017 09:25

                Я работал несколько лет с опенкартом, сопровождал пару магазинов, прочувствовал все прелести обточки напильником этого "алмаза" с модулями и без модулей, платными и не платными. Работал и с битриксом.
                Напомните, в каком году OC вышел, в 2011? С тех пор он не поменялся вообще, если не считать бутстрапа со 2 версии и мелочей, которые ничего не сменяют кардинального. То что он рука об руку идет с vqmod уже все объясняет.


                1. maxic
                  18.01.2017 09:33

                  Серьезно? :) Не менялся?
                  Ну конечно, не специалист кроме boostrap-a больше ничего не увидит.
                  Там глобальные изменения на уровне архитектуры, кода.
                  И нету vQmod -а уже, уже забыли про него давно.
                  Знаете, судя по вашим ответам, вы всё видели "издалека" и "пару раз"
                  Мне если честно, как руководителю IT проектов e-commerce систем (senior), смешно читать ваши ответы. Ну ладно бы студент такое писал, но в профиле у вас стоит "тех. директор" (чего правда?) И такие ляпы выдаете.


                  1. Alexufo
                    18.01.2017 10:02

                    В общем то я вас понимаю. Если вы руководитель — веры терять нельзя. Пишу без сарказма.
                    У меня с этим делом все самоубийственно плохо.


                    1. maxic
                      18.01.2017 10:42
                      -2

                      Это демагогия с вашей стороны.
                      Когда за спиной 20 лет разработок и большое портфолио в веб разработке (и кстати своя cms как у автора тоже есть, и на которой десятки проектов крутились) и работа на всех cms и fw — то здесь нет выбора — он один в e-commerce: Magento или opencart
                      Всё
                      Magento для серьезных проектов
                      Opencart для простых и средних (которых 99%)
                      Конкурентов то нету :)
                      woocommerce с его неандертальским говнокодом? Или битрикс у которого понятие архитектура отсутствует напрочь, но агрессивный маркетинг. Преста с говно архитектурой? Остальные я рассматривал детально — там вообще ужас.
                      Никто и близко не встал по архитектуре с opencart и magento


                      Но вы не специалист в области архитектуры — это и так видно. Вам она просто не понятна. Для вас архитектура — это код. Не путайте грешное с праведным.


                      1. Alexufo
                        18.01.2017 10:54

                        Дискуссии над предметом, который приносит хлеб, заведомо бессмысленны. Вы его всегда будете защищать выдавая личные предпочтения и опыт за плюсы, а если кто-то несогласен — дилетантство.
                        Работать с битриксом мне куда удобнее, хоть я его терпеть не могу.


                      1. oxidmod
                        18.01.2017 11:21

                        есть еще такие штуки как shopware (http://www.shopwaredemo.de/) для действительно сложных проектов и OXID (http://demoshop.oxid-esales.com/professional-edition/) для случаев попроще


      1. Alexufo
        18.01.2017 03:59
        +1

        Умоляю!
        Займите нишу!
        Это дерьмо вроде опенкарта и престы ожирело и застряло в норе как винни-пух! Я кровью обливаюсь когда меня просят совета, а что я скажу? Шлю к мерчиуму какому нибудь. Хоть глаза бы не видели мои больше кода этих cms.


        Из опенсурсного в екоммерсе НЕТУ НИЧЕГО нормального вообще! Кучу лет!
        Толпа просто попрет как только пойдут слухи о минимальстичном современном движке интернет магазина.


        1. maxic
          18.01.2017 04:39
          -3

          Если вы не работали с opencart — то давайте не умничать.
          По вашим ламерским ответам об opencart я очень быстро понял "who is who" вы. А о наборе кармы по "перепечаткам" тем более "всё с вами ясно"


          1. arteast
            18.01.2017 09:44
            +4

            Либо у вас какой-то другой opencart, либо развился стокгольмский синдром. Можно говорить, что опенкарт лучше <другой ecommerce solution name>, но код оставляет желать лучшего.
            Несколько примеров:


            • контроллеры прибиты гвоздями к вью, к конкретному шаблону. Пример: попробуйте разобрать ajax-овый аккордеон в чекауте на отдельные странички, и посмотрите, сколько придется править в контроллерах.
            • в каждом методе каждого контроллера есть десятки строк кода, просто пробрасывающие строки из language во view
            • километры копипащенных полей в формах view безмолвно вопиют. Обработка custom fields в тех же вью добавляет свою мощную ноту в том хоре.
            • используется давняя хорошая традиция защищаться от XSS путем HTML-эскейпа записей в базе данных
            • как устанавливаются 100500 обещанных нам расширений? Путем накатывания патча на код!


            1. maxic
              18.01.2017 10:26
              -3

              Всё закончили. Ваш бред, даже не хочу комментировать
              Вы даже не понимаете о чем пишите
              О стандартизации и унификации вы даже понятия не имеете. И для вас в шаблонах таскать "вычисления" — это нормальное дело я так понял, но только не для профи, и не для нормальной архитектуры
              И ничего править не надо — перехватил хуком loader и подставляй любые свои значения, любые шаблоны.
              Да это и не надо. Так как все унифицировано и стандартизировано.
              Насчет патча на код — это уж вообще рассмешили. Сразу видно "смотрел поверхностно давно".
              Там давно уже есть система ивентов, а оверлорд хуки можно было делать еще в 1.5,x. (в архитектуре это заложено — но вам это не понятно видно было) Хочешь пользуйся не хочешь не пользуйся — есть выбор. Есть квалификация — пользуешься всей мощью архитектуры, нету — пишешь "ваш" бред. И причем здесь escape XSS к БД, все параметры очищаются еще на точке входа, escape — это просто контрольный выстрел и признак хорошего тона, там большего и не надо уже ничего
              Если вы не специалист то даже не поймете, что opencart даже в 1.5.x можно было не использовать vqmod. vqmod — это для учеников, домохозяек, дилетантов, блондинок и за счет них популяризации opencart


              1. Peretyaka
                18.01.2017 12:05
                +3

                Вы бы сосредоточились на аргументах, а не оскорбляли собеседников, глядишь и что-то бы полезное было в вашей дискуссии.

                Я не спец по OC, но вот открыв рандомный файл, я как-то уже не очень горю желанием его изучать:
                https://github.com/opencart/opencart/blob/master/upload/catalog/controller/product/product.php

                Ну а с точки зрения архитектуры. Давайте пообщаемся про разделение и связывание, очередя, микросервисы, котейнеры, масштабирование. А так: с какой-то то там версии добавили систему ивентов. Это вряд ли можно назвать архитектурой, просто костыли, которые лучше оверлоад и которые были проверены и вдоль и поперек откатаны задолго до 2011 года, не понятно почему они не использовались в проекте изначально.


                1. maxic
                  18.01.2017 15:23
                  -3

                  Давайте вы вначале изучите и поработаете хотя бы годик с opencart — потом обсудим
                  Ok
                  А так это бесполезный треп — как с Alexufo — который поверхностно с ним знаком


                  1. Alexufo
                    19.01.2017 15:15
                    +1

                    ну как поверхностно. Я перепиливал шаблон полностью, прокидывал новые поля в адмику, и удивился как в битриксе удобнее вставлять компоненты вместо правки сотен вьюх с их сотнями контроллеров. Я устал просто бродить по иерархии OC.
                    Нельзя просто так взять и сделать тему с 0 в OC. Я не понимаю предназначение тем, где обязательными являются одновременно сотня файлов.
                    И сделал вывод — OC не сделан для кастомизациии тем, если не считать кастомизацией перебивание цветов в css.


                    1. maxic
                      19.01.2017 15:46
                      +1

                      Почему? Можно спокойно делать css только или для одного файла
                      Поверхностно видно и из этого поста
                      Делаете папку с темой но не все файлы переписывает а только header.tpl и stylesheet
                      В header.tpl меняете только путь к stylesheet
                      Всё
                      Не знаю что вы там чудили еще
                      В контроллерах стоит же проверка есть ли файл в папке кастомной темы если нет брать с default
                      Надо изменить какой то шаблон в своей теме — берете только нужный файл
                      Какие проблемы то :)


                      1. Alexufo
                        19.01.2017 16:12

                        Мне нужна тема которую я сам хочу. Никакие другие папки и шаблоны не нужны. В теме 170 файлов вьюх Это для кого?)


                        Мне нужно пара другая шаблонов куда я хочу прикрутить компоненты типа корзин, каталога, правки профиля с адресом, и еще несколько форм. А ОС не позволяет ни менять название шаблонов ни удалять их, я уж молчу про соблюдение папочной структуры и бесконечного прыгания по ним в поисках нужного места в шаблоне. Там профиль юзера выводится разными вьюхами в разных местах.


                        Либо переписывай все ядро, либо вся кастомизация это правка цветов в css. Меня это не устраивает. Меня темизация в wordpress устраивает.
                        Мне не нужно ни сравнение товара, ни страница производителей, тьма каких то шаблонов оплаты которой нет. я хочу сделать чистый шаблон который меня устраивает а не архитектуру движка. В OC с этим плохо. Поэтому все темы выглядят 1 к 1 — так дешевле.


                        1. oxidmod
                          19.01.2017 16:21

                          может дело в том, что ОС не CMS, в отличии от WP?


                          1. Alexufo
                            19.01.2017 16:25

                            а что же тогда, если она контент менеджмент товаров позволяет делать?
                            По сути то одна фигня, сущность — товар или запись.Ввод и вывод. А дальше куча возможных сортировок, группировок, фильтров на отображении.


                          1. maxic
                            19.01.2017 17:27

                            :) А что это? Ой… как с "вами" тяжело (у одного квалификации ноль в opencart — уже раздает "советы" и строит "мнения", второй просто "умник", теритий не читает мат. часть, но зато все "вопят")


                            Вы вообще знаете что такое CMS?
                            "система управления содержимым" — понимаете?
                            opencart — управляет содержимым.
                            Это CMS
                            PHP e-commerce CMS


                            1. oxidmod
                              19.01.2017 21:36

                              тогда любой кусок кода цмс, да...


                        1. maxic
                          19.01.2017 17:20

                          Я же написал как, в чем проблема то
                          Новая тема — переписываете туда только файлы которые изменяете — всё
                          Вы понимаете суть унификации и стандартизации? Я вижу что нет, как и 99.99% здесь. Я как то статью писал здесь — " Мы плюём на стандарты" — 99% ответов было "а зачем они надо" и куча малолеток нах… ла минусов


                          Если вы хотите вообще сделать поля шаблонов для контроллеров — не вопрос. Есть куча модулей бесплатных которые это делают. Но это костыльно и НЕ правильно. И они не нужны (можно даже посмотреть по количеству скачиваний их


                          1. Alexufo
                            19.01.2017 19:29

                            О какой унификации речь)))))))))))), если 99% тем для опенкарта это "замаскируй под современный магазин OC c помощью css"?


                            Хочешь перенести поиск в футер? лезть в контроллер, назначай вывод туда!
                            И так абсолютно с каждым выводом.


                            А теперь вспомни что и контроллер это тоже 170 файлов в 9 папках!
                            Итого: для кастомизации темы нужно работать минимум с 300 файлов раскиданных в 18 папках!


                            Показатель гибкости — это обьем тем, по которым не ясно, что за движок. В случае ОС это определяется сразу. Как таковых тем по ОС нет и не было, есть костыли над теми же 170 файлами в 9 папках.


                            Меня не устраивает ни привязка к папкам, ни огромное количество копипаста, ни разделение шаблонов. Про отсутствие ЧПУ я даже не говорю. Я знаю что значит делать темы для OC и пресса. И последний даже рядом по гибкости ставить не хочеться.
                            Можно назвать это унификацией, стандартизацией, дилетанством. Да. Только это не снимает абсолютно никаких вопросов.


                            1. maxic
                              19.01.2017 19:55
                              -1

                              :)
                              Смешно — хочешь перенести поиск вниз — не надо ничего править. Кто вас такому "учил"?
                              Сразу видно — не специалист
                              Далее даже не хочется и читать ваши "потуги" чего то "понять"


                              1. Alexufo
                                20.01.2017 14:56

                                не хочется, потому что священная корова.


                                По факту именно так и есть: перенос вывода (поиск я не про голую html форму имел ввиду) между вьюхами без правки контроллера не обходится. Такое поведение еще поискать нужно.


              1. Fortop
                18.01.2017 14:20
                +1

                Тут вот выше посоветовали…
                Глянул…

                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');
                
                



                1. maxic
                  18.01.2017 15:31
                  -2

                  :) Вот я так и знал про этот вопрос
                  Да по "детству" его часто задают — но там все продумано и сделано согласно стадартов


                  Если сами ответите поставлю пятерку
                  Что здесь не понятного "почему"?
                  Детский вопрос.
                  Даю наводку — "мухи отдельно — котлеты отдельно", "безопасность" (это же e-commerce решение, а не солянка обьявления обьектов в шаблонах и таскания обьектов по шаблонам ;) )), "парадигма MVC" и т п


                  1. Fortop
                    18.01.2017 15:34
                    +1

                    Подождите мальчик…

                    Вопрос был об архитектуре, котлетах и мухах.
                    То, что я вижу в коде, это помойка в одном месте.

                    О DataMapper нет, не слышали?

                    И как приведенный код улучшает «безопасность»?


                    1. maxic
                      18.01.2017 15:43
                      -1

                      То что и услышал в ответ — вы кодер а не архитектор и не понимаете стандартов архитектур
                      Даже не понимаете элементарный код из архитектуры и почему он такой
                      Ну да все привыкли таскать и вызывать обьекты в шаблонах, плюя при этом на стандарты
                      Еще раз даю наводку — в шаблонах не должна быть логика взаимодействия с обьектами, только с выводом массива данных. Ресурсы должны быть разделены. Шаблон — это "конечная" View — там уже никакого взаимодействия обьектов быть не должно (оно во View должно быть, а не в шаблонах). "безопасность" если таскать обьекты по всему коду mvc — могут быть проблемы утечек памяти, переполнение памяти и связанных с этим проблем и атак. Четкое разделение ресурсов снижает вероятность такой атаки. Своего рода "песочницы" если примитивно обьясняться


                      1. Fortop
                        18.01.2017 15:46

                        Ещё раз для двоечников…

                        Что вы слышали о маппинге?
                        Как этот конкретный код улучшает безопасность?


                      1. Fortop
                        18.01.2017 16:30
                        +1

                        И так, как говорят братья беларусы — панеслася
                        Разбираем этот кусок кода частично

                        $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');
                        


                        1. maxic
                          18.01.2017 16:44
                          -2

                          Бред. Набирайтесь опыта и поработайте с opencart
                          Вы неосознанный бред несете
                          Даже без комментариев, это просто смешно и по детски


                          1. Fortop
                            18.01.2017 16:57
                            +1

                            Естественно.
                            Потому что всего вашего образования — два класса и коридор.

                            Если я начну 5-тилетним задвигать теорию суперструн для них это тоже будет выглядеть бредом, как и для вас.

                            А какие громкие слова об архитектуре… :D


                    1. maxic
                      18.01.2017 16:11

                      Я вам не мальчик далеко а в отцы гожусь скорее всего
                      У меня сыну наверно больше чем вам
                      Не надо панибратства, я с вами не "пил"
                      Одно дело выявлять ламеров, которые "кричат" соврешнно при этом не знакомые с продуктом и не могут анализировать и тем более делать "выводы", а другое личное оскорбление


                      1. Fortop
                        18.01.2017 16:44
                        +2

                        Сыну больше чем мне? :D
                        Да вы у нас скорострел… Как я погляжу…

                        И ламер наблюдается пока один — это конкретно вы.

                        Основная ваша проблема в том, что знаний у вас близко к нулю.
                        Рассуждать о безопасности с таким кодом…

                        // это вызов в контроллере
                        $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 имеет право на жизнь как коробочное нерасширяемое приложение для конечного пользователя.
                        Когда вся кастомизация заключается в смене «шкурки».

                        Вопрос «безопасности» очень сильно открыт…
                        Вопрос расширяемости… увольте.


                        1. maxic
                          18.01.2017 17:17
                          -7

                          Рот закрой хорошо "обученный" идиот
                          Собрались два тролля с нулем мозгов и шаловливыми руками говнокодинга


                          1. Alexufo
                            19.01.2017 19:33
                            +1

                            не можешь атаковать мысль, атакуй мыслителя ©


                            1. maxic
                              19.01.2017 20:02

                              Начнем с того что этот дебил, подъехавший на "блатной" козе, первым перешел на личные оскорбления (посмотрите исходный пост чей он)
                              Вот и получил ответ адекватный
                              И в табло бы за такое получил
                              Все предельно просто.
                              То что он нес бред — это и так видно


                              Я тоже с 20 летним опытом работы в web разработке когда родился opencart тоже так "подьезжал" к Даниэлю (разработчику opencart) с детскими (это я уже вижу по прошествии времени) вопросами в таком же стиле как ваши или того "гражданина". Но после многих лет работы с opencart — v понял насколько гениально простое это архитектурное решения а самое главное очень функциональное и гибкое


                              1. Fortop
                                20.01.2017 07:30

                                Что вы мелете? Какие 20 лет разработки?
                                Два класса и коридор.

                                Вы Кнута и Фаулера хотя бы держали?


                                1. maxic
                                  20.01.2017 10:41
                                  -1

                                  Тебя еще на ху@ не посылали — там 3.14й туда
                                  "Я ругаюсь матом потому что мне жаль своего драгоценного времени на демагогию с хорошо обученными идиотами" © Мой


                1. oxidmod
                  18.01.2017 16:01
                  +1

                  Open Cart — это труевый MVC. Но к тому же дубовый и простой как доска. Потому оно и так))


                  1. Fortop
                    18.01.2017 16:04
                    +2

                    Чересчур дубовый.
                    Я бы даже сказал — высеченный в граните при помощи зубила


                  1. maxic
                    18.01.2017 16:16

                    Совершенно верно — все гениальное просто
                    opencart архитектура простая как "доска", но при этом очень стандартная, функциональная, гибкая, унифицированная и безопасная
                    Поэтому и популярная среди разработчиков и пользователей


        1. xoma
          19.01.2017 12:08
          +2

          А что думаете про https://github.com/yupe/yupe или https://github.com/DevGroup-ru/dotplant2?


          1. Alexufo
            19.01.2017 15:19

            спасибо. гляну.


  1. MetaDone
    17.01.2017 22:54

    мельком посмотрел и не увидел никакого контейнера зависимостей. что-нибудь подобное используется? и почему вместо твига решили «откатиться» к php-шаблонам?


    1. zenn
      17.01.2017 23:03

      Что вы имеете в виду под «контейнером зависимостей», применение паттерна DI? Он используется, достаточно редко для передачи в конструкторы моделей определенных объектов, которые наследуют интерфейс или базовый класс. Твиг достаточно удобен, но по сравнению с «голым» php различие в синтаксисе не велико (за исключением плюшек типа extend) а местами синтаксис выглядит неявным (к примеру сравнения, к этому синтаксису я привыкал достаточно долго).


      1. MetaDone
        17.01.2017 23:13

        Что вы имеете в виду под «контейнером зависимостей», применение паттерна DI?

        да, это и имеется в виду. я обычно для мелких домашних проектов, которые собираю из разных пакетов, использую https://github.com/auraphp/Aura.Di — простой, легкий и удобный, а еще не тянет кучу всего за собой
        еще вопрос — а как экранируете вывод в шаблонах? например тут
        с твигом по этому поводу париться бы не пришлось, да и вот такого тоже не было бы


        1. zenn
          17.01.2017 23:32

          Возможно, конечно от «прослоек совместимости» в качестве «потомков» под крупные пакеты стоит применить нечто универсальное, пока не сильно задумывался над этим (но по мере роста объема кода это, возможно, будет неизбежным).
          По твигу — действительно, ескейп решается |e насколько помню, но от назначения переменных и операций с ними вряд ли бы спасло (phpdoc там сделан для автокомплита). По поводу эскейпа — в большинстве случаев при отображении используются атрибуты моделей, которые завернуты в html purifier в зависимости от определенных types() входящих пользовательских данных (если для атрибута не указан принудительный тип[text|html|!secure], он автоматом упадет в очистку).


  1. Hazrat
    17.01.2017 22:56
    -3

    Мне кажется тратить силы на разработку еще одной CMS на PHP это как минимум не перспективно. Откуда энтузиазм? было бы интересно что-нибудь на NodeJS, например.


    1. zenn
      17.01.2017 23:05

      Ну почему же, возможно конкуренция среди Node проектов и ниже, но как минимум я использую cms для ряда своих и не только проектов, хотя сказать что поддержка собственного кода дается легче, чем код популярного фреймворка не могу.


    1. Alexufo
      18.01.2017 04:00
      +2

      да конечно нода! Ага! Для кого она? На пыхе просто без вариантов, если цель — большая аудитория. Семерка вышла, все, стесняться больше нечего.


  1. oxidmod
    18.01.2017 00:19

    почему же всеже не на базе фреймворка?


    зы. я знаю, что компосер лучший фреймворк, но всеже (тем более что половину компонент вытянули из симфони, так почему не симфони?)


    1. zenn
      18.01.2017 08:12

      Я не раз рассматривал такой вариант, в том числе symfony, но мне показалось что для целей CMS у него слишком избыточная система роутинга, а сам фреймворк излишне использует паттерн DI. Нет, конечно я не говорю о том, что это плохо — symfony пожалуй один из самых качественных по уровню близости кода к java фреймворк, но для моих целей он показался слишком тяжелым. На symfony, кстати, есть достаточно неплохая cms — livestreet и в ней как раз таки можно заметить сложности разработки простых расширений, вызванные использованием symfony в качестве основы.


      1. oxidmod
        18.01.2017 11:28

        ну сложность архитектуры не от симфони зависит. это лишь клей, который связывает воедино независимые компоненты, половину из которых вы и так используете.


  1. OnYourLips
    18.01.2017 01:08
    -4

    Очень хорошая дипломная работа. Однозначно на пятёрку тянет.
    Но не формат хабра.


    1. zenn
      18.01.2017 08:14
      +3

      С чего вы взяли что это дипломная работа? Это вполне рабочая система, которая уже используется на моих личных проектах и надеюсь заинтересует других людей.
      Как вы определяете, что является форматом habrahabr? Или я ошибся с тегами публикации и она ни коем образом не относится к php, cms и ооп?


      1. Alexufo
        19.01.2017 15:20

        каждый бьется за право быть в закрытой элитарной группе.


  1. xRay
    19.01.2017 09:16

    А роутинг на чем построен? К примеру для кастомных ЧПУ-ссылок.


    1. zenn
      19.01.2017 09:22

      Роутинг реализован простейшим образом — каждый корневой URI (к примеру, /demo/) будет автоматически адресован контроллеру \Apps\Controller\Front\Demo. Если вас не устраивает такое дело событий — без особых усилий можно назначить как статический алиас, так и динамический каллбэк. Более подробно — тут и тут


      1. artygrand
        25.01.2017 10:59

        Получается, чтобы у новостей был адрес /news/ffcms3-announce а не /content/read/news/ffcms3-announce нужно для каждой новости прописывать роут?


        1. zenn
          25.01.2017 11:01

          Да, это «узкое» место текеущего роутера, в этом случае не поможет динамический callback, а статические маршруты придется добавлять для всех адресов. Возможно в будущих релизах я пересмотрю роутер в сторону расширения до нужного вам функционала ('/news/*' => '/content/read/news/*')