-
Ноды (они же nodes или узлы) в Invision Community являются структурной концепцией, используемой для организации элементов контента. Они напоминают дерево с родительскими узлами, содержащими дочерние ноды, которые могут содержать другие дочерние ноды или элементы контента и т.д.
В Invision Community ноды применимы в тех областях, где необходимо отношение родитель/потомок, но наиболее распространенное использование - это иерархия категорий, где ноды представляют собой категории и некие контейнеры для элементов контента. Именно в этом ключе будем упоминать ноды в данном руководстве. Вообще говоря, ноды представляют собой созданные администратором сущности. Интерфейсы для их управления существуют в админцентре.
Примечание: У нод есть возможность иметь под-ноды другого класса. Поскольку это сложно и обычно не требуется для элементов контента, методы и свойства, относящиеся к под-нодам, были опущены в этой документации.
Пример нод
Наиболее очевидным примером структуры нод это категории, форумы и темы в приложении Форумы. В коде, категории и форумы представляют собой одно и то же - ноды, представленные моделью Форум (термин "категория" просто используется в качестве способа разъяснения функциональности). Так, родительский форум может иметь дочерние форумы, которые в свою очередь так же могут иметь дочерние форумы, или содержать в себе темы, которые являются элементами контента. Модели нод в Invision Community обрабатывают структуру форума, а модели контента обрабатывают элементы контента (модели контента обсуждаются в отдельном разделе данной документации разработчика).
| Родительский форум (Модель ноды Форум)
|-- Дочерний форум (Модель ноды Форум)
|---- Темы (Модель элемента контента Темы)
|--- Дочерний форум (Модель ноды Форум)
|--- и т.д.
Состав
Invision Community предоставляет ряд классов, которые помогают реализовать функциональность ноды. Каждая часть будет рассмотрена более подробно в последующих разделах:
Модель - \IPS\Node\Model
Предоставляет данные доступа и методы манипуляции для нод путём расширения класса \IPS\Patterns\ActiveRecord.
Контроллер - \IPS\Node\Controller
Расширяет стандартный контроллер диспетчера для добавления автоматической поддержки интерфейсов для управления элементами нод в админцентре.
Помощники (Helpers)
Наиболее подходящим помощником для нод является \IPS\Helpers\Tree, который создает интерактивный интерфейс дерева (хотя этот помощник не ограничивается только работой с нодами).
-
Базовый класс, который будут расширять классы вашей ноды, это \IPS\Node\Model. Этот класс предоставляет широкий набор специальных методов для работы с данными вашей ноды. \IPS\Node\Model в свою очередь расширяет \IPS\Patterns\ActiveRecord, предоставляя стандартные способы выборки и взаимодействия с основными данными в вашей базе данных.
<?php
namespace IPS\yourApp;
class _ExampleModel extends \IPS\Node\Model
{
//...
}
Затем ваша модель может быть загружена в ваши контроллеры, например так:
$item = \IPS\yourApp\exampleModel::load( 1 );
Указание свойств класса
Классы нод требуют несколько статических свойств для настройки своего поведения. Многое наследуется от \IPS\Patterns\ActiveRecord.
protected static $multitons = array();
Обязательное свойство. Унаследовано от \IPS\Patterns\ActiveRecord. Просто должно быть определено подклассами \IPS\Patterns\ActiveRecord.
public static $nodeTitle = 'string';
Обязательное. Ключ языковой строки во множественном числе, определяющий сущность вашей ноды, например "Форумы" или "Категории".
public static $databaseTable = 'string';
Обязательное. Унаследовано от \IPS\Patterns\ActiveRecord. Задаёт таблицу базы данных, к которой относится паттерн ActiveRecord.
public static $databaseColumnOrder = 'string';
Обязательное. Должен быть столбец в вашей таблице базы данных (без префикса), который содержит номер позиции, в порядке которой будут выстроены ноды (центральный код будет обрабатывать настройку и использовать значение, но вам нужно создать для этого поле - столбец INT).
public static $databasePrefix = 'string';
Необязательное. Унаследовано от \IPS\Patterns\ActiveRecord. Указывает префикс поля, используемого этой таблицей.
public static $databaseColumnId = 'string';
Необязательное (по умолчанию: 'id'). Унаследовано от \IPS\Patterns\ActiveRecord. Задает поле первичного ключа для этой таблицы базы данных.
public static $nodeSortable = boolean;
Необязательное (по умолчанию: true)
Определяет, будут ли ноды сортироваться администраторами в админцентре.
public static $modalForms = boolean;
Необязательное (по умолчанию: false)
Определяет, будут ли формы редактирования/добавления нод в админцентре отображаться во всплывающем модельном окне.
Определение методов вашего класса
В дополнение к методам, унаследованным от \IPS\Patterns\ActiveRecord, класс \IPS\Node\Model также предоставляет дополнительные методы (некоторые из которых обязательны в вашем собственном классе).
public void url()
Обязательный. Должен вернуть объект \IPS\Http\Url, указывающий на местоположение во фронт-енде, где пользователи могут просматривать элементы контента в вашей ноде.
public void form( \IPS\Helpers\Form $form )
Обязательный.
Должен определять элементы формы в объекте $form, которые будут использованы для оображения формы для редактирования/добавления нод в админцентре.
public static array roots()
Возвращает массив нод. Если вы реализуете отношение с родитель-потомок, метод возвращает только те, у которых нет родителя.
public static array search( string $column, string $query, string $order=NULL, mixed $where=array() )
Возвращает массив нод, соответствующих поиску.
public array getButtons( string $url [, boolean $subnode=FALSE] )
Должен вернуть массив кнопок для отображения в дереве нод для нод в админцентре. Базовый класс определяет следующие кнопки автоматически (на основе конфигурации модели ноды):
add
edit
permissions
copy
empty
delete
Вы можете определить дополнительные кнопки. Обязательно вызовите parent::getButtons( $url ) в вашем классе для установки стандартных кнопок.
Геттеры и сеттеры
Поскольку \IPS\Node\Model расширяет \IPS\Patterns\ActiveRecord, могут быть определены геттеры и сеттеры для обработки определённых свойств нод. \IPS\Node\Model определил большинство из них, поэтому вам нужно только определить свои собственные, если хотите обрабатывать поля по-разному. Например, вы всегда определяете метод get__title(), но вам практически никогда не понадобится вручную определять метод get__id().
Свойство
Описание
Get
Set
Стандартное значение
$_id
Возвращает ID номер вашей ноды.
Значение столбца "id" в базе данных.
$_title
Возвращает заголовок вашей ноды.
Пустая строка
$_description
Возвращает описание ноды, или NULL если не применимо.
NULL
$_badge
Может использоваться для возврата бэйджа, отображаемого при просмотре нод в админцентре. Смотрите phpDocs.
NULL
$_icon
Может использоваться для возврата иконки в строке, отображаемой при просмотре нод в админцентре. Возвращает CSS класс для иконки.
NULL
$_enabled
Если реализовано, добавит бэйдж "Включено" / "Отключено", на который можно кликнуть, чтобы переключить статус. Вы должны реализовать это, если у ваших нод есть концепция включения/отключения.
NULL
$_locked
Если вы используете $_enabled, это можно использовать для указания того, что отдельная нода не может быть включена/отключена и заблокирована в текущем состоянии.
NULL
$_position
Возвращает позицию ноды.
Значение столбца в базе данных, представленное $databaseColumnOrder
$_items
Количество элементов контента в ноде
NULL
$_comments
Количество комментариев к элементам контента в ноде
NULL
$_reviews
Количество отзывов к элементам контента в ноде
NULL
Формы модели
При просмотре нод в админцентре Invision Community автоматически строит формы для их добавления/изменения. Поэтому вы должны определить метод формы в вашей модели, которые должны строить элементы форм для отображения. Например:
public function form( \IPS\Helpers\Form $form )
{
$form->add( new \IPS\Helpers\Form\Translatable( 'category_title', NULL, TRUE, array( 'app' => 'yourApp', 'key' => ( $this->id ? "yourApp_category_{$this->id}" : NULL ) ) ) );
$form->add( new \IPS\Helpers\Form\YesNo( 'category_example', $this->example ) );
}
Этот код создаёт форму с двумя элементами - Переводимое поле, позволяющее администратору установить локализованное название вашей ноды, и поле ДаНет для другого (не существующего, в данном случае) свойства.
При сохранении формы, любые поля, соответствующие столбцам в таблице базы данных, будут установлены автоматически. Однако вам может потребоваться дополнительная работа. В этом примере, поскольку заголовок является переводимым, его нельзя хранить в определенном столбце базы данных, поэтому нам нужно сохранить его в языковой системе. Это можно сделать, переопределив метод saveForm(). Например так:
public function saveForm( $values )
{
// Need to do this as if we’re creating a new node, we
// won’t have an ID yet and the language system will need one to
// store the title.
if ( !$this->id )
{
$this->save();
}
\IPS\Lang::saveCustom( 'yourApp', "yourApp_category_{$this->id}", $values['category_title'] );
parent::saveForm( $values );
}
-
При создании админ контроллеров, предназначенных для работы с определённой моделью ноды (например, страница управления форумами в приложении Форумы), Invision Community предоставляет специальный контроллер ноды, который вы можете расширить для получения множества автоматических функций, вместо построения их самостоятельно вручную. Этот контроллер обеспечивает интерфейс для просмотра и управления нодами (добавление, редактирование, переупорядочение и т.д.).
Контроллер \IPS\Node\Controller дополнительно расширяет \IPS\Dispatcher\Controller, поэтому все стандартные методы контроллера по-прежнему доступны вам.
Использование \IPS\Node\Controller
Единственное требование для использования контроллер это добавление свойства $nodeClass, ссылающегося на вашу модель, которая определена вашим классом:
namespace \IPS\yourApp\modules\front\yourModule;
class _yourController extends \IPS\Node\Controller
{
protected $nodeClass = 'IPS\yourApp\YourModelClass';
// ... Методы и свойства вашего контроллера
}
Никакие другие методы не требуются в этом контроллере (хотя вы можете добавить другие обработчики запроса, если это необходимо); основная часть контроллера автоматическая.
-
В большинстве ситуаций ноды позволят другим нодам быть дочерними элементами, формируя отношения родитель-потомок друг с другом. Примером этого являются форумы, где форум может содержать под-форумы, которые могут содержать дополнительные подфорумы и т.д. Каждый форум является нодой, и выглядит в виде древовидной структуры с родительскими и дочерними форумами.
Чтобы поддерживать отношения родитель/потомок, модель вашей ноды просто должна определять родительское свойство (смотрите ниже). Это сделает ряд унаследованных методов доступными вашему классу. Кроме того, администраторы смогут изменять порядок отображения и родителя в админцентре (это поведение может быть настроено).
Настройка класса модели
public static $databaseColumnParent = 'string';
Просто определите это свойство в своем классе для реализации отношений родитель/потомок. Значение должно быть названием колонки базы данных (без префикса), которая содержит идентификационный номер родительской ноды.
public static $nodeSortable = boolean;
Если false (по умолчанию true), то ноды не смогут быть отсортированы администратором в админцентре.
Настройка класса вашей контроллера
По умолчанию контроллеры нод не нуждаются в каких-либо свойствах или методах, добавленных для поддержки отношений родитель/потомок. Однако, есть некоторые свойства, которые вы можете определить для контроля их поведения.
protected $lockParents = boolean;
Если true, ноды не смогут быть удалены из своих родительских нод. Они смогут быть переупорядочены только в рамках их настоящего родителя.
protected $protectRoots = boolean;
Если true, корневые ноды не смогут стать дочерними, соответственно, дочерние не смогут стать корневыми нодами.
Поддерживаемые методы
После реализации отношений родитель/потомок, в вашей модели будут доступны следующие методы.
public mixed parent()
Возвращает ближайший родительский узел или NULL, если это корневой элемент без родителя.
public \SplStack parents()
Возвращает стек всех родителей (непосредственная родительская нода, родитель этой ноды и т. д. вплоть до корневой ноды).
public boolean hasChildren( [string|null $permissionCheck='view' [, \IPS\Member|null $member=NULL [, boolean $subnodes=TRUE [, mixed $where=array() ]]]] )
Возвращает true или false, указывая, имеет ли эта нода дочерние ноды.
$permissionCheck
Ключ разрешения для проверки для подсчёта количества нод (передача null не будет проверять разрешения).
$member
Пользователь, для использования в качестве контекста при проверке разрешений (передача null позволит использовать текущего авторизованного пользователя).
$subnodes
Следует ли подсчитывать только потомков. Если false, все потомки ноды будут подсчитываться независимо от глубины вложенности.
$where
Дополнительные операторы where для передачи в запрос.
public int childrenCount( [string|null $permissionCheck='view' [, \IPS\Member|null $member=NULL [, boolean $subnodes=TRUE [, mixed$where=array() ]]]] )
Возвращает число дочерних нод. Принимает те же параметры, что и hasChildren, выше.
public array children( [string|null $permissionCheck='view' [, \IPS\Member|null $member=NULL [, boolean $subnodes=TRUE [, array|null $skip=NULL [, mixed $where=array() ]]]]] )
Возвращает массив дочерних нод.
$permissionCheck
Ключ разрешения для проверки для подсчёта количества нод (передача null не будет проверять разрешения).
$member
Пользователь, для использования в качестве контекста при проверке разрешений (передача null позволит использовать текущего авторизованного пользователя).
$subnodes
Следует ли подсчитывать только потомков. Если false, все потомки ноды будут подсчитываться независимо от глубины вложенности.
$skip
Массив дочерних идентификаторов для пропуска.
$where
Дополнительные операторы where для передачи в запрос.
public boolean isChildOf( \IPS\Node\Model $node )
Возвращает true или false, указывающий, является ли этот узел дочерним (на любой глубине вложенности) предоставленного $node.
-
В большинстве случаев, вы должны поддерживать Ограничения администратора в классах ваших моделей, поскольку Invision Community существует возможность предоставления ограниченного функционала админцентра для сотрудников сайта.
Как работают Ограничения администратора
Ограничения администратора работают с помощью вызова методов вашей модели, которые представляют действия, предпринимаемые администратором. Метод, вызванный в модели, вернет логическое значение, указывающее, имеет ли администратор разрешение на выполнение этого действия. Поддерживаемые действия методов:
canAdd() (администратор может добавлять новые ноды данного типа).
canEdit() (администратор может редактировать существующие ноды).
canCopy() (администратор может копировать ноды).
canManagePermissions() (администратор может редактировать пользовательские разрешения).
canDelete() (администратор может удалять ноды).
Класс \IPS\Node\Model определяет эти методы за вас автоматически. Вы создадите ограничения администратора, которые хотите поддерживать в Центре разработчика, а затем сопоставите их с этими методами действий в вашей модели.
Настройка ограничений администратора
Первый шаг это использование Центра разработчика для создания ограничений для вашего приложения. Каждый контроллер в каждом модуле вашего приложения может иметь отдельные ограничения. Ограничения всегда отображаются как простые поля Да/Нет, поэтому формулируются в виде вопроса "Можно _____?". Например, "Можно управлять форумами" или "Можно редактировать настройки?".
Существует несколько поддерживаемых типов разрешений, которые вы можете реализовать:
access (то есть администратор может получить доступ ко всей этой ноде).
manage (то есть администратор просматривать данную ноду).
add
edit
copy
permissions
delete
Обратите внимание, что доступ и управление не имеют связанных методов действий (то есть вы не можете использовать в вашей модели методы canAccess или canManage); вместо этого Диспетчер будет автоматически проверять эти разрешения, если определено, и предотвращать доступ, если владельцем сайта не установлено разрешение Да.
Добавьте ограничением кликом кнопкой мыши по плюсу рядом с нужным контроллером. Вы увидите предложение указать ключ, по которому можно будет представлять данное ограничение в вашем коде.
Это также сформирует языковую строку для перевода описания ограничения, при этом ключ фразы будет в формате r__{key}, где {key} это тот ключ, который вы указали. Это проще всего, если вы придерживаетесь норм именования ограничений и задаете свой ключ в формате {controller} _ {permission}, где {controller} является соответствующим контроллером в вашей модели, а {permission} является одним из типов ограничения в приведенном выше списке, Например, в контроллере форумов для приложения "Форумы", мы имеем следующее:
forums_manage
forums_add
forums_edit
...и так далее.
Придерживайтесь данного формата для упрощения настройки вашей модели. Не забудьте добавить соответствующие языковые строки в языковой файл вашего приложения. Это всё, что вам нужно сделать в админцентре. Далее вы настроите свою модель.
Настройка вашей модели
Для реализации ограничений в вашей модели, вы должны добавить статическое свойство:
protected static $restrictions = array();
Вы должны добавить в этот массив два необходимых ключа:
app - ключ вашего приложения.
module - модуль, который содержит ограничения, которые вы применяете.
Вам также потребуется указать хотя бы один дополнительный ключ, в зависимости от типа поведения, которое вы хотите:
prefix - если вы назвали свои ограничения, используя описанный выше способ, вы можете здесь просто указать префикс, и модель автоматически будет использовать правильные разрешения. К примеру, если вы назвали ваши ограничения forums_add и т.д., префикс, который вы укажете для этого значения, будет forum_.
all - если вы хотите использовать одно разрешение для всех действий, просто укажите его, используя это значение.
map - если вы хотите вручную проверять какое действие должно проверять разрешение, добавьте значение с именем map. Это должен быть ассоциативный массив с указанными ниже ключами. Значение для каждого ключа должно быть ключом ограничения, который вы создали в центре разработчика, которое будет проверено для этого действия.
add
edit
copy
permissions
delete
Перезагрузка методов разрешений
Несмотря на то, что базовая модель определяет и реализует для вас методы действий, могут возникнуть ситуации, когда вам нужно перегрузить их в классе своей модели. Например, если предположить, что у нашего приложения есть параметр, который означает, что добавление новых дочерних узлов не имеет смысла, мы можем сделать:
// app/sources/ExampleModel/ExampleModel.php
function canAdd()
{
if( $this->some_setting )
{
// Нельзя добавить ноды, если включена гипотетическая настройка, поэтому возвращаем здесь FALSE
return FALSE;
}
// В других случаях не забудьте вызвать родительский метод
return parent::canAdd();
}
Использование методов разрешения
В большинстве случаев вам не нужно вручную использовать методы действий, предусмотренные для ограничений администратора. Класс \IPS\Node\Controller автоматически вызовет их при необходимости для создания интерфейса, отображая соответствующие элементы в соответствии с тем, что разрешено администратором. Однако, вы можете вызвать их, если необходимо, например так:
$item = \IPS\forums\Forum::load( 1 );
echo $item->canAdd();
-
Разрешения фронтэнда позволяют администраторам контролировать, какие группы пользователей могут выполнять какие-либо действия (к примеру, возможность просматривать элементы контента внутри ноды, создание новых элементов контента, комментирование элементов контента, и так далее). Ваши ноды могут иметь до 7 различных разрешений, настраиваемых в зависимости от потребностей вашего приложения. Реализация разрешения изменяет поведение нескольких методов ноды, и добавляет несколько новых методов на основе разрешений, которые вы можете вызвать.
Настройка вашей модели
Для того, чтобы использовать фронтэнд разрешения, ваша модель должна расширить интерфейс \IPS\Node\Permissions, например так:
class _ExampleModel extends \IPS\Node\Model implements \IPS\Node\Permissions
{
//...
}
Далее вам нужно определить три свойства для вашей модели.
public static $permType = 'string';
Уникальный (для вашего приложения) ключ, который представляет данный набор разрешений на сайте, например 'форумы' или 'категории'.
public static $permApp = 'string';
Ключ вашего приложения, позволяющий сайту корректно ассоциировать ваши разрешения с вашим приложением.
public static $permissionMap = array();
Это свойство представляет собой массив, который сопоставляет ключи разрешений, которые вы хотите определить, с индексом разрешений, который должен иметь либо значение 'view' или целое число от 2 до 7. Как отмечено выше, вы должны, по крайней мере, определить ключ со значением 'view'; вам не нужно определять все 7 разрешений, если вы не планируете их использовать. В качестве примера:
$permissionMap = array(
'view' => 'view',
'read' => 2,
'add' => 3,
'reply' => 4,
'export' => 5,
'download' => 6
);
В данном примере мы определяем обязательный ключ view, а также пять других ключей, которые будут использоваться нашим приложением. Ключи, которые вы определяете здесь, - это средства, с помощью которых вы будете проверять разрешения в других методах, а так же формируют ключи языковых строк, которые предназначены для названия ваших разрешений.
Некоторые ключи требуются, если ваши модели реализуют некоторые другие функции:
view (можно просматривать ноду) всегда необходим (определяется как значение 'view').
read (можно читать элементы контента) всегда необходим.
add (можно добавлять элементы контента) всегда необходим.
reply (можно отвечать на элементы контента) обязателен, если ваши элементы контента могут быть прокомментированы.
review (можно оставлять отзывы на элементы контента) обязателен, если ваши элементы контента поддерживают отзывы.
Интерфейс матрицы разрешений в админцентре покажет разрешения в порядке, который вы определяете здесь. Имена столбцов определяются строкой языка с ключом perm__{$key}, где $key это ключ из вышеприведённого массива, поэтому вам нужно добавить их в файл lang.php вашего приложения.
Изменённые поведения после реализации \IPS\Node\Permissions
После реализации в вашей модели, следующие три метода (по умолчанию) будут возвращать дочерние ноды, которые текущий авторизованный пользователь имеет разрешения просматривать:
hasChildren()
childrenCount()
children()
Эти методы принимают два необязательных параметра, которые позволяют вам контролировать это поведение. Подпись параметра одинакова для всех трех; В качестве примера здесь показан children().
array children( [ string $permissionCheck='view' [, \IPS\Member $member=NULL ] ] )
$permissionCheck (string, optional, default 'view')
Определяет, какое разрешение проверяется при работе с потомком; должен быть одним из ключей разрешения, которые вы определили ранее. Разрешение просмотра используется, если ни один не указан.
$member (\IPS\Member, optional)
Контролирует какие разрешения пользователя проверяются. По умолчанию, используется авторизованный в настоящее время пользователь, однако, вы можете переназначит это и указать другого пользователя.
В дополнение к вышупомянутым, метод loadAndCheckPerms() теперь будет бросать исключение OutOfRangeException, если нода загружена у авторизованного пользователя, не имеющего разрешения на просмотр..
Дополнительные методы
boolean static canOnAny( string $permission [, \IPS\Member $member ] )
Возвращает true, если пользователь имеет запрашиваемое разрешение на любой ноде, которая использует эту модель.
$permission (string, required) Тип разрешения для проверки.
$member (\IPS\Member, optional) Если предоставлено, при выполнении проверки используется разрешение данного пользователя. По умолчанию, используется авторизованный в настоящее время пользователь.
boolean can( string $permission [, \IPS\Member $member ] )
Возвращает true, если пользователь имеет запрашиваемое разрешение для объекта ноды.
$permission (string, required) Тип разрешения для проверки.
$member (\IPS\Member, optional) Если предоставлено, при выполнении проверки используется разрешение данного пользователя. По умолчанию, используется авторизованный в настоящее время пользователь.
array permissions()
Возвращает массив, представляющий строку ноды из таблицы core_permission_index, которая содержит данные о том, какие группы какие имеют разрешения. Массив содержит ключи perm_view и с perm_2 до perm_7, предоставляющие настроенные вами типы разрешений. Каждое из этих значений представляет собой список идентификаторов групп, разделенных запятыми, которые имеют это разрешение. Например:
$permissions = $myNode->permissions();
$groupsWithPermission = explode( ",", $permissions['perm_2'] ); // perm_2 может быть 'read' в нашей ноде
foreach( $groupsWithPermission as $id )
{
echo "Группа #{$id} имеет разрешение на прочтение элементов в этой ноде";
}
Этот метод в первую очередь полезен при построении запросов на основе групп, имеющих указанное разрешение.
-
В большинстве случаев ваши Ноды будут контейнером для элементов контента - это типичная структура, используемая большинством приложений. Модели нод и модели их элементов контента предоставляют ряд методов для работы друг с другом в таких отношениях. Эта взаимосвязь состоит из двух частей: функциональности, которая становится доступной для контейнера (т.е. Ноды), и функциональности, которая становится доступной для элементов контента в этой ноде.
Настройка модели ноды
В вашей модели ноды вы должны указать название модели элемента контента, который вы используете.
public static $contentItemClass = 'string';
Например, в модели ноды Форум, мы должны указать модель элемента контента следующим образом:
public static $contentItemClass = 'IPS\forums\Topic';
Настройка модели элемента контента
В модели элемента контент вы должны указать название используемой модели ноды.
public static $containerNodeClass = 'string';
Например, в модели ноды Topic, мы укажем модель ноды таким образом
public static $containerNodeClass = 'IPS\forums\Forum';
Кроме того, вам нужно добавить ключ с именем container к свойству $databaseColumnMap, значение которого должно быть именем столбца в таблице базы данных, который содержит ID ноды, которая является родительской для каждого элемента контента.
protected static $databaseColumnMap = array(
'container' => 'parent_id',
//other column maps...
);
Геттеры/Сеттеры, доступные для модели ноды
После установления двусторонней привязки эти дополнительные геттеры и сеттеры становятся доступными для класса вашей модели. Все они определены в базовом классе модели ноды, и по умолчанию все методы get__* возвращают NULL, тогда как все методы set__* ничего не делают. Вы можете переопределить их в своем собственном классе, если вам нужно отслеживать значения.
-
Ниже приведен полный пример класса, использующего \IPS\Node\Model. Это нода категории в приложении Downloads.
<?php
namespace IPS\downloads;
/**
* Category Node
*/
class _Category extends \IPS\Node\Model implements \IPS\Node\Permissions
{
/**
* @brief [ActiveRecord] Multiton Store
*/
protected static $multitons;
/**
* @brief [ActiveRecord] Default Values
*/
protected static $defaultValues = NULL;
/**
* @brief [ActiveRecord] Database Table
*/
public static $databaseTable = 'downloads_categories';
/**
* @brief [ActiveRecord] Database Prefix
*/
public static $databasePrefix = 'c';
/**
* @brief [Node] Order Database Column
*/
public static $databaseColumnOrder = 'position';
/**
* @brief [Node] Parent ID Database Column
*/
public static $databaseColumnParent = 'parent';
/**
* @brief [Node] Node Title
*/
public static $nodeTitle = 'categories';
/**
* @brief [Node] ACP Restrictions
* @code
array(
'app' => 'core', // The application key which holds the restrictrions
'module' => 'foo', // The module key which holds the restrictions
'map' => array( // [Optional] The key for each restriction - can alternatively use "prefix"
'add' => 'foo_add',
'edit' => 'foo_edit',
'permissions' => 'foo_perms',
'delete' => 'foo_delete'
),
'all' => 'foo_manage', // [Optional] The key to use for any restriction not provided in the map (only needed if not providing all 4)
'prefix' => 'foo_', // [Optional] Rather than specifying each key in the map, you can specify a prefix, and it will automatically look for restrictions with the key "[prefix]_add/edit/permissions/delete"
* @encode
*/
protected static $restrictions = array(
'app' => 'downloads',
'module' => 'downloads',
'prefix' => 'categories_'
);
/**
* @brief [Node] App for permission index
*/
public static $permApp = 'downloads';
/**
* @brief [Node] Type for permission index
*/
public static $permType = 'category';
/**
* @brief The map of permission columns
*/
public static $permissionMap = array(
'view' => 'view',
'read' => 2,
'add' => 3,
'download' => 4,
'reply' => 5,
'review' => 6
);
/**
* @brief Bitwise values for members_bitoptions field
*/
public static $bitOptions = array(
'bitoptions' => array(
'bitoptions' => array(
'moderation' => 1, // Require files to be approved?
'comment_moderation' => 2, // Require comments to be approved?
'reviews_mod' => 4, // Reviews must be approved?
)
)
);
/**
* @brief [Node] Title search prefix. If specified, searches for '_title' will be done against the language pack.
*/
public static $titleSearchPrefix = 'downloads_category_';
/**
* @brief [Node] Moderator Permission
*/
public static $modPerm = 'download_categories';
/**
* @brief Follow Area Key
*/
public static $followArea = 'category';
/**
* [Node] Get title
*
* @return string
*/
protected function get__title()
{
return \IPS\Member::loggedIn()->language()->get("downloads_category_{$this->id}");
}
/**
* [Node] Get whether or not this node is enabled
*
* @note Return value NULL indicates the node cannot be enabled/disabled
* @return bool|null
*/
protected function get__enabled()
{
return $this->open;
}
/**
* [Node] Set whether or not this node is enabled
*
* @param bool|int $enabled Whether to set it enabled or disabled
* @return void
*/
protected function set__enabled( $enabled )
{
$this->open = $enabled;
}
/**
* [Node] Add/Edit Form
*
* @param \IPS\Helpers\Form $form The form
* @return void
*/
public function form( &$form )
{
$form->add( new \IPS\Helpers\Form\Translatable( 'cname', NULL, TRUE, array( 'app' => 'downloads', 'key' => ( $this->id ? "downloads_category_{$this->id}" : NULL ) ) ) );
$form->add( new \IPS\Helpers\Form\Translatable( 'cdesc', NULL, FALSE, array( 'app' => 'downloads', 'key' => ( $this->id ? "downloads_category_{$this->id}_desc" : NULL ), 'editor' => array( 'app' => 'downloads', 'key' => 'Categories', 'autoSaveKey' => ( $this->id ? "downloads-cat-{$this->id}" : "downloads-new-cat" ), 'attachIds' => $this->id ? array( $this->id, NULL, 'description' ) : NULL, 'minimize' => 'cdesc_placeholder' ) ) ) );
$form->add( new \IPS\Helpers\Form\YesNo( 'cbitoptions_moderation', $this->bitoptions['moderation'] ) );
$form->add( new \IPS\Helpers\Form\YesNo( 'cbitoptions_comment_moderation', $this->bitoptions['comment_moderation'] ) );
$form->add( new \IPS\Helpers\Form\YesNo( 'cbitoptions_reviews_mod', $this->bitoptions['reviews_mod'] ) );
// etc...
}
/**
* [Node] Save Add/Edit Form
*
* @param array $values Values from the form
* @return void
*/
public function saveForm( $values )
{
if ( !$this->id )
{
$this->save();
}
foreach ( array( 'cname' => "downloads_category_{$this->id}", 'cdesc' => "downloads_category_{$this->id}_desc" ) as $fieldKey => $langKey )
{
\IPS\Lang::saveCustom( 'downloads', $langKey, $values[ $fieldKey ] );
unset( $values[ $fieldKey ] );
}
foreach ( array( 'moderation', 'comment_moderation', 'reviews_mod' ) as $k )
{
$this->bitoptions[ $k ] = $values["cbitoptions_{$k}"];
unset( $values["cbitoptions_{$k}"] );
}
parent::saveForm( $values );
}
/**
* Get URL
*
* @return \IPS\Http\Url
*/
public function url()
{
return \IPS\Http\Url::internal( "app=downloads&module=downloads&controller=browse&id={$this->_id}", 'front', 'downloads_cat', $this->name_furl );
}
}