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

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

Ранее и сейчас, весь код проекта на Битрикс хранился исключительно внутри DOCUMENT_ROOT. Это, конечно, прозрачно и понятно, однако не имеет никакого смысла хранить весь код именно там. Причин тому несколько:

  • Этот код будет доступен из веб (в случае с битриксом, это вполне вероятно, если за этим специально не следить)
  • Есть всякие другие интересные вещи, которые не имеет смысла хранить в DOCUMENT_ROOT, например логи, конфиги, сторонние библиотеки

Рассмотрим на примере. Назовем наш абстрактный сайт site.ru. Ранее он хранился бы где-нибудь в /var/www/site.ru и это был бы его DOCUMENT_ROOT. Но в реальности правильнее было бы создать еще один уровень вложенности и переместить корень туда. В нашем примере это может быть, например, /var/www/site.ru/htdocs.
Что в реальности это дает?

Во-первых, логи

Вы можете создать директорию с логами. /var/www/site.ru/log. В этой директории можно хранить логи веб-сервера, а также логи самого проекта. Благодаря этому, вы можете быстро с помощью консоли получить доступ к нужным логам. В директории с логами можно организовать любую удобную структуру. Например, для логов веб-сервера использовать такие имена директорий, как apache2 и nginx (как в /var/log). Для каждого своего сервиса создать отдельную директорию с логами. Кстати, если кто-то еще пишет свои собственные классы с логами, то примите к сведению, что есть такая мега-удобная и гибкая штука, как monolog, а также его адаптация под битрикс от BEX. Этот логгер полностью соответствует стандарту логирования PSR-3.
Удобно.

Во-вторых, зависимости.

Пропадает необходимость хранить библиотеки composer в /local директории битрикса. Само по себе хранение зависимостей внутри /local как-то противоречит самой идее данной директории, т.к. в ней должен находиться только версионируемый код разработчиков. Да и обычно все зависимости размещаются непосредственно начиная от корня проекта, но в случае с битриксом это может превращаться в неудобство.
Если же мы переносим зависимости из /local в корень проекта (а не DOCUMENT_ROOT), то мы сразу убиваем двух зайцев, удовлетворяя обычным практикам использования composer, а также более правильно следуем самой идее директории /local.
Таким образом, получается, что composer.json, composer.lock и директория /vendor будут располагаться в /var/www/site.ru. И эти файлики не будут беспокоить заказчика, если он дотошный. А чтобы поставить зависимости, достаточно зайти в корень проекта и запустить команду установки, все логично и очевидно:

cd /var/www/site.ru && composer install

Удобно!

В-третьих, статика.

Прошлый пост этой серии я закончил на том, что у меня осталась нерешенной проблема со статикой. На момент написания этих строк, проблема со статикой почти решена. Пока что я пришел к выводу, что нет пока более удобного инструмента для сборки статики, чем webpack. Мы постепенно внедряем его в наши проекты, однако его конфигурация, а также все зависимости npm хранятся также внутри DOCUMENT_ROOT, что не является целесообразным.

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

В-четвертых, версионный контроль.

Я надеюсь, что ни для кого из вас не секрет, что хранить системные файлы репозитория внутри DOCUMENT_ROOT не очень хорошо. Обычно, достаточно вынести репозиторий на уровень выше, и слинковать его с рабочей копией с помощью опции worktree. Однако это лишает репозиторий возможности использовать некоторые фишки, например stash, или submodules (будь они прокляты! не используйте их 🙂 ), и еще некоторых возможностей. Хорошо, если на продакшене это не нужно, но мне бы хотелось иметь полный контроль над репозиторием. В связи с этим, я в последнее время переношу репозиторий в корень рабочей копии, и закрываю директорию /.git с помощью .htaccess, например.

Если же мы используем предложенную схему, то рабочей копией репозитория можно сделать директорию /var/www/site.ru, и не придется ничего мудрить.
Крутяк!

В-пятых, да придумать то можно что угодно!

Хотите хранить бекапы - можно вынести их на новый уровень вложенности. Хотите какие-то консольные скрипты - выносите их туда же. Юнит тесты - да легко! Любые конфигурационные файлы - всегда пожалуйста: composer.json, package.json, bower.json, webpack.config.js, phpunit.xml.dist, travis.yml - к вашим услугам, не надо это хранить в DOCUMENT_ROOT. Можно и кеши какие-то свои вынести на этот уровень. Да все, что душе угодно.

Таким образом, получается нечто такое (серым помечены исключенные из версионного контроля вещи, а структура начинается с /var/www/site.ru):

Немного по модификациям того, о чем я писал ранее.

Автозагрузка классов

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

{
    "autoload": {
        "psr-4": {
            "Maximaster\\": "htdocs/local/classes/"
        }
    }
}

Ну и остается следовать стандарту PSR-4, тогда автозагрузчик будет прекрасно работать в тандеме со всеми вашими зависимостями.

Ajax

К черту /local/ajax. Самым правильным решением будет организация единого API. Например, для внутреннего API использовать путь /api/internal. Создавать директорию под это дело совсем не обязательно, лучше обойтись без лишних папочек, несмотря на всю файловую природу битрикса.

Cron

К черту /local/cron :smiley:. Не надо плодить отдельные скрипты для каждой задачи. Используйте symfony/console или console jedi (который основан на symfony/console) для создания консольных команд. А на крон уже цепляйте созданные задачи, а не выполнение конкретных скриптов.

UPD. Нашелся, все же, небольшой косячок у всей этой структуры. В PHPStorm $_SERVER[‘DOCUMENT_ROOT’] резолвится в корень проекта. А тут корень проекта не будет соответствовать корню виртуального хоста на сервере. Из-за этого многие инклюды в битриксе не будут резолвиться корректно при просмотре их в IDE. Но это, на мой взгляд, очень несущественная и маленькая проблема, которая полностью покрывается всеми теми плюсами, которые дает предложенная структура.