Организация кода в Битрикс — к обсуждению

1c

Не сохранилась половина статьи про исключения ….(( а написал много. Поэтому пока их отложу, а напишу про битрикс.

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

Что нам предлагает битрикс

Слава разработчикам, что они наконец-то начали отделять код ядра от кода разработчиков. С 12й версии битрикс появилась возможность использовать директорию /local (более полная поддержка пришла с 14й версией). Данная директория должна находиться в корне сайта. По структуре она полностью повторяет структуру директории /bitrix, за тем исключением, что в ней нет файлов ядра (встроенных модулей, компонентов и т.д.). Что же может содержать в себе директория  /local? Основываясь на статье перечисляю поддерживаемые вложенные директории:

  • /local/activities — действия из модуля бизнес-процессов
  • /local/components — сторонние компоненты
  • /local/gadgets — гаджеты для рабочего стола админки
  • /local/modules — сторонние модули
  • /local/php_interface — работает только init.php и директория user_lang (для подмены языковых файлов)
  • /loca/templates — шаблоны сайта

Директория local имеет приоритет перед /bitrix, т.ч. при одинаковых именах файлов будет использован вариант из /local.

Шаблон сайта

Вроде все базово, все и всё знают, однако сколько проектов ни видел, нигде нет единого варианта. Шаблон сайта должен находиться в директории /local/templates/<templatename>. Структура файлов директории с шаблоном сайта достаточно подробно расписана тут, а я все-таки остановлюсь немного подробнее на нескольких файлах:

  • header.php и footer.php. Пожалуйста — не стоит размещать в них логику. Только в самых крайних случаях. Надо понимать — что это файлы шаблонов — а в шаблонах должны быть только шаблоны, и ничего более. Тупой пример с одного из проектов, где в header.php определяется тип пользователя. Мало того, что логика в шаблоне, так и код еще ужасный:

    Если хотите разместить блок с какой-то логикой, то набросайте по быстрому компонент, это будет правильнее
  • template_styles.css — несмотря вполне логичное название файла, переводимое как «Стили шаблона» разработчики часто вставляют туда все свои css стили. Нужно использовать этот файл для хранения только тех стилей, которые относятся именно к данному шаблону
  • images/ — в этой директории должны храниться изображения шаблона. Не нужно в шаблоне использовать изображения из других директорий. Сохраните все картинки верстки в ней и подключайте отсюда
  • components/ — тут должны находиться кастомизированные шаблоны только стандартных компонентов или компонентов сторонних разработчиков. Не нужно кастомизировать шаблоны написанных вами компонентов! О компонентах — ниже

Компоненты, свой — чужой

Часто наблюдаю нелепую ситуацию. Разработчик написал компонент, узкоспециальный, который решает конкретную в рамках продукта задачу. Сохраняет код компонента в /local/component/mx/my.component. А шаблон внезапно выносит зачем-то в шаблон сайта, или того хуже — в /bitrix/templates/.default/components/mx/my.component/templates/. Есть еще уникумы, которые в шаблоне своего компонента пишут result_modifier.php, который изменяет результат собственной выборки. На мой взгляд это полный бред. Если уж ты написал компонент, который правильно будет работать с конкретным шаблоном, то храни шаблон компонента внутри директории компонента /local/components/mx/my.component/templates. Если шаблон этого компонента работает исключительно с определенным шаблоном сайта, то я бы назвал шаблон этого компонента по имени шаблона сайта. И уж тем более не нужно использовать result_modifier.php, когда эту логику можно оставить в теле компонента.

Также, разработчики часто забывают про возможности ООП внутри компонентов. Если кто не знает, то уже давно внутри компонента можно создать файл class.php, который должен содержать класс, унаследованный от CBitrixComponent.
Благодаря этому можно использовать наследование классов других компонентов при создании своих — иногда это очень полезный инструмент. Подробнее — тут.

Перед тем, как кастомизировать встроенный компонент — нужно 1000 раз подумать, а действительно ли он не соответствует вашим требованиям? Может вместо копирования встроенного компонента лучше прибегнуть к написанию собственного? Если вы все-таки решили скопировать встроенный компонент, то обязательно документируйте, что и где вы изменили внутри этого компонента, это сильно поможет другим разработчикам, а также поможет при обновлении компонентов при обновлении ядра.

Собственные и сторонние классы, библиотеки

Я предлагаю для хранения библиотек и классов завести директорию /local/lib. Для php библиотек — /local/lib/backend, для js — /local/lib/frontend
Внутри директории для php библиотек можно хранить библиотеки и классы по типу, описанному в одной из моих статей. В идеале — приводить свои библиотеки к виду, регламентируемому замечательным composer (про него когда-нибудь тоже напишу).
Каждая js библиотека должна храниться в отдельной директории, т.к. для библиотеки часто в комплекте может идти несколько css файлов, map, или еще чего. Ну и удобнее так будет, ибо нужно хранить и исходник файла, и его минифицированную версию.

Для конфигураций предлагаю создать директорию /local/config, внутри которой вижу следующие файлы:

  • const.php — константы вашего проекта
  • events.php — вызовы AddEventHandler для всех возможных кастомных обработчиков событий проекта.
  • frontend.php — регистрация js библиотек из /local/lib/frontend/ — об этом ниже

Не нужно подключать все свои js файлы прямым включением в шапку сайта. Для подключения js файлов в битриксе есть добротный класс CJSCore. Можно зарегистрировать все свои js библиотеки, и подключать их строго на нужных страницах. Для регистрации библиотек используем файл, который должен быть подключен на всех страницах нашего проекта — /local/config/frontend.php

Ниже в примере показано, как зарегистрировать библиотеку и подключить ее:

Содержимое файла /local/config/frontend.php

Кто напишет автолоадер — тому пирожок, я пока на таком варианте остановился.

Для подключения зарегистрированной библиотеки на какой-то странице сайта, используйте конструкцию:

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

Прочее

/local/cron — скрипты, которые должны запускаться по крону
/local/ajax — скрипты, обращение к которым происходит посредством ajax из каких-то библиотек, компонентов и пр.
/local/admin — для подключения скриптов, содержащих интерфейс для административного раздела

Здравый смысл

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

UPD. Написал небольшое продолжение и дополнение для данной статьи
UPD2. Многое из статьи стало не актуальным спустя время. Продложение статьи тут

  • > Да и по коду проще искать, чем по списку файлов
    Это только потому что в phpStorm ужасное дерево файлов ))
    В целом согласен везде есть свои + и — и если говорить начистоту они не критичные и «на вкус». Мне лично не сильно принципиально

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

  • Организация конечно нужна. В целом согласен, но по поводу:

    > events.php – вызовы AddEventHandler для всех возможных
    > кастомных обработчиков событий проекта
    А где сами функции храниться будут?

    Есть так же ситуации когда например пишешь класс и обработчик удобнее поставить ему самому (если там внутри какая-то логика с этим запрограммирована).

    Я лично храню event’ы в отдельной папке, и под каждый тип события создан отдельный файл.

    Это упрощает нахождения событий, а так же уменьшает риск совместных правок. Вот бы и сюда автолодер 🙂

    • Я бы предложил вынести все обработчики в один namespace, допустим Mx\EventHandlers.
      Для каждого модуля можно сделать класс. Каждый метод такого класса — обработчик какого-то события. Один класс = один файл. Сразу будет видно в классе, сколько обработчиков какого события существует (в шторме — структура класса), а то бывает часто создают несколько очень мелких обработчиков, которые можно было бы объединить в один — вот будет повод замечать подобные вещи. В разных классах можно дать одинаковое наименование для разных по назначению обработчиков, что тоже может быть иногда полезно
      В AddEventHandler нужно будет передавать тогда последним параметром массив, например так:
      AddEventHandler(
      'iblock',
      'OnAfterElementAdd',
      array('\\Mx\\EventHandlers\\Iblock', 'sendMessageAfterProductAdd')
      );

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

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