Как я интегрировал WebSockets в существующую систему на PHP

    Статья будет о том, как нехарактерная для PHP вещь вроде веб-сокетов может быть интегрирована в существую систему на примере CleverStyle CMS, и какие нюансы при этом могут возникнуть.

    Библиотеки


    Написать сервер и клиент для веб-сокетов весьма сложно, к счастью есть практически безальтернативная библиотека Ratchet, которая предоставляет сервер для веб-сокетов. Под капотом она использует несколько частей ReactPHP и Guzzle (зависит так же от Symfony компонентов, но в данном случае они оказались совершенно лишними). Так же будем использовать Pawl от автора Ratchet, это клиент для веб-сокетов.

    Архитектура


    Так как CleverStyle CMS может работать с несколькими серверами, то было решено поддерживать эту функциональность и тут. Для этого создается пул серверов. Он являет собой MEMORY табличку в MySQL с одной колонкой, публичным адресом для подключения вида wss://web.site/WebSockets (хранить в MySQL или ещё где-то не принципиально, главное чтобы все сервера имели доступ к одной и той же информации). Каждый запускаемый сервер добавляет себя в пул, и если он там не один — подключается к первому как мастеру (если один — сам становится мастером). Если мастер не отвечает — он удаляется из пула и следующий становится мастером, все подключатся к нему. Таким образом обеспечивается устойчивость от падений и полная децентрализация.

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

    Отправка и прием сообщений


    Формат сообщений был выбран простой:

    {
    	"action"  : "some/action",
    	"details" : []
    }
    

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

    Формат общий для отправки с клиента на сервер, и с сервера на клиент. Единственное отличие — действие для клиента может оканчиваться суффиксом :error, для удобства на клиенте можно указать два коллбека — success и error.

    На клиенте прием и отправка сообщений производится пачкой методов объекта cs.WebSockets (который устанавливает и поддерживает соединение с сервером автоматически, также сам производит аутентификацию с помощью текущей сессии):

    • on(action, callback, error)
    • off(action, callback, error)
    • once(action, callback, error)
    • send(action, details)

    Это на столько просто, что проще уже, наверное, некуда. Так как переданные детали являются массивом — каждый элемент будет передан как отдельный аргумент.

    Всё немного сложнее на сервере. Отправка сообщения производится методом \cs\modules\WebSockets::send_to_clients($action, $details, $send_to, $target) (отправлять можно не только из-под сервера, но и на рядовых страницах, в этом случае будет установлено соединение с одним из серверов, и сообщение будет передано во внутреннем формате, после чего дойдет до клиента).

    Дополнительные аргументы позволяют указать, какому пользователю или группе, или нескольким конкретным пользователям нужно доставить сообщение.

    Для приема используется стандартная система событий, нужно подписаться на событие WebSockets/{action} (подписка совершается по возникновению события WebSockets/register_action), где {action} — это то, что получено от клиента, так же в событие передается текущий пользователь (отправитель), его сессия и язык.

    Пример hello-сервиса:

    <?php
    use
    	cs\Event,
    	cs\modules\WebSockets\Server;
    // Register actions
    Event::instance()->on('WebSockets/register_action', function () {
    	// If `hello` action from user
    	Event::instance()->on('WebSockets/hello', function ($data) {
    		$Server = Server::instance();
    		// Send `hello` action back to the same user with the same content
    		if ($data['details']) {
    			$Server->send_to_clients(
    				'hello',
    				$data['details'],
    				Server::SEND_TO_SPECIFIC_USERS,
    				$data['user']
    			);
    		} else {
    			$Server->send_to_clients(
    				'hello:error',
    				$Server->compose_error(
    					400,
    					'No hello message:('
    				),
    				Server::SEND_TO_SPECIFIC_USERS,
    				$data['user']
    			);
    		}
    	});
    });
    ?>
    

    // Since everything is asynchronous - lets add handler first
    cs.WebSockets.once('hello', function (message) {
    	alert(message);
    });
    // Now send request to server
    cs.WebSockets.send('hello', 'Hello, world!');
    

    Все очень просто.

    Запуск сервера


    Вот тут уже немного сложнее. Было решено поддерживать запуск с веб-интерфейса (даже есть кнопочка в админке), а так же из командной строки. При чем если выполнение консольных команд в PHP доступно, то веб-версия всё равно под капотом запустит консольный вариант сервера. Сервер слушает на указанном в настройках порту на 0.0.0.0 или 127.0.0.1 на выбор (потом Nginx, или что стоит вместо него, на этот порт отправляет все соединения с wss://web.site/WebSockets, то есть для пользователя используется тот же 80 или 443 порт, другие порты могут быть заблокированы во многих ситуациях подобных публичному Wi-Fi).

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

    Движок устроен так, что запускается ядро, потом выполняется определённых модуль, соответствующий странице, потом делается вывод. Так вот сервер веб-сокетов — обычный модуль, вот только до вывода дело не доходит, event-loop запускается и слушает соединения.

    Немного подводных камней


    1. Event-loop может быть только один. В связи с этим и клиент и сервер (так как оба могут и отправлять и принимать сообщения при общении мастер/рядовой сервер) используют один и тот же event-loop
    2. Все подготовительные действия нужно сделать до запуска сервера, после старта event-loop весь линейный код блокируется до остановки (пересекается с первым пунктом, но всё же)
    3. Нужно беречь память; если есть какие-то кэши в объектах — их нужно отключить, иначе через несколько дней процесс может скушать слишком много памяти, ситуацию можно проверить нагрузив сервер с помощью, например, Siege
    4. Нужно беречь время; так как вы скорее всего не используете для всего-всего неблокирующие альтернативные варианты встроенных функций, то следующий клиент не будет обслужен до выполнении блокирующей операции, так что минимизируйте работу чего либо под сервером
    5. Подготовьте ваш код для длительного выполнения (в моем случае в некоторых местах использовалась константа с временем запуска скрипта, которая переставала быть актуальной в случае долгоиграющего процесса)

    Вот и всё


    Хотя веб-сокеты и подобные асинхронные штуки не являются «родными» для PHP и при их упоминании часто вспоминают и Node.js, а так же то, как его совместить с PHP, последний сам может легко работать с той же парадигмой и не умирать после каждого запроса (при определённых навыках можно утилизировать React для создания HTTP-сервера на чистом PHP).

    Попробовать


    Если есть желание поиграть — Docker контейнер ждет вас:

    docker run --rm -p 8888:8888 -v /some_dir:/web nazarpc/cleverstyle-cms
    

    Потом заходите по адресу localhost:8888 в браузере, включаете модуль веб-сокетов, стартуете сервер. В папке /some_dir добавляете любые модули, экспериментируете, пробуете, всё сразу попадает в демку. После остановки останется только удалить /some_dir (--rm ключ удалит сам контейнер автоматически).

    Исходный код
    Share post
    AdBlock has stolen the banner, but banners are not teeth — they will be back

    More
    Ads

    Comments 17

      0
      Я думал вы с прошлого раза передумали использовать global…
      refactoring.guru/ru/
        0
        Можно уточнить где вы нашли global?
          0
          Не глянул подробнее исходники (где в новой версии заменено на singleton), но это
          global $Config, $db, $L;
          
          напомнило старую статью.
          github.com/nazar-pc/CleverStyle-CMS/search?l=php&q=global&utf8=%E2%9C%93

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

          Касаемо модуля веб-сокетов:
          Первое, что бросается в глаза использование композера внутри модуля — спрашивается зачем? Если я поставлю 10 модулей, которым нужны зависимости из композера, мне 10 раз запускать composer update?

          Кстати, обновить зависимости все равно не выйдет, ведь все файлы библиотек уже жестко зашиты вами в репозиторий… зачем?

          Второй момент, уже давно не надо делать собственных автозагрузчиков, если следовать стандартам psr-0, psr-4. Достаточно в томже композере написать 2 строчки.


          В общем, тут можно долго продолжать, постарайтесь продумать архитектуру в соответствии с современными реалиями и ооп дизайном.
            0
            По поводу результатов поиска — первый файл — файл обновления модуля блогов, так как в древних версиях были global — осталось, будет удалено в последствии вместе с возможностью обновления с очень древних версий. Так же используется в процессе установки, что меня не волнует совсем. run-tests.php писали разработчики PHP а не я, так что туда не лез. В целом те несколько результатов поиска уже пережиток и скоро исчезнут вовсе. Статья которую вы указали отображает весьма старую версию системы, многое из комментариев учтено и многое переписано. Лучше глянуть на документацию в wiki, там поддерживается актуальное состояние описания, даже последние статьи уже немного устарели.

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

            По поводу зависимостей — этого и не нужно делать, они будут обновлены вместе с самим модулем WebSockets, вы выберете в админке новый дистрибутив модуля WebSockets, кликните «обновить», и всё. Файлы библиотек зашиты определённые, которые работают вместе без проблем, иногда для правильной работы или исправления библиотеки нужно патчить, зашивание вполне конкретных версий обеспечивает работоспособность. Модуль хранит всё в себе, включая специфические зависимости (более общие, как WYSIWYG редактор выделены в отдельные модули/плагины) и исчезает бесследно и без мусора при удалении. Логично и удобно.

            Для библиотек не нужно делать автозагрузчиков, вот и взял composer как есть. А по поводу автозагрузчика системы — он достаточно прост, но учитывает специфику размещения файлов в CleverStyle CMS. Это накладывает отпечаток на пути к классам, но в целом правило простое — \ заменяется на /, и отрезается вендорный префикс cs.

            Архитектура очень контекстная штука, для фреймворков которые состоят из отдельных компонентов composer подходит прекрасно, если же втискать его в систему зависимостей CleverStyle CMS, то получится что я создам проблему, которую потом придется самому же и решать. В итоге для понимания что же в конце концов происходит нужно будет детально разобраться в устройстве composer, а потом в его интеграции в систему. В случае простых библиотек я их с радостью использую (меня приятно удивляют размеры Ratchet и React), но иногда оптимальнее написать простенький велосипед конкретно под задачу без излишеств, главное без фанатизма и NIH принципа)
              0
              run-tests.php писали разработчики PHP а не я, так что туда не лез.

              Эм, я гденибудь упоминал этот файл? :)

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

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

              По поводу зависимостей — этого и не нужно делать, они будут обновлены вместе с самим модулем WebSockets, вы выберете в админке новый дистрибутив модуля WebSockets, кликните «обновить», и всё.

              Это смотря как посмотреть и придумать реализацию. Дублирование пакетов в папке vendor обеспечено.

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

              Для патчинга библиотек надо слать pull-request'ы автору, а затем запустить composer update. Почитайте про semver и то, как можно получать только патчи (обратная совместимость сохраняется) ссылка на доку.
              В других случаях применяют наследование, т.е. в папку vendor не лезут.

              Модуль хранит всё в себе, включая специфические зависимости (более общие, как WYSIWYG редактор выделены в отдельные модули/плагины) и исчезает бесследно и без мусора при удалении. Логично и удобно.

              за вас это давно сделали, зачем городить еще один велик в котором придется разбираться? Разработчику пишущему модуль куда логичнее и проще использовать то, что уже протещено многими людьми и то, что уже когдато изучил.

              Для библиотек не нужно делать автозагрузчиков, вот и взял composer как есть

              … ээм? Как это не нужно?

              А по поводу автозагрузчика системы — он достаточно прост, но учитывает специфику размещения файлов в CleverStyle CMS.

              суть совершенно не в этом. Я вам об одном, вы о другом. Посмотрите сначала стандарты psr-0 и psr-4. Подумайте, что реализовывать собственный автозагрузчик разработчику модуля будет лень, а пихать еще один композер внуть — как минимум, ужас принципа DRY.

              если же втискать его в систему зависимостей CleverStyle CMS, то получится что я создам проблему, которую потом придется самому же и решать

              вы себе уже создали проблему, создав свой велосипед, вместо того, чтобы взять готовое и популярное решение :)

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

              Мне кажется или это стоит делать с любым инструментом и техлогией?

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

              вся cms сплошной велосипед :) код как минимум сложно читать, а про поддержку и добавление новых фитч, я вообще молчу. Тем более никто не говорит, под каждый чих искать вендора.
                0
                Эм, я гденибудь упоминал этот файл? :)

                Это было в результатах поиска, ссылку на которые вы привели.
                А жаль, когда сталкиваетесь с новыми технологиями, стоит подумать, как они помогут в усовершенствовании чего либо в ваших проектах. Почитайте документацию, посмотрите как его используют, например, в последних фреймворках, пакетах и так далее./blockquote>
                По-моему в контексте того, что вы процитировали не имеет смысла, похоже не то процитировали.
                Это смотря как посмотреть и придумать реализацию. Дублирование пакетов в папке vendor обеспечено.

                Не обеспечено, а вероятно. Более вероятные ситуации, как и упоминалось, выносятся в отдельные компоненты, кроме того при желании папка vendor в корне сайта и автозагрузчик composer так же подхватываются движком, можете указать там желаемые версии чего угодно.
                Для патчинга библиотек надо слать pull-request'ы автору, а затем запустить composer update. Почитайте про semver и то, как можно получать только патчи (обратная совместимость сохраняется) ссылка на доку.
                В других случаях применяют наследование, т.е. в папку vendor не лезут.

                Спасибо за капитанский комментарий, можете посмотреть мою активность на GitHub. Уверен, вы будете удивлены сколько патчей я уже отправил, и сколько ещё висят. Но пока разработчик не просмотрит и не одобрит патч мне тоже как-то нужно работать, верно ведь?
                за вас это давно сделали, зачем городить еще один велик в котором придется разбираться? Разработчику пишущему модуль куда логичнее и проще использовать то, что уже протещено многими людьми и то, что уже когдато изучил.

                Так используйте, в чём проблема? Если вы смотрели на разные системы — они все устроены по разному, и нет единого способа установить TinyMCE, например, чтобы он работал в любом фреймворке и использовал все его возможности. Для каждого фреймворка/CMS есть своя прослойка для интеграции. Тут аналогичная прослойка, не более, не менее. Субъективно прослойка гораздо проще для понимания.
                … ээм? Как это не нужно?

                Я имел ввиду писать, загрузчики уже есть написаны, потому и был взят загрузчик, который сгенерировал composer.
                суть совершенно не в этом. Я вам об одном, вы о другом. Посмотрите сначала стандарты psr-0 и psr-4. Подумайте, что реализовывать собственный автозагрузчик разработчику модуля будет лень, а пихать еще один композер внуть — как минимум, ужас принципа DRY.

                Начнем с того, что я знаю что такое PSR-0 и PSR-4, продолжим с тем, что в абсолютном большинстве модулей загрузчика нет вообще, системного достаточно (посмотрите код, что ли), по поводу DRY — да, согласен, не красиво, но храня абсолютно независимые модули в разных папках иначе не получится (либо вы подкажете такой способ).
                вы себе уже создали проблему, создав свой велосипед, вместо того, чтобы взять готовое и популярное решение :)

                Покажите мне ОДНО единственное решение которое позволит так же быстро поднять аналогичный сервер веб-сокетов с автоматической аутентификацией и обработкой событий на сервере и клиенте, с отправкой сообщений из любого места серверного кода. Опустим за рамками поддержку нескольких серверов и удобство/простоту системы как таковой.
                Мне кажется или это стоит делать с любым инструментом и техлогией?

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

                Любой фреймворк/CMS как минимум на половину велосипед (чаще почти полностью). Тем не менее на одном удобнее ездить чем на другом, хотя часто это субъективно. А про поддержку и добавление фич вы не можете говорить, не прочитав код (который GitHub форматирует криво), документацию, и не попробовав что-то реальное сделать. Это нормально, но только после этого вы сможете сравнить.
                  +1
                  По-моему в контексте того, что вы процитировали не имеет смысла, похоже не то процитировали.

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

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

                  дык, а зачем какие компоненты композера выносить глобально, а какие-то нет? Не проще ли разработчику модуля указать, какие зависимости требуется для его работы? А затем дело за вами, вы их подгрузите и установите в одну-единственную папку vendor.
                  К томуже, тотже разработчик, может в модуле наследовать и изменить, если надо нужные компоненты из композера.
                  Профит.
                  Так используйте, в чём проблема? Если вы смотрели на разные системы — они все устроены по разному, и нет единого способа установить TinyMCE, например, чтобы он работал в любом фреймворке и использовал все его возможности. Для каждого фреймворка/CMS есть своя прослойка для интеграции. Тут аналогичная прослойка, не более, не менее. Субъективно прослойка гораздо проще для понимания.

                  Немного не так выразился. Суть в том, что бы реализовать модульную систему без головной боли, в том виде в котором она есть сейчас. Например, манифест, в котором указать vcs ссылку на стабильный релиз TinyMCE. В общем более оптимальных вариантов полно. Короче, надо думать.
                  > «Субъективно прослойка гораздо проще для понимания» — только если в контексте модуля.
                  Единый способ установки «TinyMCE чтобы он работал в любом фреймворке и использовал все его возможности» описан на главной странице гитхаба редактора.

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

                  Именно. Я про это и говорю. Зачем писать свой автозагрузчик, когда проще изначально структуру проекта сделать в psr-4 и прописать в composer.json:
                  "autoload": {
                      "psr-4": {
                           "VendorName\\": "src/"
                      }
                  }
                  

                  ? Получается, мы выбросили на помойку 1 свой велосипед, предотвратили создание новых (например в модуле, своя либа, которую автолоадер cms не подгрузил) в модуле, а также, если использовать пакеты композера глобально, не создаем лишних папок vendor опять же в модулях.

                  посмотрите код, что ли

                  смотрел, мне на долго хватило… (я в целом)

                  либо вы подкажете такой способ

                  подсказал выше.

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

                  Смотрите внимательнее => «если же втискать его в систему зависимостей CleverStyle CMS, то получится что я создам проблему, которую потом придется самому же и решать»
                  ответ дал выше.

                  Касаемо цитаты:
                  Зачем? Его нет. Ведь это модуль заточенный чисто под нужны вашей cms.

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

                  Избегать как, своим велосипедом?

                  Любой фреймворк/CMS как минимум на половину велосипед (чаще почти полностью).

                  Это не оправдание писать свои велосипеды.

                  А про поддержку и добавление фич вы не можете говорить, не прочитав код

                  Смотрел. Очередной жестко зашитый вендор в ядре оО… своя реализация кеширования, работы с базой и так далее… чем не устроили готовые и стабильные варианты? Использовать тот же stash, к которому есть уже написанная документация и армия разработчиков умеющих его использовать. Фигак и у вас новый контрибутор помогающий в разработке. Смекаете?

                  Впрочем, мне надоело доносить эту мысль.
                    0
                    дополню:
                    Любой фреймворк/CMS как минимум на половину велосипед (чаще почти полностью).

                    А вы смотрели код? Laravel 5, например.
                      –1
                      дык, а зачем какие компоненты композера выносить глобально, а какие-то нет? Не проще ли разработчику модуля указать, какие зависимости требуется для его работы? А затем дело за вами, вы их подгрузите и установите в одну-единственную папку vendor.
                      К томуже, тотже разработчик, может в модуле наследовать и изменить, если надо нужные компоненты из композера.
                      Профит.

                      Так в том то и дело, что composer не является обязательным, это частный случай. В вашем случае я должен взять composer «потому что это современно и круто», сделать над ним обертку и вручную манипулировать этой кухней вместо того, чтобы просто положить библиотеку в папку модуля. Composer это круто, но это не повод совать его туда, где он не совсем вписывается.
                      Единый способ установки «TinyMCE чтобы он работал в любом фреймворке и использовал все его возможности» описан на главной странице гитхаба редактора.

                      Это всё круто, но почему-то не все хотят каждый раз велосипедить в каждом проекте, и пишут обертку для конкретной системы, которую постоянно используют. Первое что нашел для symfony, вот вам laravel, хоть по-моему устаревший репозиторий. Я хочу использовать TinyMCE без головной боли, которую как раз вы и предлагаете.
                      ? Получается, мы выбросили на помойку 1 свой велосипед, предотвратили создание новых (например в модуле, своя либа, которую автолоадер cms не подгрузил) в модуле, а также, если использовать пакеты композера глобально, не создаем лишних папок vendor опять же в модулях.

                      Вы не знакомы с архитектурой, и от этого не понимаете что иногда кроме просто распаковки файлов нужно сделать ещё некоторые операции, и это весьма распространено если мы имеем дело не просто с библиотекой. А еще есть обновление компонентов, в которых не всегда одной лишь миграцией структуры БД можно обойтись, и для всего этого придется писать столько клея, что вы потеряетесь в дебрях что и откуда запускается, кто кого вызывает, и что вообще происходит.
                      Смотрите внимательнее => «если же втискать его в систему зависимостей CleverStyle CMS, то получится что я создам проблему, которую потом придется самому же и решать»
                      ответ дал выше.

                      Спасибо за ответ, такого простого решения просто нет, либо вы о нем не знаете. По вашему мы должны взять composer, прописать зависимости, подключить фреймворк, написать немного клея, и если повезет то в течении суток получим франкенштейна, который маловероятно будет лучше. При этом его каждый пишет под себя, складывая в личную копилку (возможно немного утрирую, но суть комментария, думаю, ясна).
                      Избегать как, своим велосипедом?

                      Совершенно верно, если выбирать строить велосипед вокруг большого проверенного решения (его-то нужно интегрировать) либо просто небольшой велосипедик — то однозначно второе.
                      Это не оправдание писать свои велосипеды.

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

                      Напишу вам аналог примера из документации stash (никогда раньше не стыкался)
                      stash
                      function getUserInfo($userId)
                      {
                          $pool = $this->cachePool;
                      
                          // Get a Stash object from the cache pool.
                          $item = $pool->getItem('user', $userId, 'info');
                      
                          // Get the date from it, if any happens to be there.
                          $userInfo = $item->get();
                      
                          // Check to see if the cache missed, which could mean that it either
                          // didn't exist or was stale.
                          if($item->isMiss())
                          {
                              // Run the relatively expensive code.
                              $userInfo = loadUserInfoFromDatabase($userId);
                      
                              // Store the expensive code so the next time it doesn't miss.
                              $item->set($userInfo);
                          }
                      
                          return $userInfo;
                      }
                      


                      CleverStyle CMS
                      function getUserInfo($userId) {
                          $userId = (int)$userId;
                          return $this->cache->get("$userId/info", function () use ($userId) {
                              // Run the relatively expensive code.
                              return loadUserInfoFromDatabase($userId);
                          }
                      }
                      


                      Смекаете в чем разница? И так в каждом аспекте. Конечно, мы можем написать прослойку которая предоставит такой же интерфейс, но я уже об этом писал.
                      А вы смотрели код? Laravel 5, например.

                      Возьмем Laravel и пример с кэшированием, внимание, строчка из composer.json:
                      illuminate/cache

                      Угадайте, на какой кухне это приготовили? Угадайте, используют ли это в Symfony, Zend, Kohana, etc?
                      Ответ — возможно, но маловероятно.
                      Каждый пишет свою, якобы абсолютно независимую decoupled реализацию, которая тем не менее лучше всего подходит к вполне конкретному фреймворку, где, собственно, и используется.
                        0
                        Так в том то и дело, что composer не является обязательным, это частный случай. В вашем случае я должен взять composer «потому что это современно и круто», сделать над ним обертку и вручную манипулировать этой кухней вместо того, чтобы просто положить библиотеку в папку модуля. Composer это круто, но это не повод совать его туда, где он не совсем вписывается.

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

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

                        Как это относится к устранению лишних автозагрузчиков? Распаковка файлов модуля никак не мешает.

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

                        Любой разработчик уже потерялся в дебрях, не понимает что и откуда запускается, кто кого вызывает, и что вообще происходит в используемой clever cms.

                        Спасибо за ответ, такого простого решения просто нет, либо вы о нем не знаете.

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

                        По вашему мы должны взять composer, прописать зависимости, подключить фреймворк, написать немного клея, и если повезет то в течении суток получим франкенштейна, который маловероятно будет лучше.

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

                        А вообще, по моему — писать никаких новых cms не следует (максимум для собственно опыта — не более). Тысяч других для выбора хватает.

                        Совершенно верно, если выбирать строить велосипед вокруг большого проверенного решения (его-то нужно интегрировать) либо просто небольшой велосипедик — то однозначно второе.

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

                        Напишу вам аналог примера из документации stash (никогда раньше не стыкался)

                        Смекаю :)
                        function getUserInfo($userId) {
                            $item = $this->cachePool->getItem('user', $userId, 'info');
                            $userInfo = $item->get();
                            if($item->isMiss())  {
                                $userInfo = loadUserInfoFromDatabase($userId);
                                $item->set($userInfo); 
                            }
                            return $userInfo;
                        }
                        



                        А вообще, сравнение не верное. В вашем варианте, если кеш закончится, он всегда будет браться из базы (или по крайней мере я не вижу явного сохранения). К томуже, если важно сократить кол-ва кода, напишите враппер. И вуаяля, за полчасика у вас есть готовое кеширование в CMS. В чем преимущество своего велика?

                        Угадайте, на какой кухне это приготовили? Угадайте, используют ли это в Symfony, Zend, Kohana, etc?

                        Посмотрите, как Laravel, Kohana используют компоненты симфони.

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

                        Любой компонент современного фреймворка можно поставить себе без проблем. Но суть совершенно не в этом. Мы же решаем проблемы людей, которые используют cms, так зачем тратить время на создание не проверенных временем и сообществом инструментов?

                        P.S. Все вопросы риторические.

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

                          Вы опять пропустили половину комментария.
                          Как это относится к устранению лишних автозагрузчиков? Распаковка файлов модуля никак не мешает.

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

                          У моего подхода те же плюсы — баг фиксы и апдейты никуда не деваются, на счёт архитектуры то же самое, а вот дублировать объединение компонентов не нужно, они уже вместе работают, и работают хорошо, а этом принципиальное отличие.
                          зачем стоить велосипед вокруг большого проверенного решения? просто используйте его. Можно делать врапперы для удобства. Больше то зачем?
                          К велосипедику со временем возрастает кол-во требований и послепенно добавляется еще куча лапши, которую сложно поддерживать. Свои решение должны быть, но еще раз говорю, на каждый чих вендора не ищут.

                          Во-первых, обертка уже может быть больше велосипедика, а при росте требований вы так или иначе придете к моменту когда проще всё переписать заново, чем улучшать вашу обертку. Проверенное решение не часто 1 в 1 ложится на ваши требования, что с этим делать — ваше решение.
                          Смекаю :)

                          Тем не менее 6 строчек кода вместо 3х, на счёт удобства и понятности комментировать не буду, каждый сделает вывод для себя.
                          А вообще, сравнение не верное. В вашем варианте, если кеш закончится, он всегда будет браться из базы (или по крайней мере я не вижу явного сохранения). К томуже, если важно сократить кол-ва кода, напишите враппер. И вуаяля, за полчасика у вас есть готовое кеширование в CMS. В чем преимущество своего велика?

                          Сохранение есть, в том то и соль. Множество вещей реализованы для удобства, можно при желании и атомарные операции использовать. Обертку написать можно, но она не будет такой же быстрой, и такой же оптимальной, на взаимодействие будут дополнительные расходы. Zip архив со stash занимает 105 КиБ, всё что относится к кэшированию в CleverStyle CMS занимает 20.8 КиБ в незапакованом виде (и это ещё @ inheritdoc редко используется).
                          Посмотрите, как Laravel, Kohana используют компоненты симфони.

                          Я тоже использую PhpMailer, passwords_compat на сервере, и ещё много готового на клиенте, и что? Это же самая прямая аналогия.
                          Любой компонент современного фреймворка можно поставить себе без проблем. Но суть совершенно не в этом. Мы же решаем проблемы людей, которые используют cms, так зачем тратить время на создание не проверенных временем и сообществом инструментов?

                          Вот я и стараюсь решить проблему максимально простым и оптимальным образом. Если в результате появляется что-то отличное от существующего, но при этом гораздо проще в понимании и использовании, что почему нет, Я не пытался и не пытаюсь полностью скопировать что-то другое, в этом нет смысла, можно просто взять готовое.
                            0
                            В последнем релизе появился новый модуль Composer. Теперь в мета-информации компонента (файл meta.json) можно в параметре require_composer указать зависимости от пакетов composer, и они будут установлены с компонентом автоматически (доступ к CLI не нужен в принципе).
                            Это сделано в первую очередь для того, чтобы не подключать разные версии одних и тех же компонентов, ну и чтобы не дублировать файлы, пример для обновленного модуля WebSockets: github.com/nazar-pc/CleverStyle-CMS/blob/master/components/modules/WebSockets/meta.json#L14
                              0
                              (:

                              @-todo:
                              1. Сделать компоненты (cache, event, mailer и т.д.) ядра менее связанными (пруф)
                              2. В этот же момент избавиться от антипаттерна singleton (link). Краткость вызова никто не отменял (первые 2 ссылки для примера) — link, затем посмотреть это link и это link. Для зависимостей использовать Service Container или еще лучше полноценный IoC c их внедрением. Например link или link.
                              3. Вынести их в свой публичный репозиторий, добавить composer.json и радоваться :) Теперь я могу использовать ваши велосипеды имея уверенность, что там пофикшены последние баги (link) и они работают отдельно от CMF. Пример, как выносят компоненты.

                              Плохого не посоветую.
                                0
                                1. Они становятся менее связными от версии к версии, но передавать зависимости способом в линке, понятное дело, не удобно
                                2. Если разобраться — то это и не singleton на самом-то деле, но название сразу объясняет вам что вы получите в результате. На самом деле Page::instance() полностью аналогично $app->Page(), менять это на View::display() — ну извините, зачем мне дополнительный вызов __callStatic() (на самом деле вы можете даже добавить точно такое же поведение, переопределив Singleton, читайте дальше)? Как по мне ::instance() достаточно лаконичное и простое решение. PHP-DI, к примеру, это хорошо, но зачем разбирать PhpDoc секции, если можно этого не делать?
                                3. Но тогда для автономной установки нужно будет:
                                a) Иметь локально composer
                                b) Или включать phar размером больше мегабайта в дистрибутив (что почти удвоит его размер)

                                Singleton в текущем виде весьма гибкая штука, вы можете заменить его внутренности на что угодно при надобности. Как доказательство — вчерашняя статья, движок по сути работает в request/response режиме, при этом может даже работать с асинхронностью (модифицированный Singleton trait).

                                Singleton trait это легкий способ централизировать создание объектов, при этом не форсируя статический анализ IDE принудительным указанием объектом какого класса является какая переменная, и не увеличивая цепочку вызовов без особой на то надобности. Просто другое решение той же задачи.

                                Ну а на счёт Symfony — там всё на столько академически, что уровни абстракции не позволяют понять, а что на самом деле вызывает что. Общаясь с некоторыми разработчиками складывается впечатление, что они пользуются, но не понимают, как оно устроено, а при попытке понять погружаешься в такой стек вызовов, что теряешься в нем.

                                В случае CleverStyle CMS ядро просто на столько, на сколько возможно, и оно постепенно ещё больше упрощается. При возникновении любой ошибки вы легко сможете понять что случилось из стека вызовов. Это стоит того, чтобы избегать overengeneering'а. Вы же заметили как сейчас можно использовать composer? Добавить зависимости в meta.json, всё поставиться из GUI, не нужно ни командной строки, ни наличие composer в системе. Всё максимально просто и легко интегрируется в простое ядро.
                  0
                  Удалил все оставшиеся global из моего кода, включая установщик)
              0
              я правильно понимаю, что вы на пыхпыхе написали именно ws-сервер?
                0
                Веб-сервер сам по себе в библиотеке Ratchet, я его интегрировал, но не писал с нуля. Он написан на PHP, да.

              Only users with full accounts can post comments. Log in, please.