Теперь вся мощь ООП проектирования доступна в компонентах 2.0
[spoiler]
Рассмотрим простейший компонент возводящий параметр в квадрат.
/bitrix/components/demo/sqr/component.php:
<?if(!defined("B_PROLOG_INCLUDED") || B_PROLOG_INCLUDED!==true) die(); $arParams["X"] = intval($arParams["X"]); if($this->startResultCache()) { $arResult["Y"] = $arParams["X"] * $arParams["X"]; } $this->includeComponentTemplate(); ?> |
<?if(!defined("B_PROLOG_INCLUDED") || B_PROLOG_INCLUDED!==true)die();?> <div class="equation"> <?echo $arParams["X"];?> в квадрате равно <?echo $arResult["Y"];?>. </div> |
А теперь "внезапно" представим, что операция умножения это не одна звёздочка, а три десятка строк и таких операций у нас 5-6. В результате файл component.php превращается в тяжело понимаемый мегамот (см.
Выделяем логику компонента в класс.
/bitrix/components/demo/sqr/class.php
<?if(!defined("B_PROLOG_INCLUDED") || B_PROLOG_INCLUDED!==true) die(); class CDemoSqr extends CBitrixComponent { //Родительский метод проходит по всем параметрам переданным в $APPLICATION->IncludeComponent //и применяет к ним функцию htmlspecialcharsex. В данном случае такая обработка избыточна. //Переопределяем. public function onPrepareComponentParams($arParams) { $result = array( "CACHE_TYPE" => $arParams["CACHE_TYPE"], "CACHE_TIME" => isset($arParams["CACHE_TIME"]) ?$arParams["CACHE_TIME"]: 36000000, "X" => intval($arParams["X"]), ); return $result; } public function sqr($x) { return $x * $x; } } |
/bitrix/components/demo/sqr/component.php:
<?if(!defined("B_PROLOG_INCLUDED") || B_PROLOG_INCLUDED!==true) die(); if($this->startResultCache()) { //$this - экземпляр CDemoSqr $arResult["Y"] = $this->sqr($arParams["X"]); } $this->includeComponentTemplate(); ?> |
Теперь код в файле component.php стал управляемым.
Есть возможность наследования компонент.
Например (декоратор):
/bitrix/components/demo/double_sqr/class.php
<?if(!defined("B_PROLOG_INCLUDED") || B_PROLOG_INCLUDED!==true) die(); //Необходимо для корректного поиска класса CDemoSqr CBitrixComponent::includeComponentClass("demo:sqr"); //Наследник расширяющий функциональность: class CDemoDoubleSqr extends CDemoSqr { public function sqr($x) { return parent::sqr($x)*2; } } |
/bitrix/components/demo/double_sqr/component.php
идентичен - копируем
/bitrix/components/demo/sqr/component.php
/bitrix/components/demo/double_sqr/templates/.default/template.php:
<?if(!defined("B_PROLOG_INCLUDED") || B_PROLOG_INCLUDED!==true)die();?> <div class="equation"> <?echo $arParams["X"];?> в квадрате взятое дважды равно <?echo $arResult["Y"];?>. </div> |
Можно создать и компонент без файла component.php
Для этого достаточно перекрыть метод executeComponent.
Например:
class CDemoSqr extends CBitrixComponent { ... public function executeComponent() { if($this->startResultCache()) { $this->arResult["Y"] = $this->sqr($this->arParams["X"]); } $this->includeComponentTemplate(); return $this->arResult["Y"]; } } |
Теперь из обоих компонентов можно удалить файлы component.php.
Успехов в применении ООП!
Но без фанатизма
Сейчас думаю, что большие компоненты - это зло, даже с классами. Выношу классы в отдельные файлы и автолоадом подключаю.
Но бывает так, что нужна в компоненте пара функций. И тогда такой класс будет очень полезным. А еще статические переменные в классе. Вообще здорово.
Тяжелую бизнес логику лучше держать в такой сущности как "модуль".
А по теме - отлично! Дождались
Как один из подходов, можно попробовать выделить что-то общее у группы компонентов.
Например во всех catalog.* есть логика складывания товара в корзину.
Не вижу причин сложить её в единое место и править только там. Учитывая то обстоятельство, что остальной функционал "перпендикулярен".
В файле /main/classes/general/component.php всё в порядке + php doc
Еще раз извини, это не негатив, а мое непонимание Скажем так, был бы благодарен за пример применения в обычном сайте. Или по другому - какой бы из текущих компонент прекрасно лег на эту логику?
Я при3наться игрался в ООП, но практического применения кроме как своиx в модуляx — не вижу пока. Посмотрим, что будет.
Судя по уровню исполь3ования новыx фишек ра3работчикам (иx основной части) потребуется годик для того что бы распробовать фишку.
Имxо, бе3 популяри3ации и лучшиx практик от Максима и команды Битрикса вxождение будет гора3до более долгим. Пример JS - фреймворк битрикса.
Так что тут уж лучше правило — демо и документация в первую очередь!
В нём очень нетривиальная логика вычисления состояния чекбоксов.
После первого подхода в рамках "классического" component.php у меня просто опустились руки...
Был выход - вынести логику в модуль инфоблоков. Но кому она там нужна? (не считая этого компонента).
И тут как свет в конце тоннеля! Озарение! (заодно решил задачу возложенную на меня).
Но только для тестирования API модулей, не компонентов.
Представляется очень сложным написать реалистичный тест для компонента.
Основная сложность в наполнении тестовыми данными. Да и объектом теста в лучшем случае можно сделать arResult, ведь выход 98-й версии хрома просто сломает верстку...
в каждом компоненте делали папку /classes/ и туда логику складывали (классы), плюс автозагрузчик к ним.
Один раз даже компонент у нас базовый работал как выборка, он просто возвращал данные, мы вызывали его из других. При таком новом подходе мы просто бы вынесли логику в метод класса базового компонента и подрубали бы в остальных, где он нужен.
я правильно понял, что /component_name/class.php - это зарезервированное имя файла, и такой файл автоматом будет подключаться?
При вызове $APPLICATION->IncludeComponent()
идет вызов final метода initComponent в котором и подключается class.php если он есть и из него берется самый последний класс наследник от CBitrixComponent
Т.е. непонятное шаманство вида
Осталось написать автолоадер - и вперёд
1) позволяют программисту использовать более короткую запись;
2) облегчают автоматический анализ кода.
И за счет чего достигается уникальность имён компонент в рамках системы?
В случае общего пространства имён, его каждый раз указывать не требуется. Пространство заводится чтобы отделить систему от других интегрируемых систем например и чтобы не захламлять корневое пространство своими классами.
1) В случае пространств имен Вы говорите "О, не надо захламлять, вводим простанство имён \Primer"
2) В случае "сейчас" Вы говорите "Ну, оно лежит в одной папке, и так сойдет"
Пока что Вы не привели ни одного четкого примера, который был показал преимущество записи без неймспейсов (и без передёргиваний)
Более того, я утверждаю обратное: в любой непротиворечивой системе именования классов, которую можно реализовать и "по старинке", и на пространствах имён, [полная] длина имён получится одинаковой (с точностью до служебных символов).
Был CCatalogProduct, стал \Catalog\Product .
Был CSocNetGroupSubject, стал \SocNet\GroupSubject .
Был CIBlockElement, стал \IBlock\Element .
Был CFile, стал \Main\File - потому что текущее имя, строго говоря, дефектно (не включает имя модуля)
CatalogProduct
1) обеспечить именование классов так, чтобы допустить встраивание других систем
2) произвести переход к неймспейсам.
Понятно, что если первую задачу планируется делать, то лучше её выполнить перед второй, дабы не совершить лишней работы.
Но также понятно, что сейчас не будет выполняться ни первая, ни вторая задача. Внести какие-то существенные изменения можно было в 12-й версии, ознаменовав это как "переход к PHP 5.3" . А теперь это банально никто не купит
"Серебрянной пули - нет".
Но теперь изменившаяся парадигма позволяет стройные реализации.
Все-таки хотелось бы что бы ООП в Битриксе не было просто тупой оберткой функционального кода. (распихали код в классы и по методам и типа у нас ООП).
Не, нету. По крайней мере, я разброд наблюдаю примерно с появления модуля "соц.сеть".
А в более старом коде сталкиваешься с двумя вещами:
- вместо массива $arSort - 2 отдельных параметра, которые ещё и принимаются по ссылке
- вместо объекта класса CDBResult возвращается готовый массив
Но это редко гдеВ /main/classes/general/component.php в методе initComponent пока что проверяется наличие файла component.php (строка 324), таким образом просто удалить файл и получить работающий компонент не удастся.
Исправление выйдет в версии 12.0.4
Но встал вопрос дубля корзины в новом дизайне. Соответственно, весь чудо-код с резалта перетаскиваем в дубль и имеем два идентичных кода. По хорошему, это дело как раз и надо вынести в class компонента, но...
1. Как понял, на уровне шаблона класс не добавить?
2. Как вообще в моей ситуации в веянии нового быть?
1. Кастомизировать компонент корзины и перенести логику из шаблона в компонент.
2. init.php
PS из нереального будущего: отнаследовать системный компонент корзины и расширить его класс.
Так вот, введя в нее один class.php, получится мини-модуль, который будет таскаться из проекта в проект. А так как в рамках одного проекта у меня есть один компонент и куча шаблонов ИДЕАЛЬНА была бы схема класса для этой группы шаблонов.
К примеру, хитрое форматирование цены в нескольких списках (разные шаблоны). Сейчас мне придется таскать функцию форматирование между шаблонами. Класс шаблонов бы очень спас ситуацию. Пусть даже пока класс в рамках одного проекта (доступен из любых шаблонов данного компонента).
А в result_modifier пишу логику (одну на все подшаблоны). И несколько неправильно это имхо, но зато не плодятся шаблоны одинаковые (почти).
И вот ООП ну отлично бы выручил.
CBitrixComponent::includeComponentClass("demo:sqr";);
$this->arParams