Как-то я уже предпринимал попытку объяснить устройство комплексного компонента. Но тогда был сам помоложе и поглупее. Делаем дубль два [spoiler] Зачем он вообще нужен?
Комплексный компонент это такая удобная штука, которая объединяет много-много мелочей. Их не надо бояться. Более того, при разработке чего-то публичного, где более одной страницы, обязательно собирайте мелочь в комплексные. Хороший пример - форум, насчитывающий десятки мелких компонент, но на странице форума компонент один - комплексный. Ну и еще важный аргумент - комплексный компонент легко позволяет сделать ЧПУ.
Не бойтесь дробить, но и меру знайте. При дроблении важно соблюсти инкапсуляцию и причастие к тому или иному. Например, облако тегов, это ведь отдельный маленький компонент, который показывается в форуме тоже, а относится вообще к модулю поиска.
В общем, маленькие компоненты - это домики, детские площадки, песочницы, даже урны; комплексный - улица, квартал, или даже район города. Ну а наш сайт - это город
Давайте строить город
Самое главное
Комплексный компонент, за редкими исключениями, не несет никакой логики (примерно как абстрактный город абсолютно без всего). Поэтому, каждый мелкий компонент должен уметь работать автономно, а комплексный их лишь объединяет.
Есть разумные исключения, когда в комплексный компонент можно включить логику. Например: проверка авторизации, установка title.
Общая структура
Здесь и далее я буду опускать ланг-файлы для облегчения кода. Да и вообще, с новым решением из Маркета вы можете писать прямо в коде кирилицу, а потом билддить полноценный модуль. Также я постараюсь избегать кодов, так как они некрасивые (а по некрасивому неприятно учиться), а ставить скриншоты. Примеры вы сможете найти в любом комплексном компоненте.
Также, я предполагаю, что вы уже знаете как устроен обычный компонент, как его размещать в дереве компонент, поэтому опишу только отличающиеся файлы.
Итак, в корне компонента у нас вот что:
.description.php стандартный, .parameters.php и component.php разберем ниже.
В templates у нас папка шаблона. .default пусть будет. Можно также иметь несколько шаблонов одного комплексного компонента. Все то же самое, как и у обычного. А вот внутри шаблона уже структура иная:
(это мы перешли в шаблон .default)
На этом мы тоже остановимся ниже.
.parameters.php
Он объединяет в себе все настройки всех внутренних компонент, которые можно (это важно, не надо туда все пихать) менять. Например, если внутри комплексного есть компонент списка новостей, то разумно вынести в общие настройки выбор ИБ и кол-во на странице. Но не стоит выводить "Проверять права", если логика вашего компонента подразумевает, что права мы будем проверять обязательно. Это будет тоже ниже показано.
Помимо таких общих настроек есть блок VARIABLE_ALIASES и SEF_MODE.
VARIABLE_ALIASES
Задает переменные для работы НЕ в ЧПУ, хотя поддержка такого режима нужна скорее для хорошего тона:
Визуально это превращается в:
Тут надо перечислить все значимые параметры для отображения того или иного внутреннего компонента. На следующих скриншотах будет понятно о чем я говорю:
(отдельная страница)
(динамический элемент)
Далее SEF_MODE, это всем знакомый ЧПУ. В коде делается так:
(тут вам надо обратить внимание на ключи массива, а также на дефолтные значения, первое обязательное, а второе избавит клиента от придумывания адресов; каждый элемент массива подразумевает под собой какой-то отдельный компонент (отдельную страницу))
А превращается это в уже вам знакомое:
Ну а в публичной части при режиме ЧПУ мы уже видим ЧПУ-адреса, скриншоты делать не буду. На этом .parameters.php готов.
component.php
Код, описываемый здесь, вы можете посмотреть по ссылке.
В самом начале задаем дефолтные значения для не ЧПУ и ЧПУ режимов соответственно. То есть, переменные и пути по умолчанию, если компонент на настраивали, или что-то сбилось.
Кстати, присмотритесь к ключам второго массива $arDefaultUrlTemplates404, они равны ключам массива SEF_MODE из настроек. Значения первого же соответствуют переменным из настроек компонента, но они роли не играют, хотя лучше ставить одинаковые, чтобы не путаться.
Эти две строчки из массива SEF_MODE настроек и из текущего пути вычисляет а какой же компонент нам подключить. $componentPage будет содержать тот ключ массива SEF_MODE, который и активен в настоящий момент. Например, для страницы http://test.d-it.ru/tube/load/ сработал ключ load, и $componentPage равен 'load'.
Также обратите внимание на выделенные переменные: $arDefaultUrlTemplates404 как раз массив по умолчанию, заданный в предыдущем шаге.
Далее на скриншоте мы подготавливаем URL для использования в шаблоне По сути, их может и не быть, это просто является хорошим стилем, чтобы не городить URL внутри шаблонов.
Далее в коде мы уже можем работать с наполненным массивом $arVariables, где содержатся переменные, и мы можем по ним судить - какую страницу отобразить. if (isset($arVariables['load'])) - значит это страница загрузки, if ($arVariables['section_id'] != '') - значит страница категории. Обращу внимание, что мы тут абсолютно не зависим от того какие переменные пользователь укажет в реальных настройках. Он может страницу загрузки обозвать не ?load, а ?upload. Все продолжит работать. Это же верно и для ЧПУ - какие бы пути не ввел настройщик, все будет работать.
Цель второй части кода на скрине это собственно узнать, какой компонент подключать. Это содержится в $componentPage, и на этом первая часть (ЧПУ) и вторая (текущая, не ЧПУ) сходятся в результате.
Помните как мы выше строили пути для ЧПУ-варианта? Вот тут то же самое, только для не ЧПУ. Это (и в ЧПУ в том числе) надо для того, чтобы в шаблоне не заботиться о том, в каком режиме мы работаем. Там мы оперируем уже URL, которые содержатся в переменных.
Например, в $arResult['PATH_TO_LOAD'] для ЧПУ будет что-то типа /tube/load/, а для не ЧПУ будет /tube/?load. Понятно? Я знаю, что это на жаргоне паттерно-любителей это как-то круто называется, но умничать не будут, не знаю
Ужасы кончились, дальше идет $this->IncludeComponentTemplate($componentPage);
причем общий (!) для двух режимов (ЧПУ и не), так как $componentPage мы вычислили.
Динамические переменные
Это конкретная новость, или категория новостей (например). То есть, для построения участвует динамический параметр. Например, /section/123/ - вывести элементы секции 123.
Так вот, в описываемой схеме, для любого режима (ЧПУ / не) данные динамические переменные будут содержаться в $arResult["VARIABLES"]. Для примера /section/123/ выше будет что-то типа:
[VARIABLES] => Array
(
[ID] => 123
)
И тогда внутренней соответствующей компоненте мы уже передадим параметр, что надо вывести секцию с определенным ID. Например, так:
Шаблон
Структуру на скрине я кидал выше. Рассмотрим опять же load.php. Вы, подозреваю, уже поняли, что именно load.php подрубится для ключа load? Если нет, то вот он, результат магии.
Внутри этого файла идет вызов компонента:
Может быть и несколько компонент. Может быть даже минимальный html. Например,
но именно минимальный! Кстати, видите как мы передаем внутреннему компоненту настройки комплексного? А некоторые вбиваем насильно, так как подразумеваем, что здесь такая логика, и не может быть иной (продолжая аналогию города, установим в данном доме детскую площадку с песочницей, без права ТСЖ ее убрать).
Обратите внимание на подчеркнутую строчку. Обычный код вызова компонента содержит там false, или ничего. Тут же мы показываем, что компонент вызывается из компонента, и он должен считать себя пасынком.
Это нужно по ряду причин, а в частности для того, чтобы компонент хранил свои шаблоны ВНУТРИ шаблона комплексного. Посмотрите еще раз на скрин файлов шаблона в самом начпле. Видите там папочку bitrx? Вот там лежат шаблоны всех внутренних компонент:
Коль мы сосредоточились на компоненте загрузки, то опять обратим внимание на него, он выделен в списке. Внутри этой папки лежит шаблон компонента asd.tube.load с позапрошлого скрина. Так как там мы не передали название шаблона, то он называется .default. Может и иначе называться.
Вы спросите почему подпапка с шаблонами называется bitrix? Потому что компонент asd.tube.load лежит в пространстве bitrix. Какое пространство, такая и подпапка.
Если же, на позапрошлом скрине не указать $component, то компонент не будет считать себя пасынком, и подключит свой шаблон, который лежит у него, а не возьмет его из подпапки комплексного.
Вот, собственно, и все. Возможно, некоторые моменты могут показаться сложными. Если это так, сообщите, я разжую побольше.
Советы
Сюда я буду дописывать рекомендации, какие вспомню, или что дополнят в комментариях.
Стили и js-скрипты. Лучше выносить в общие файлы, которые складывать внутрь уже комплексного шаблона, а у внутренних компонент их убивать. За редкими исключениями - например, если компонент редко фигурирует, а скрипты или стили у него тяжелые.
PS: Я дал облегченную версию ЧПУ-компонента, в реальных компонентах вы увидите много лишнего, хотя зачем оно реально нужно, я лично не понял. Если я что-то упустил важное, укажите, пожалуйста, в комментариях.
А в качестве дополнительных материалов можно почитать:
Долганин Антон написал: Стили и js-скрипты. Лучше выносить в общие файлы, которые складывать внутрь уже комплексного шаблона, а у внутренних компонент их убивать
На самом деле они вроде бы даже не подключаются. Не помню этот момент. Ну а почему они не нужны в принципе - потому что в случае комплексного мы оперируем именно комплексОМ, и стили правильнее заводить общие. Ну JS можно еще дробить. Но это имхо.
Группы на сайте создаются не только сотрудниками «1С-Битрикс», но и партнерами компании. Поэтому мнения участников групп могут не совпадать с позицией компании «1С-Битрикс».