Дополнительные поля - использование в плагинах
В новой разрабатываемой версии LiveStreet есть функционал дополнительных (пользовательских) полей. Сейчас он задействован для топиков. Суть сводится к удобной возможности добавлять в различные объекты новые поля разных типов.
Сейчас поддерживаются следующие типы полей:
Постепенно мы наращиваем функционал и количество типов.
За весь функционал по полям отвечает модуль Property. Рассмотрим пример подключения функционала дополнительных полей к плагину «Статьи» на базе ORM.
Здесь мы регистрируем новый тип «article» с объектом ORM сущности
Далее необходимо в саму сущность
Всё. Теперь к объекту статей можно смело добавлять новые поля. Добавление происходит через специальный интерфейс «Пользовательские поля» в админке.
Да, и нужно не забыть при деактивации плагина удалить за собой созданный тип:
Часто бывает необходимость при активации плагина автоматически создать нужный набор дополнительных полей (дефолтный набор). Сделать это можно в методе активации плагина вот так:
Переходим к добавлению новых элементов новых полей на форму создания объекта «Статьи».
Если интерфейс плагина находится в админке ( livestreet.ru/blog/dev_documentation/16562.html ), то подключение новых полей к форме происходит так:
В примере мы определяем параметры блока и подключаем его. Этот блок универсальный и подходит как для создания объектов (статей), так и для редактирования (в параметре target передается редактируемый объект). Если плагин не используется админку для своего интерфейса, то достаточно из параметров подключения блока удалить
После добавление этого блока у нас на форме создания статей появились новые поля для заполнения.
Теперь осталось их сохранять/обновлять при создании/редактировании статьи. Значения дополнительных полей передаются в форме в параметре property и они автоматически подхватываются из реквеста. Но можно это прописать и в явном виде (не обязательно, просто для наглядности в коде). Для этого в коде сохранения объекта (статьи), там где происходит присвоение значений перед валидацией можно вставить код:
Метод
Также есть возможность получить конкретное поле по его коду или ID:
Дополнительно можно использовать такой код для вывода всех полей:
В этом примере для показа полей будут использоваться шаблоны из property/*. У каждого типа поля может быть собственный шаблон, если его нет, то используется базовый. Также есть возможность задавать собственные шаблоны для конкретного типа таргета и типа поля. Поиск шаблона происходит по цепочке:
Такой подход позволяет, например, задать собственный шаблон для поля «Изображение» у статей.
По умолчанию данные для метода
Возможно самые любопытные уже задаются вопросом, а можно ли искать и сортировать по дополнительным полям? Можно!
Например, вот так можно искать:
Поле для поиска задается в виде
А вот так можно сортировать по дополнительному полю:
Поле для сортировки указывается как
Вот такие основные принципы работы с новым функционалом дополнительных полей. Пример их использования можно посмотреть в плагине «Article». Важно помнить, что этот функционал создан для покрытия большинства простых задач с данными, если вам необходимо сложная логика (создание, выборка и т.п.), то лучше использовать нативные поля в таблице БД.
Если у вас возникли вопросы, задавайте их в комментах.
UPDATE 18.06.2014
Функционал полей претерпел изменения по части подключения к плагинам/объектам.
Теперь не нужно в сущность добавлять метод getPropertyTargetType(), вместо этого необходимо использовать новый функционал поведений (behavior). Для этого нужно в сущности статьи и модуле статьи сделать объявление использования поведений (имя поведения строго должно быть property):
Дополнительно к этому, теперь запросы к методам вида gerProperty* необходимо делать через объект поведения, например, было
UPDATE 25.09.2014
Изменился способ подключения блока для редактирования полей, сейчас он выглядит так (в тексте статьи уже исправлено):
Изменились названия классов поведений:
ModuleProperty_BehaviorPropertyEntity -> ModuleProperty_BehaviorEntity
ModuleProperty_BehaviorPropertyModule -> ModuleProperty_BehaviorModule
Сейчас поддерживаются следующие типы полей:
- Целое число
- Дробное число
- Строка
- Текст
- Чекбокс
- Дата
- Выпадающий список
- Теги
- Ссылка на видео
- Файл
- Изображение
Постепенно мы наращиваем функционал и количество типов.
За весь функционал по полям отвечает модуль Property. Рассмотрим пример подключения функционала дополнительных полей к плагину «Статьи» на базе ORM.
Подключение
Первое, что нужно сделать, это при активации плагина зарегистрировать новый тип для дополнительных полей.public function Activate() { /** * Создаем новый тип для дополнительных полей * Третий параметр true ознает перезапись параметров, если такой тип уже есть в БД */ if (!$this->Property_CreateTargetType('article',array('entity'=>'PluginArticle_ModuleMain_EntityArticle','name'=>'Статьи'),true)) { return false; } return true; }
Здесь мы регистрируем новый тип «article» с объектом ORM сущности
PluginArticle_ModuleMain_EntityArticle
.Далее необходимо в саму сущность
PluginArticle_ModuleMain_EntityArticle
добавить новый метод getPropertyTargetType()
/** * Возвращает тип для дополнительных полей. * Необходим для интеграции с дополнительными полями. * * @return string */ public function getPropertyTargetType() { return 'article'; }
Всё. Теперь к объекту статей можно смело добавлять новые поля. Добавление происходит через специальный интерфейс «Пользовательские поля» в админке.
Да, и нужно не забыть при деактивации плагина удалить за собой созданный тип:
public function Deactivate() { $this->Property_RemoveTargetType('article',ModuleProperty::TARGET_STATE_NOT_ACTIVE); return true; }
Часто бывает необходимость при активации плагина автоматически создать нужный набор дополнительных полей (дефолтный набор). Сделать это можно в методе активации плагина вот так:
/** * Добавляем новые поля к статьям, далее пользователь может делать это через интерфейс админки */ $aProperties=array( array( 'data'=>array( 'type'=>ModuleProperty::PROPERTY_TYPE_INT, 'title'=>'Номер', 'code'=>'number', 'sort'=>100 ), 'validate_rule'=>array( 'min'=>10 ), 'params'=>array(), 'additional'=>array() ) ); if (!$this->Property_CreateDefaultTargetPropertyFromPlugin($aProperties,'article')) { return false; }
Переходим к добавлению новых элементов новых полей на форму создания объекта «Статьи».
Если интерфейс плагина находится в админке ( livestreet.ru/blog/dev_documentation/16562.html ), то подключение новых полей к форме происходит так:
{* Подключаем блок для управления дополнительными свойствами *} {insert name="block" block="propertyUpdate" params=[ 'plugin' => 'admin', 'target' => $oArticle, 'entity' => 'PluginArticle_ModuleMain_EntityArticle' ]}
В примере мы определяем параметры блока и подключаем его. Этот блок универсальный и подходит как для создания объектов (статей), так и для редактирования (в параметре target передается редактируемый объект). Если плагин не используется админку для своего интерфейса, то достаточно из параметров подключения блока удалить
plugin = 'admin'
. В параметре entity
необходимо передать класс объекта.После добавление этого блока у нас на форме создания статей появились новые поля для заполнения.
Теперь осталось их сохранять/обновлять при создании/редактировании статьи. Значения дополнительных полей передаются в форме в параметре property и они автоматически подхватываются из реквеста. Но можно это прописать и в явном виде (не обязательно, просто для наглядности в коде). Для этого в коде сохранения объекта (статьи), там где происходит присвоение значений перед валидацией можно вставить код:
$oArticle->setProperties(getRequest('property'));
Использование
Выводить данные из дополнительных полей можно как угодно. Можно получить сразу полный список текущих полей у объекта через методgetPropertyList()
:{$aProperties = $oArticle->getPropertyList()} {foreach $aProperties as $oProperty} {$oProperty->getTitle()}: {$oProperty->getValue()->getValueForDisplay()} {/foreach}
Метод
$oProperty->getValue()
возвращает объект сущности, который соответствует таблице property_value, именно в ней хранятся данные конкретных полей.Также есть возможность получить конкретное поле по его коду или ID:
{if $oProperty = $oArticle->getProperty('price')} {$oProperty->getValue()->getValueForDisplay()} {else} Значение не определено {/if}
Дополнительно можно использовать такой код для вывода всех полей:
{$aProperties = $oArticle->getPropertyList()} {include 'property/render.list.tpl' aPropertyItems=$aProperties}
В этом примере для показа полей будут использоваться шаблоны из property/*. У каждого типа поля может быть собственный шаблон, если его нет, то используется базовый. Также есть возможность задавать собственные шаблоны для конкретного типа таргета и типа поля. Поиск шаблона происходит по цепочке:
property/item.[type].[target_type].tpl -> property/item.[type].tpl -> property/item.base.tpl
Такой подход позволяет, например, задать собственный шаблон для поля «Изображение» у статей.
По умолчанию данные для метода
getPropertyList()
используют «ленивую» загрузку, т.е. запрашиваются из БД в момент вызова метода. Это хорошо, если предполагается работать только с одним объектом, но если нужно вывести дополнительные поля сразу у списка объектов (список новых статей), то возникает чрезмерная нагрузка на БД. Чтобы это избежать, по аналогии с опцией #with
в ORM, введена новая опция — '#properties'=>true
. Если ее указать, то данные по дополнительным полям будут загружены в момент выполнения основного запроса на получение списка статей. Это позволит сократить число обращений к БД до минимума.Возможно самые любопытные уже задаются вопросом, а можно ли искать и сортировать по дополнительным полям? Можно!
Например, вот так можно искать:
$aFilter=array( '#prop:price <' => 100, '#properties' => true, '#order' => array('id'=>'desc') ); $aResult=$this->PluginArticle_Main_GetArticleItemsByFilter($aFilter);
Поле для поиска задается в виде
#prop:[code]
, где [code]
это код дополнительного поля. Поиск поддерживает для простых типов (числа, строки, чекбоксы, текст).А вот так можно сортировать по дополнительному полю:
$aFilter=array( 'state' => 1, '#order' => array('prop:price'=>'asc') ); $aResult=$this->PluginArticle_Main_GetArticleItemsByFilter($aFilter);
Поле для сортировки указывается как
prop:[code]
.Вот такие основные принципы работы с новым функционалом дополнительных полей. Пример их использования можно посмотреть в плагине «Article». Важно помнить, что этот функционал создан для покрытия большинства простых задач с данными, если вам необходимо сложная логика (создание, выборка и т.п.), то лучше использовать нативные поля в таблице БД.
Если у вас возникли вопросы, задавайте их в комментах.
UPDATE 18.06.2014
Функционал полей претерпел изменения по части подключения к плагинам/объектам.
Теперь не нужно в сущность добавлять метод getPropertyTargetType(), вместо этого необходимо использовать новый функционал поведений (behavior). Для этого нужно в сущности статьи и модуле статьи сделать объявление использования поведений (имя поведения строго должно быть property):
class PluginArticle_ModuleMain_EntityArticle extends EntityORM { protected $aBehaviors=array( 'property'=>array( 'class'=>'ModuleProperty_BehaviorEntity', 'target_type'=>'article' ) ); // ...... } // и в модуле, для возможности делать фильтры/сортировку по полям при ORM запросах class PluginArticle_ModuleMain extends ModuleORM { protected $aBehaviors=array( 'property'=>'ModuleProperty_BehaviorModule' ); }
Дополнительно к этому, теперь запросы к методам вида gerProperty* необходимо делать через объект поведения, например, было
$oArticle->getPropertyList()
стало $oArticle->property->getPropertyList()
UPDATE 25.09.2014
Изменился способ подключения блока для редактирования полей, сейчас он выглядит так (в тексте статьи уже исправлено):
{insert name="block" block="propertyUpdate" params=[ 'plugin' => 'admin', 'target' => $oArticle, 'entity' => 'PluginArticle_ModuleMain_EntityArticle' ]}
Изменились названия классов поведений:
ModuleProperty_BehaviorPropertyEntity -> ModuleProperty_BehaviorEntity
ModuleProperty_BehaviorPropertyModule -> ModuleProperty_BehaviorModule
21 комментарий
Очень бы хотелось типа поля с мультиселектом, чтобы его можно было «рендерить» и как список чекбоксов и как select с мультивыбором. Достаточно часто возникает потребность в таких полях.
Планируется ли возможность ролевого доступа к полям?
Но мне очень интересен подход к архитектуре самого livestreet, как в данном случае идеи с дополнительными полями. Я сам пишу цмс, и в ней тоже реализовал примерно похожий функционал для плагинов.Только немного в другом виде.
Огромное спасибо комьюнити livestreet за интересные, свежие, и продуктивные идеи
Изменился способ подключения блока для редактирования полей, сейчас он выглядит так (в тексте статьи уже исправлено):
Изменились названия классов поведений:
ModuleProperty_BehaviorPropertyEntity -> ModuleProperty_BehaviorEntity
ModuleProperty_BehaviorPropertyModule -> ModuleProperty_BehaviorModule
ValueTypeRule.entity.class.php
После этого система будет думать, что класс ModuleProperty_EntityValueTypeRule существует и использовать его как обычно.
Список полей получить удается
А вот получить поле по его коду не удается, почему-то возвращает NULL