-
Постов
962 -
Зарегистрирован
-
Посещение
-
Победитель дней
131
Тип контента
Форумы
Склад
Документация IPS4
Новости
Приложения
Лаборатория
Багтрекер
Разработка
Интервью
Профили
Файлы
Блоги
Календарь
Идеи
Весь контент invisionbyte
-
Если вы используете элементы контента в своем приложении, то, разумеется, вы захотите использовать контент в этих элементах в какой-то момент. Существует две возможности в зависимости от того, использует ли ваша модель определенный столбец для контента или ожидает, что первый комментарий будет действовать как контент (так, например, в приложении "Форумы"). Для поля определённого контента Для поля определённого контента просто добавьте ключ в $databaseColumnMap со значением, являющимся столбцом в базе данных, содержащей контент. Для комментариев в качестве контента Когда вы реализуете комментарии контента, первый комментарий будет автоматически рассматриваться как элемент контента. Методы, доступные для работы с контентом string content() Возвращает значение контента. string truncated( [ boolean $oneLine=FALSE ] ) Возвращает контент в формате, подходящем для использования с виджетом data-ipsTruncate. $oneLine (логический, необязательный, по умолчанию FALSE) - по умолчанию параграфы воспринимаются в разрыв строки. Если данный параметр имеет значение TRUE, параграфы заменяются пробелами вместо разрывов строк, что делает усеченный контент подходящим для однострочного отображения.
-
Расширение маршрутизации контента для Элемента Контента Многие фнукции Invision Community обрабатываются централизованно и автоматически, например, предупреждения и разрешения модератора. Для поддержки этого, вам необходимо зарегистрировать ваши типы элементов контента с помощью ядра, что с делается с помощью простого расширения Content Router (далее Маршрутизация Контента). Дополнительные сведения о расширениях смотрите в соответствующем документе. Как реализовать расширение ContentRouter Первым шагом к реализации вашего маршрутизатора контента является создание расширения ContentRouter в Центре разработчика вашего приложения. Имя класса должно иметь отношение к цели вашей модели, к примеру Темы. Откройте созданный файл и добавьте такой код (изменив значения, если это необходимо): namespace IPS\yourApp\extensions\core\ContentRouter; class _YourClass { public $classes = array( 'IPS\yourApp\YourContentItemClass' ); } Далее добавьте следующее свойство в вашу модель ноды (но не в модель элемента контента): static $modPerm = 'string'; Значение используется как ключ для хранения нод, с которыми модератор имеет разрешение работать. Это может быть что угодно. Создайте языковую строку в вашем файле lang.php с этим же ключом - это будет текстовое представление того, как называются ваши ноды (например, 'Категории'). Наконец, добавьте языковую строку в файл lang.php для каждого из действий модерации, используя этот формат: can_<action>_<title> где <title> это ключ, определяемый статическим свойством $title из вашей модели элемента контента. Действия, которые вам нужно определить, будут зависеть от того, какие функции элементов контента вы поддерживаете в своей модели, но могут включать: pin и unpin (если поддерживается закрепление). feature и unfeature (если поддерживается возможность делать контент популярным). hide, unhide и view_hidden (если поддерживается скрытие и одобрение). lock, unlock и reply_to_locked (если поддерживается закрытие). edit. move. delete. Примечание: если ваш элемент контента поддерживает комментирование, повторите этот последний шаг для действий, которые могут быть выполнены у комментариев (edit, delete, hide, unhide и view_hidden), где <title> будет ключом, определённым статическим свойством $title из вашей модели комментария контента. В качестве примера предположим, что $title нашей модели элемента контент является 'myapp_entry'. В таком случае языковые строки будут с такими ключами: 'can_edit_myapp_entry' => "Можно редактировать записи?", 'can_move_myapp_entry' => "Можно перемещать записи?", 'can_delete_myapp_entry' => "Можно удалять записи?" ...и так далее. Поведение, которое изменяется после реализации расширения ContentRouter При создании модератора администраторы смогут настраивать разрешения модератора для ваших элементов контента. При просмотре профиля пользователя, показ всего контента, размещенного этим пользователем, будет содержать и ваши элементы контента. Если вы поддерживаете скрытие элементов контента, при просмотре панели модератора будут показаны скрытые элементы контента из вашего приложения. При перестройке количества сообщений пользователя учитываются элементы вашего контента. При удалении всего контента пользователя, элементы контента вашего приложения у пользователя также будут удалены.
-
Элементы контента могут автоматически проверять, имеет ли пользователь разрешение на выполнение определенных действий путем изучения объекта ноды контейнера. Чтобы эта функциональность поддерживалась, как и следовало ожидать, ваши элементы контента должны использовать ноды контейнера. Для получения дополнительной информации обратитесь к документации по контейнерам нод и поддержке контейнеров в элементах контента. Поддержка разрешений в элементах контента Все, что вам нужно сделать для поддержки разрешений - это реализовать интерфейс разрешений в вашем классе модели элементов контента: implements \IPS\Content\Permissions Изменения в методах модели после реализации разрешений Несколько методов в вашей модели элемента контента немного меняют поведение при реализации разрешений. canView() вернёт FALSE для элемента ноды, у которого пользователь не имеет разрешения на просмотр. loadAndCheckPerms() вызовет исключение OutOfRange, если загружен объект, к которому пользователь не имеет разрешения на просмотр. Во всех местах, где функции что-то делают, будет проверено разрешение. Например, canCreate() теперь вернёт FALSE, если пользователь не имеет разрешения на создание элементов контента в указанной ноде. getItemsWithPermission() будет возвращать только элементы, к которым текущий авторизованный пользователь имеет разрешение на просмотр (или другое разрешение, указанное параметрами). Доступные дополнительные методы модели boolean can( строка $permission [, \IPS\Member $member=NULL ] ) Возвращает логическое значение, указывающее, имеет ли пользователь разрешение на выполнение указанного действия. $permission (строка, обязательный) - Ключ проверяемого разрешения. Действие должно соответствовать значению из статического свойства $permissionMap класса контейнера. $member (\IPS\Member, необязательный) - Объект пользователя, разрешения которого должны быть проверены. Вы можете передать объект \IPS\Member\Group, чтобы проверить права группы. Если значение не передано, используется текущий авторизованный пользователь. integer permId() Возвращает идентификатор индекса разрешения для этой модели элемента.
-
В большинстве случаев ваши элементы контента будут существовать внутри структуры контейнеров нод, которые их классифицируют - например, темы (элемент) в форуме (нода), или изображения (элемент) в альбоме (нода). В модели элементов контента доступно несколько методов, облегчающих работу с этими отношениями. Добавление поддержки для нод контейнеров Первый шаг, который вам нужно предпринять - добавить новое статическое свойство в вашу модель элемента контента. protected static $containerNodeClass = 'string'; Значение этого свойства должно быть именем класса модели ноды, позволяя Invision Community распознать отношения. Далее вам нужно добавить ключ контейнера в массив $databaseColumnMap в вашей модели (дополнительную информацию см. в руководстве по модели элементов контента). Значение должно быть именем столбца базы данных, содержащего ID номер контейнера. Оба примера можно наблюдать здесь: protected static $containerNodeClass = "IPS\yourapp\YourNodeClass"; public static $databaseColumnMap = array( //... Другие значения, определенные в вашей карте столбцов 'container' => 'item_parent_id' ); Дополнительные методы, доступные для моделей элементов контента После добавления поддержки контейнеров доступны два метода: boolean canMove( \IPS\Member $member=NULL ) Возвращает логическое значение, указывающее, может ли предоставленный пользователь перемещать элемент в другой контейнер. $member (\IPS\Member, optional) - Пользователь, чьи разрешения должны использоваться. По умолчанию используется авторизованный в настоящее время пользователь. void move( \IPS\Node\Model $container [, boolean $keepLink=FALSE ] ) Перемещает элемент в другой контейнер. Примечание: данный метод не проверяет разрешения; используйте canMove() в первую очередь. $container (\IPS\Node\Model, обязательный) - Объект ноды контейнера, в который будет перемещен элемент. $keepLink (boolean, необязательный, по умолчанию FALSE) - Если true, добавляется ложный элемент контента, который указывает на новое местонахождение старого элемента контента. Дополнительные методы также доступны для модели ноды контейнера, помогающие вам работать с коллекциями элементов; более подробную информацию см. в документации по модели ноды контейнера.
-
Создание формы "Добавить элемент" Вы можете создать форму, которая позволяет пользователям создавать новые элементы контента, просто вызывая следующее в методе контроллера: \IPS\Output::i()->output = \IPS\yourApp\YourModelClass::create( $node ); Вы должны передать ноду, в которой создаётся элемент контента, в виде параметра (или передать NULL, если вы создаёте элемент контента, не зависящие от нод, или если вы добавите элемент формы (например выпадающий список), из которого пользователь может выбрать сам ноду). Метод create() автоматически обработает отображение формы, создание элемента, а затем перенаправит пользователя после создания. Элементы формы получаются из метода formElements() унаследованного вашей моделью из модели элемента контента. Вы можете переопределить этот метод в своей собственной модели, добавив дополнительные поля, которые будут отображаться как в форме создания, так и в форме редактирования. Метод автоматически добавляет поля для: Заголовка элемента. Тегов (если ваша модель реализует тегирование). Поля редактора для первого комментария к вашему элементу (если комментирование поддерживается вашей моделью, и требуется первый комментарий). Если вы переопределяете метод formElements(), обязательно также вызовите родительский метод, чтобы включить эти автоматические поля. Названия для элементов форм имеют префикс в виде значения статического свойства $formLangPrefix (которое по умолчанию пустое, если не будет перезаписано). Вы можете установить это свойство, если хотите использовать собственные языковые строки для кастомизации результата вашей формы. Методы жизненного цикла Существует несколько методов жизненного цикла, которые можно переопределить для выполнения действий в определенных точках создания. boolean canCreate( \IPS\Member $member [, \IPS\Node\Model $container=NULL [, boolean $showError=FALSE ] ] ) Прежде чем отобразить форму, этот метод вызывается, чтобы определить, имеет ли пользователь разрешение на создание новых элементов. Большинство проверок разрешений обрабатываются автоматически, поэтому обычно вам не нужно переопределять этот метод, но если вам нужно выполнить дополнительные проверки, они могут быть выполнены здесь. Например, модуль личных сообщений имеет настройку, которая может ограничивать количество сообщений, отправленных за день, поэтому данный лимит проверяется в этом методе модели личных сообщений. $member (\IPS\Member, обязательный ) - пользователь, чьи разрешения проверяются. $container (\IPS\Node\Model, необязательный) - контейнер, в котором будет создан элемент, если необходимо. $showError (boolean, необязательный, по умолчанию FALSE) - по умолчанию этот метод вернёт знаение true/false. Если $showError имеет значение TRUE, вместо того, чтобы возвращать значение, этот метод будет показывать ошибку пользователю. void processBeforeCreate( массив $values ) Данный метод вызывается непосредственно перед вводом данных в базу данных, но после того, как объект был создан в памяти, и были установлены стандартные значения, такие как автор, дата и любые поля, которые могут быть установлены благодаря наличию того же ключа, как и столбец базы данных. Важно отметить, что этот метод работает только для новых элементов. $values (массив, обязательный) - Массив значений из формы. void processForm( массив $values ) Данный метод вызывается сразу же после processBeforeCreate (см. ниже). Он отличается от этого метода тем, что он также работает для редактируемых элементов. Вы должны использовать его для установки любых полей, добавленных в formElements(), которые являются более сложными, чем просто установить прямое значение (что было бы сделано автоматически). Стандартный метод устанавливает заголовок, теги (если включено - смотрите раздел Теги) и другие данные, поэтому убедитесь, что вы вызываете метод в родительском классе, чтобы не переопределить это. $values (массив, обязательный) - Массив значений из формы. void processAfterCreate( \IPS\Comment\Content $comment=NULL, массив $values ) Вызывается после того, как элемент контента был добавлен в базу данных, и была завершена вся обработка, включая создание первого комментария, если включено. $comment (\IPS\Comment\Content, required, default NULL) - Объект для первого комментария, если применимо $values (array, required) - Массив значений из формы. Увеличение количества сообщений По умолчанию, при публикации пользователем нового элемента контента, его количество сообщений увеличивается на единицу. Это может быть нежелательно в зависимости от цели вашего приложения, поэтому, определяя метод incrementPostCount на вашей модели, вы можете контролировать это поведение. boolean incrementPostCount( \IPS\Node\Model $container=NULL ) $container (\IPS\Node\Model, optional, default NULL) - Контейнер, в котором создается элемент контента, если это применимо. Возвращает true или false из этого метода, чтобы определить, следует ли увеличивать количество сообщений пользователя.
-
Расширение класса \IPS\Content\Controller приводит к унаследованию множества возможностей. Как и все типы контроллеров, ваш контроллер элемента контента находится в директории <app>/modules/<location>, например yourapp/modules/front/somemodule/somecontroller.php. Если вы еще не читали о стандартных контроллерах в Invision Community, мы рекомендуем сперва ознакомиться с основными принципами Контроллеров перед продолжением изучения данного материала. Контроллеры элементов контента - это просто более специализированная версия стандартного контроллера диспетчера, и поэтому большая часть функций остается прежней, однако становятся доступны методы, специфичные для элементов контента. Основной скелет По своей сути контроллер элемента контента прост: namespace IPS\yourapp\modules\front\yourmodule; class _yourcontroller extends \IPS\Content\Controller { } Главное, что нужно отметить, чтобы ваш контроллер расширял \IPS\Content\Controller, вместо напрямую \IPS\Dispatcher\Controller. Просто выполнив это, ваш контроллер уже имеет возможность удалять контент - если вы добавите &do=delete&id=X (где X - ID элемента) в URL-адресу элемента, в данном случае контроллер сперва автоматически проверит, имеет ли пользователь разрешение на удаление элемента (что, по умолчанию, доступно только для пользователей, являющихся модератором с разрешением на удаление любого контента). По мере прохождения других шагов этого руководства вы будете внедрять в свой контроллер другие интерфейсы, которые добавят новые функции (как автоматические, так и новые методы, которые вы можете вызвать).
-
Что такое активная запись? Invision Community широко реализует паттерн Active Record, где каждый активный объект записи представляет собой строку в вашей базе данных, и объект предоставляет методы для взаимодействия с этой строкой (включая добавление новых строк). Далее по тексту будем называть активная запись. Например, поскольку модель \IPS\Member возвращает активную запись, мы можем получать и взаимодействовать с строкой пользователем в базе данных следующим образом: $member = \IPS\Member::load(1); $member->name = "Валера"; $member->save(); Основной класс активной записи в Invision Community - \IPS\Patterns\ActiveRecord. Большинство классов моделей, с которыми вы будете работать (включая \IPS\Node\Model, \IPS\Content\Item, \IPS\Content\Comment и \IPS\Content\Review), паттерн активной записи, что означает, что все они предлагают совместимый интерфейс для работы с вашими данными. Важно, чтобы вы использовали методы, предоставленные активной записью, а не напрямую обращались к базе данных, так как при добавлении дополнительных функций к вашему элементу контента, методы будут выполнять более сложные задачи. Настройка классов ActiveRecord При написании класса, который расширяет \IPS\Patterns\ActiveRecord в цепочке наследования (даже если вы не расширяете непосредственно его), вам нужно указать некоторые свойства, которые позволяют классу находить записи в базе данных. Вот они: public static $databaseTable = 'string'; Обязательное. Задает таблицу базы данных, к которой относится данный ActiveRecord. public static $databasePrefix = 'string'; Необязательное. Указывает префикс поля, используемый этой таблицей. Например, если ваша таблица имеет поля item_id, item_name, item_description и так далее, то свойство $databasePrefix может быть установлено как item_. Это позволяет автоматически сопоставлять свойства со столбцами базы данных. public static $databaseColumnId = 'string'; Необязательное (по умолчанию: 'id'). Задает поле первичного ключа этой таблицы базы данных. Загрузка записей static \IPS\Patterns\ActiveRecord load( int $id [, string $idField=NULL [, mixed $extraWhereClause=NULL ]] ) Пример: $row = \IPS\YourClass::load(1); Этот метод извлекает строку с идентификатором 1 из базы данных и возвращает её как экземпляр активной записи вашего класса. $id (Integer; обязательный) - Идентификатор первичного ключа для загрузки. $idField (строка; необязательный) - столбец базы данных, относящийся к параметру $id (NULL будет использовать static::$databaseColumnId). $extraWhereClause (Mixed; optional) - Дополнительный оператор where (смотрите \IPS\Db::build). Выбрасывается исключение InvalidArgumentException, если $idField не существует в таблице, или исключение OutOfRangeException, если запись с данным идентификатором не найдена. Примечание. Этот метод не проверяет права пользователя на загружаемый элемент. При написании класса, который расширяет одну из моделей контента (\IPS\Node\Model, \IPS\Content\Item, \IPS\Content\Comment или \IPS\Content\Review, к примеру), вы должны вместо этого использовать loadAndCheckPerms, когда загружаете данные для фронтэнда. Этот метод с такой же конструкцией, что и методы load выше, но loadAndCheckPerms выбросит исключение OutOfRangeException, если у пользователя нет разрешения на просмотр записи. static \IPS\Patterns\ActiveRecord constructFromData( array $data [, boolean $updateMultitonStoreIfExists=TRUE] ) Пример $row = \IPS\YourClass::constructFromData( \IPS\Db::i()->select(...)->first() ); Если вы извлекли строку базы данных ручным запросом (например, чтобы получить самую последнюю запись), и вам нужно создать объект ActiveRecord из данных, этот метод позволит вам сделать это без необходимости вызова load (что вызовет другой запрос к базе данных). $data (Массив; обязательный) - Строка базы данных, вернувшаяся от \IPS\Db как массив. $updateMultitonStoreIfExists (Boolean; необязательный) - Если true, обновит текущий кэшированный объект, если он существует для данного ID. Обновление данных в ActiveRecord Вы можете получить или установить данные для записи просто установив свойства объекта, которые сопоставляются с именами столбцов базы данных. Если вы настроили свойство $databasePrefix в вашем классе, тогда вы не должны включать префикс при ссылке на свойства. Пример (если в нашей таблице базы данных содержатся столбцы с названием title и description): $item = \IPS\YourClass::load( 1 ); $item->title = "Заголовок моей статьи"; echo $item->description; Обратите внимание, что для фактического обновления базы данных метод save следует вызывать после внесения всех изменений (см. ниже). Если вашему классу необходимо выполнить обработку свойств перед их получением или установкой, вы можете определить геттеры или сеттеры для каждого свойства, добавив метод с именем get_<значение> или set_<значение>. В рамках этих методов вы можете получить доступ к необработанным значениям, используя массив $this->_data. Пример, переводящий свойство title в верхний регистр: // YourClass.php public function set_title( $title ) { $this->_data['title'] = strtoupper( $title ); } // OtherClass.php $item = \IPS\YourClass::load( 1 ); $item->title = 'my title'; echo $item->title; //--> 'MY TITLE' Сохранение и удаление записей void save() Пример: $item = \IPS\YourClass::load( 1 ); $item->title = 'New Title'; $item->save(); После изменения данных в ActiveRecord для обновления базы данных необходимо вызвать save. void delete() Пример: $item = \IPS\YourClass::load( 1 ); $item->delete(); Удаляет строку из базы данных. Клонирование записей Вы можете просто клонировать записи с помощью выражения clone. \IPS\Patterns\ActiveRecord гарантирует, что первичные ключи настраиваются по мере необходимости. Обратите внимание, что вам все равно нужно вызвать save после клонирования, чтобы создать запись в базе данных. $item = \IPS\YourClass::load( 1 ); $copy = clone $item; $copy->save(); echo $copy->id; //--> 2 Использование побитовых флагов Класс ActiveRecord реализует поразрядную функцию, позволяющую хранить несколько логических значений в одном поле, без необходимости добавлять в вашу модель новые поля (и, следовательно, столбцы базы данных). Под капотом побитовое поле хранится как целое (integer). Вы определяете свои побитовые флаги как ключи с числовым значением; это числовое значение удваивается для каждого добавляемого вами нового значения (так порядок будет таким 1, 2, 4, 8, 16, 32 и т. д.). public static $bitOptions = array( 'model_bitoptions' => array( 'model_bitoptions' => array( 'property_1' => 1, // Некоторые опции для этой модели 'property_2' => 2, // Другая опция для этой модели 'property_3' => 4 // Третья опция для модели ) ) ); В этом примере таблица базы данных нашей модели будет иметь столбец с именем model_bitoptions - и мы используем это имя в массиве $bitOptions для его идентификации. Мы сохраняем три варианта, но вы можете определить больше, следуя шаблону удвоения значения каждый раз. Хорошая практика прокомментировать каждый вариант, объясним, что делает каждый параметр. Ваша модель ActiveRecord автоматически предоставит объект \IPS\Patterns\Bitwise для этого столбца, который реализует \ArrayAccess, позволяя вам получать и устанавливать значения, поскольку это был массив: /* Получение значения */ if ( $object->model_bitoptions[‘property_1’] ) { // ... } /* Установка значения - помните, что это может быть только TRUE или FALSE! */ $object->model_bitoptions[‘property_2’] = FALSE; $object->save(); /* Получение строк базы данных */ $rowsWithPropery1AsTrue = \IPS\Db::i()->select( ‘*’, ‘table’, \IPS \Db::i()->bitwiseWhere( \IPS\YourClass::$bitOptions['model_bitoptions'], 'property_1' ));
-
Наследственная цепочка Ваша модель контента расширяет несколько классов. В свою очередь, это: \IPS\Content\Item - Предоставляет возможности Элементов Контента. Данный класс содержит весь код для различных дополнительных функций элементов контента, которые вы активируете, добавив свойства и интерфейсы в вашу модель. \IPS\Content - Предоставляет небольшое количество функций, которые являются общими для моделей Элемента Контента и моделей Комментария Контента (проясним позже) таких, как получение автора и работа с $databaseColumnMap. \IPS\Patterns\ActiveRecord - Обеспечивает функциональность загрузки элементов из базы данных, работы с их свойствами, сохранения и удаления. Дополнительную информацию об этом классе см. в документе Active Records. Основной скелет <?php namespace IPS\yourapp; class _YourClass extends \IPS\Content\Item { /** * @brief Multiton Store */ protected static $multitons; /** * @brief Default Values */ protected static $defaultValues = NULL; /** * @brief Application */ public static $application = 'yourapp'; /** * @brief Module */ public static $module = 'yourmodule'; /** * @brief Database Table */ public static $databaseTable = 'table'; /** * @brief Database Prefix */ public static $databasePrefix = 'prefix_'; /** * @brief Database Column Map */ public static $databaseColumnMap = array( 'author' => 'author' ); /** * @brief Title */ public static $title = ‘thing’; /** * Get URL * * @param string|NULL * @return \IPS\Http\Url */ public function url( $action=NULL ) { $url = \IPS\Http\Url::internal( ... ); if ( $action ) { $url = $url->setQueryString( 'do', $action ); } return $url; } } Указание свойств класса Модели Элемента Контента требуют указания нескольких статических свойств для настройки их поведения. Многие из них относятся к классу Active Records. public static $application = 'string'; Обязательное. Ключ приложения, к которому принадлежит элемент контента. public static $module = 'string'; Обязательное. Ключ модуля, к которому принадлежит элемент контента. public static $multitons = array(); public static $defaultValues = NULL; Обязательное. Наследуется от \IPS\Patterns\ActiveRecord. Эти два свойства обязательны по требованию \IPS\Patterns\ActiveRecord. Их нет необходимости переназначать; они просто должны быть определены. public static $databaseTable = 'string'; Обязательное. Наследуется от \IPS\Patterns\ActiveRecord. Имя таблицы базы данных, в которой хранятся эти элементы контента. public static $databasePrefix = 'string'; Необязательное. Наследуется от \IPS\Patterns\ActiveRecord. Указывает префикс поля, используемый этой таблицей. public static $databaseColumnMap = array(); Обязательное. Возможности, предоставленные классами выше, которые расширяет ваша модель, будут проверять этот массив, чтобы узнать, какие столбцы хранятся в вашей базе данных. Требуются следующие элементы, и во всех случаях значение с $databasePrefix опущено: author - Должно содержать имя столбца, содержащего ID пользователя, разместившего контент. title - Должно содержать имя столбца, содержащего заголовок контента. date - Должно содержать имя столбца, который содержит UNIX-время, когда был создан элемент контента. ip_address - Должно содержать имя столбца (без $databasePrefix), который содержит IP-адрес пользователя, разместившего контент. public string $title = 'string'; Ключ для языковой строки, описывающий то, чем является ваш элемент контента (Например, 'Тема', 'Файла', 'Изображение', и т.д.) Доступные методы моделей Элементов Контента В дополнение к тем методам, которые предоставляются \IPS\Patterns\ActiveRecord (которые работают точно так же, как и для нод), доступен ряд дополнительных методов. \IPS\Patterns\ActiveRecordIterator static getItemsWithPermission( ... ) Получает элементы контента, к которым у текущего пользователя есть доступ. Смотрите phpDoc в файле /system/Content/Item.php для просмотра всех поддерживаемых аргументов. \IPS\Member author() Возвращает объект \IPS\Member пользователя, разместившего элемент контента. Например: $item = YourClass::load( 1 ); $user = $item->author(); echo $user->name; boolean canView( [ \IPS\Member $member=NULL ] ) Возвращает логическое значение, указывающее, может ли предоставленный пользователь просматривать элемент контента. По умолчанию всегда будет возвращать значение TRUE, но зависит от включены ли разрешения и если включено Hiding. $member (\IPS\Member, optional) - Если предоставлено, используются разрешения текущего пользователя при выполнении проверки. По умолчанию будет использоваться текущий пользователь. boolean canEdit( [ \IPS\Member $member=NULL ] ) Возвращает логическое значение, указывающее, может ли предоставленный пользователь редактировать элемент контента. $member (\IPS\Member, optional) - Если предоставлено, используются разрешения текущего пользователя при выполнении проверки. По умолчанию будет использоваться текущий пользователь. boolean canDelete( [ \IPS\Member $member=NULL ] ) Возвращает логическое значение, указывающее, может ли предоставленный пользователь удалить элемент контента. $member (\IPS\Member, optional) - Если предоставлено, используются разрешения текущего пользователя при выполнении проверки. По умолчанию будет использоваться текущий пользователь. boolean static modPermission( string $type [, \IPS\Member $member=NULL [, \IPS\Node\Model $container=NULL ] ] ) Возвращает логическое значение, указывающее, имеет ли предоставленный пользователь разрешение выполнить действие, указанное параметром $type в указанном контейнере $container (если предоставлен). $type (string, required) Тип проверяемого разрешения. Допустимые значения: edit delete move feature (если включена такая возможность) unfeature (если включена такая возможность) pin (если включена такая возможность) unpin (если включена такая возможность) lock (если включена такая возможность) unlock (если включена такая возможность) hide (если включена такая возможность) unhide (если включена такая возможность) view_hidden (если включена такая возможность) $member (\IPS\Member, optional) Если предоставлено, используются разрешения текущего пользователя при выполнении проверки. По умолчанию будет использоваться текущий пользователь. $container (\IPS\Node\Model, optional) Если предоставлено, проверяет разрешение именно в этом контейнере ноды. void modAction( string $type [, \IPS\Member $member=NULL [, string $reason=NULL ] ] ) Выполняет указанное действие модерации. Выбрасывает исключение OutOfRangeException, если пользователь не имеет разрешения на выполнение этого действия. $type (строка, обязательно) - Тип выполняемого действия модерации. Допустимые значения можете найти в списке предыдущего метода. $member (\IPS\Member, необязательно) - Если предоставлено, используются разрешения текущего пользователя при выполнении проверки. По умолчанию будет использоваться текущий пользователь. $reason (строка, необязательно) - Используется только для действий скрыть/показать; определяет причину, по которой предпринимается действие.
-
Ниже приведен полный пример класса, использующего \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 ); } }
-
В большинстве случаев ваши Ноды будут контейнером для элементов контента - это типичная структура, используемая большинством приложений. Модели нод и модели их элементов контента предоставляют ряд методов для работы друг с другом в таких отношениях. Эта взаимосвязь состоит из двух частей: функциональности, которая становится доступной для контейнера (т.е. Ноды), и функциональности, которая становится доступной для элементов контента в этой ноде. Настройка модели ноды В вашей модели ноды вы должны указать название модели элемента контента, который вы используете. 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__* ничего не делают. Вы можете переопределить их в своем собственном классе, если вам нужно отслеживать значения.
-
Разрешения фронтэнда позволяют администраторам контролировать, какие группы пользователей могут выполнять какие-либо действия (к примеру, возможность просматривать элементы контента внутри ноды, создание новых элементов контента, комментирование элементов контента, и так далее). Ваши ноды могут иметь до 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} имеет разрешение на прочтение элементов в этой ноде"; } Этот метод в первую очередь полезен при построении запросов на основе групп, имеющих указанное разрешение.
-
В большинстве случаев, вы должны поддерживать Ограничения администратора в классах ваших моделей, поскольку 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();
-
В большинстве ситуаций ноды позволят другим нодам быть дочерними элементами, формируя отношения родитель-потомок друг с другом. Примером этого являются форумы, где форум может содержать под-форумы, которые могут содержать дополнительные подфорумы и т.д. Каждый форум является нодой, и выглядит в виде древовидной структуры с родительскими и дочерними форумами. Чтобы поддерживать отношения родитель/потомок, модель вашей ноды просто должна определять родительское свойство (смотрите ниже). Это сделает ряд унаследованных методов доступными вашему классу. Кроме того, администраторы смогут изменять порядок отображения и родителя в админцентре (это поведение может быть настроено). Настройка класса модели 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 предоставляет специальный контроллер ноды, который вы можете расширить для получения множества автоматических функций, вместо построения их самостоятельно вручную. Этот контроллер обеспечивает интерфейс для просмотра и управления нодами (добавление, редактирование, переупорядочение и т.д.). Контроллер \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'; // ... Методы и свойства вашего контроллера } Никакие другие методы не требуются в этом контроллере (хотя вы можете добавить другие обработчики запроса, если это необходимо); основная часть контроллера автоматическая.
-
Базовый класс, который будут расширять классы вашей ноды, это \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 ); }
-
Ноды (они же nodes или узлы) в Invision Community являются структурной концепцией, используемой для организации элементов контента. Они напоминают дерево с родительскими узлами, содержащими дочерние ноды, которые могут содержать другие дочерние ноды или элементы контента и т.д. В Invision Community ноды применимы в тех областях, где необходимо отношение родитель/потомок, но наиболее распространенное использование - это иерархия категорий, где ноды представляют собой категории и некие контейнеры для элементов контента. Именно в этом ключе будем упоминать ноды в данном руководстве. Вообще говоря, ноды представляют собой созданные администратором сущности. Интерфейсы для их управления существуют в админцентре. Примечание: У нод есть возможность иметь под-ноды другого класса. Поскольку это сложно и обычно не требуется для элементов контента, методы и свойства, относящиеся к под-нодам, были опущены в этой документации. Пример нод Наиболее очевидным примером структуры нод это категории, форумы и темы в приложении Форумы. В коде, категории и форумы представляют собой одно и то же - ноды, представленные моделью Форум (термин "категория" просто используется в качестве способа разъяснения функциональности). Так, родительский форум может иметь дочерние форумы, которые в свою очередь так же могут иметь дочерние форумы, или содержать в себе темы, которые являются элементами контента. Модели нод в Invision Community обрабатывают структуру форума, а модели контента обрабатывают элементы контента (модели контента обсуждаются в отдельном разделе данной документации разработчика). | Родительский форум (Модель ноды Форум) |-- Дочерний форум (Модель ноды Форум) |---- Темы (Модель элемента контента Темы) |--- Дочерний форум (Модель ноды Форум) |--- и т.д. Состав Invision Community предоставляет ряд классов, которые помогают реализовать функциональность ноды. Каждая часть будет рассмотрена более подробно в последующих разделах: Модель - \IPS\Node\Model Предоставляет данные доступа и методы манипуляции для нод путём расширения класса \IPS\Patterns\ActiveRecord. Контроллер - \IPS\Node\Controller Расширяет стандартный контроллер диспетчера для добавления автоматической поддержки интерфейсов для управления элементами нод в админцентре. Помощники (Helpers) Наиболее подходящим помощником для нод является \IPS\Helpers\Tree, который создает интерактивный интерфейс дерева (хотя этот помощник не ограничивается только работой с нодами).
-
Invision Community может периодически проверять наличие обновлений для вашего приложения, плагина или темы и показывать информирующее сообщение в админцентре, если обновление доступно. При создании приложения, плагина или темы вы можете указать URL-адрес, который Invision Community будет использовать для проверки доступности обновления. Invision Community будет периодически отправлять запрос на указанный URL-адрес с параметром "version", указывающим ID текущей версии. Например, если вы укажете URL так: https://site.ru/myapp/check.php И кто-то использует версию вашего приложения с ID "10002", тогда запрос будет отправлен на: https://site.ru/myapp/check.php?version=10002 Данный URL-адрес должен возвращать JSON-кодированный объект со следующими свойствами: version Человекопонятный номер (например "2.1.0") последней доступной версии. longversion ID номер (например "20000") последней доступной версии. released Дата релиза в формате UNIX-времени. updateurl URL-адрес, по которому администратор может загрузить обновление. Например, вы можете вернуть что-то вроде этого: { "version": "2.0.0", "longversion": 20000, "released": 1423841958, "updateurl": "https://site.ru/myapp/download" } Живой пример URL-адреса проверки последней версии Invision Community: https://remoteservices.invisionpower.com/updateCheck
-
Что делает расширение Расширение AdvertisingLocations позволяет вам определять местоположения и настройки для рекламных объявлений, чтобы вы могли вставлять рекламные объявления в определенных местах вашего приложения. Например, приложение Форумы использует это расширение для показа объявлений после первого сообщения в теме и в списке тем. Как использовать При создании нового экземпляра этого расширения приложения, вам нужно будет определить два метода (которые уже будут определены шаблонно, если вы используете Центр разработчика для создания расширения). /** * Get the locations and the additional settings * * @param array $settings Current setting values * @return array Array with two elements: 'locations' which should have keys as the location keys and values as the fields to toggle, and 'settings' which are additional fields to add to the form */ public function getSettings( $settings ) Метод getSettings принимает один параметр (массив) и должен вернуть массив с двумя элементами. Первый, с ключом 'locations', должен быть массивом с ключами, которые вы определили для расположения рекламных объявлений, и значения должны быть массивом ключей настроек для использования этих местоположений. Первый, с ключевыми «местоположениями», должен быть массивом с его ключами, которые являются определяющими вами ключами местоположения рекламы, а значениями являются массив ключей настройки для использования для местоположения. Второй элемент должен использовать ключ 'settings' и определять массив объектов помощника форм. Например: /** * Get the locations and the additional settings * * @param array $settings Current setting values * @return array Array with two elements: 'locations' which should have keys as the location keys and values as the fields to toggle, and 'settings' which are additional fields to add to the form */ public function getSettings( $settings ) { return array( 'locations' => array( 'ad_fluid_index_view' => array( 'ad_fluid_index_view_number', 'ad_fluid_index_view_repeat' ) ), 'settings' => array( new \IPS\Helpers\Form\Number( 'ad_fluid_index_view_number', ( isset( $settings['ad_fluid_index_view_number'] ) ) ? $settings['ad_fluid_index_view_number'] : 0, FALSE, array(), NULL, NULL, \IPS\Member::loggedIn()->language()->addToStack('ad_fluid_index_view_number_suffix'), 'ad_fluid_index_view_number' ), new \IPS\Helpers\Form\Number( 'ad_fluid_index_view_repeat', ( isset( $settings['ad_fluid_index_view_repeat'] ) ) ? $settings['ad_fluid_index_view_repeat'] : 0, FALSE, array( 'unlimited' => -1 ), NULL, NULL, \IPS\Member::loggedIn()->language()->addToStack('ad_fluid_index_view_repeat_suffix'), 'ad_fluid_index_view_repeat' ) ) ); } Второй метод в этом файле это parseSettings(), который является обратным вызовом, позволяющим настраивать значения параметров, которые сохраняются во время настройки администратором. Если настроек нет, этот метод должен просто вернуть пустой массив. /** * Return an array of setting values to store * * @param array $values Values from the form submission * @return array Array of setting key => value to store */ public function parseSettings( $values ) { return array( 'ad_fluid_index_view_number' => $values['ad_fluid_index_view_number'], 'ad_fluid_index_view_repeat' => $values['ad_fluid_index_view_repeat'] ); } Затем вы можете использовать рекламное объявление в отображении с использованием loadByLocation метода \IPS\core\Advertisement. Например: {{if $advertisement = \IPS\core\Advertisement::loadByLocation( 'ad_fluid_index_view' )}} {$advertisement|raw} {{endif}}
-
В приложении MVC, таком как Invision Community, задача контроллера заключается в обработке запросов от пользователей. Он, по своей сути, является посредником, запрашивая данные от модели, делая необходимую обработку и передавая их в представление для отображения (шаблоны) или вывода других данных. Как описано в документе Маршрутизация и URL-адреса, методы в контроллерах напрямую сопоставляются с URL-адресом. Когда вы посещаете URL-адрес, к примеру такой - community.ru/index.php?app=core&module=messenger&controller=messenger, то контроллер /applications/core/modules/front/messenger/messenger.php инициализируется для обработки запроса. Все контроллеры расположены в директории /modules приложения. Эта директория имеет две поддиректории. /front - для модулей, которые обрабатывают фронэнд (общедоступные) функциональные возможности. /admin - для модулей, которые обрабатывают функциональность админцентра. Админ контроллеры могут быть доступны только при авторизации пользователя в учетную запись с правами администратора. Анатомия контроллера Базовый контроллер: <?php namespace IPS\core\modules\front\example; class _example extends \IPS\Dispatcher\Controller { public function manage() { //... } public function otherMethod() { echo "Hello world"; //... } } В этом примере наш контроллер называется 'example'. В результате он сохраняется в файле с именем example.php, что позволяет Invision Community находить его. Наше пространство имён (namespace) должно быть IPS\<app>\modules\<location>\<module>, где app это ключ вашего приложения, location - либо admin, либо front, a module это название модуля, которому принадлежит этот контроллер. Как написано в документе Автозагрузка классов, имя класса контроллера должно быть строчным (совпадающее с именем файла) и с префиксом подчеркивания; это позволяет Invision Community правильно находить и загружать ваш контроллер, когда это необходимо. Как минимум, контроллеры должны расширять \IPS\Dispatcher\Controller. Существуют другие классы, которые вы можете расширить для дополнительной функциональности, о чем будет сказано ниже. Методы внутри контроллера являются обработчиками запросов и вызывается, когда параметр do в URL-адресе совпадает с названием метода. В нашем примере выше, URL-адрес community.ru/index.php?app=core&module=example&controller=example&do=otherMethod будет выведена надпись "Hello world". Специальные методы Метод execute в контроллере запускается для каждого запроса к обработчику в этом контроллере. Это означает, что это хорошее место для выполнения чего-либо, что применяется ко всем обработчикам - включение CSS или JS файлов для модуля, например. Если вы определяете метод execute() в своем контроллере, вы всегда должны вызывать родителя: public function execute () { // Ваш код... parent::execute(); } Метод manage() это обработчик по умолчанию в контроллере. Если в URL-адресе не передаётся какой-либо параметр - будет вызван метод method(). Методы без запроса Если у вашего контроллера есть методы, которые не являются обработчиками запросов (например, методы утилит), вы должны указывать префикс подчеркивание перед их названием. Эти методы недоступны по URL-адресу, как стандартные методы. protected function _someHelper () { // Метод, который наши обаработчики запроса могут вызывать } Расширенные контроллеры Хотя большинство контроллеров расширяют класс \IPS\Dispatcher\Controller, существуют другие контроллеры, которые могут быть расширены вместо этого, чтобы обеспечить дополнительную функциональность (и они, в свою очередь, сами расширяют \IPS\Dispatcher\Controller). Вот они: \IPS\Node\Controller - Управляет функциональностью для нод - древовидные структуры данных, широко используемые в Invision Community. \IPS\Content\Controller - Дополнительная функциональность для элементов контента Invision Community. \IPS\Api\Controller - Обрабатывает запросы API (этот контроллер не расширяет \IPS\Dispatcher\Controller). Эти контроллеры будут рассмотрены более подробно в следующих документах. Защита от CSRF-атак CSRF (Межсайтовая подделка запроса) - это тип веб-атаки, когда пользователь совершает действия, которые он не намеревался выполнять. Чтобы защитить от этого типа атаки, для каждого пользователя создается уникальный ключ, который должен быть включён с действиями, которые делают изменения состояния, а затем проверяется до того, как эти изменения будут сохранены. Invision Community облегчает защиту. Любой URL-адрес, который выполняет изменение состояния (например, обновляет значение в базе данных или удаляет строку в базе данных), должен выполнить проверку CSRF перед тем, как внести это изменение. Первым шагом является включение ключа CSRF пользователя в URL-адрес обработчика контроллера.При использовании класса \IPS\Http\Url для создания URL-адреса, вы можете сделать это легко, вызвав ->csrf(). Если вы создаете URL-адрес с помощью помощника шаблонов, вы можете просто передать csrf="true" в теге. Пример: $url = \IPS\Http\Url::internal( "app=application&module=foo&controller=bar" )->csrf(); {url="app=application&module=foo&controller=bar" csrf="true"} Это добавить параметр &csrfKey=(unique key) к URL-адресу, который вы можете легко проверить в своем методе контроллера следующим образом: \IPS\Session::i()->csrfCheck(); Этот метод автоматически покажет ошибку, если ключ CSRF недействителен. Это все, что вам нужно сделать! Имейте в виду, что эта проверка должна выполняться для любого изменения состояния (в любое время, когда база данных изменяется, путём перехода по URL-адресу).
-
Да, именно там.
-
Установите темы Chameleon 4.x доступной для гостей, чтобы я мог выбрать её и просмотреть на Вашем форуме.
-
Ошибки являются естественной частью любого веб-приложения, и вам нужно быть готовым показать ошибки, когда это необходимо. Invision Community имеет несколько мощных встроенных функций для обработки ошибок, с которыми вы должны ознакомиться, чтобы лучше справляться с неожиданными (или даже ожидаемыми, но недействительными) ситуациями. Invision Community выбрасывает Исключения в случае необходимости и пытается бросить наиболее подходящий класс исключения (включая кастомные классы исключений, которые расширяют стандартные классы исключений PHP). Это означает, что каждый раз, когда вы вызываете встроенные методы, вы должны обернуть эти вызовы в блоки try/catch. Например, вы создании HTTP запроса, он может завершиться с ошибкой по нескольким причинам, и это нормально - важно обернуть запрос в блок try/catch, чтобы убедиться, что любая ошибка обрабатывается корректно. Невыполнение этого требования, как правило, приводит к тому, что конечному пользователю показывается общая ошибка "Что-то пошло не так", которая является бесполезной (что пошло не так?) и часто неуместна (мы должны показывать ошибку конечному пользователю?). try { // Сделать здесь что-то throw new \UnexpectedValueException; } catch( \UnexpectedValueException $e ) { // Сделать что-нибудь другое } Важно ловить индивидуальные исключения тогда, когда это возможно и либо показывать соответствующие сообщения об ошибках, записывать информацию по мере необходимости, либо выполнять другое действие, если это возможно (в некоторых случаях исключения могут быть ожидаемыми и даже могут быть проигнорированы). Вам следует избегать ловить общий класс \Exception - лучше поймать 3 отдельных более конкретных подкласса Exception. Когда вам нужно показать ошибку конечному пользователю, в \IPS\Output есть метод error() для облегчения этой необходимости. public function error( $message, $code, $httpStatusCode=500, $adminMessage=NULL, $httpHeaders=array(), $extra=NULL, $faultyAppOrHookId=NULL ) Первым параметром должен быть строковый ключ языка сообщения об ошибке. Полное сообщение об ошибке для отображения также допустимо в случае, если сообщение поступает от стороннего приложения или вы должны заменить переменные в языковой строке. Второй параметр должен быть уникальным кодом ошибки, которую вы генерируете (использование ключа приложения в уникальном коде полезно для обеспечения его уникальности). Третий параметр - это код состояния HTTP, возвращаемый конечному пользователю. Сообщения об ошибках всегда должны иметь код состояния HTTP 4xx или 5xx, и вы всегда должны использовать наиболее подходящий код состояния. Например, если пользователь запросил неизвестную страницу, вы, скорее всего, вернете код статуса 404, в то время как запрос на страницу, к которой у пользователя нет разрешения на просмотр, скорее всего, вернет код состояния 403. Параметр $adminMessage позволяет вам показывать разное сообщения для администраторов и для обычных пользователей. Это полезно для указания администраторам причины возникшей ошибки. К примеру, если причина, по которой возникает ошибка, связана с тем, что отключена какая-либо настройка, вы можете сообщить конечному пользователю: «У вас нет прав на доступ к этой странице», но вы можете вместо этого подсказать администратору «Эта страница не может отображена потому, что параметр XYZ отключен в панели управления администратора ". Массив $httpHeaders позволяет отправлять собственные заголовки с HTTP ответом, если это необходимо. Например, если причина, по которой пользователь попал на страницу с ошибкой, является ограничение скорости, вы можете отправить заголовок Retry-After, тем самым указать пользовательскому агенту, когда он может попробовать зайти ещё раз. Параметр $extra позволяет добавлять дополнительную информацию (например обратную трассировку), которая будет показана администраторам, и $faultyAppOrHookId обычно опускается, если вы вручную вызываете метод error(). Имейте в виду, что вы должны вызывать метод error(), даже если текущий запрос является запросом AJAX. Метод автоматически обработает эту ситуацию и вернет информацию об ошибке в JSON ответе, который будет обрабатываться автоматически (в большинстве случаев, по крайней мере) с помощью основных javascript-библиотек AJAX. Когда возникает непредвиденная ошибка, вы также должны записывать некоторые дополнительные данные в системных журналах, чтобы позже диагностировать проблему. Ознакомьтесь с документацией Журналирование для получения дополнительной информации о записи данных в системных журналах.
-
Журналирование неожиданных ошибок, возникших в вашем приложении или плагине это способ #1 для определения причины возникновения ошибки. Часто, правильное журналирование может сберечь вам кучу времени, которое вы могли бы потратить на воспроизведение возникшей проблемы. Основной способ ведения журналов проблем в Invision Community это класс \IPS\Log. Основное журналирование Когда вам нужно записать непредвиденную ситуацию, вы должны использовать метод \IPS\Log::log(). Первым параметром должен быть либо экземпляр Исключения (Exception), либо строка для записи. Вторым параметром должна быть случайно выбранная "категория". try { throw new \UnexpectedValueException( 'Моё сообщение', 200 ); } catch( \Exception $e ) { \IPS\Log::log( $e, 'my_app_issue' ); \\ Вывести сообщение об ошибке } Здесь информация об исключении будет записана в категорию 'my_app_issue', которую вы можете назвать как угодно. Используя уникальные коды ошибок, вы можете более легко определить, где была зарегистрирована запись в системном журнале, когда пользователь сообщает об этой проблеме администратору. Отладочный журнал В дополнение к основному журналированию вы также можете записывать отладочные сообщения, полезные при работе для диагностики проблем в своем приложении и в первую очередь для разработки. Определение функции такое же, как метод log(), за исключением того, что вы вызываете debug(). try { throw new \UnexpectedValueException( 'Моё сообщение', 200 ); } catch( \Exception $e ) { \IPS\Log::debug( $e, 'my_app_issue' ); \\ Сообщение об ошибке } Чтобы включить запись отладочных сообщений, вам необходимо включить константу в файле constants.php. define( 'DEBUG_LOG', true ); Затем вы можете просмотреть системные журналы в админцентре, используя фразу "System logs" в живом поиске.
-
Invision Community предоставляет два разных, но связанных друг с другом способа кэширования данных: хранилище данных и кэширование уровней абстракции. Очень важно, чтобы оба типа кэширования считались изменчивыми (волатильными), и что данные могут быть восстановлены "на лету" по мере необходимости. Другими словами, использование слоя кэширования для ускорения приложения это хорошая идея в большинстве случаев, ваш код должен изящно обрабатывать ситуации, когда данные недоступны в кэше. Хранилище данных Основным методом кэширования данных в Invision Community является хранилище данных. Доступ к хранилищу данных осуществляется с помощью конструкции \IPS\Data\Store::i()->$key, где $key любой строковый ключ, который вы хотите использовать (вы должны позаботиться о предотвращении использования одинаковых ключей, выбирая достаточно уникальное имя ключа). Чтобы установить данные в хранилище данных, вам нужно всего лишь установить переменную, например: \IPS\Data\Store::i()->my_key_name = "Данные"; Это всё: данные будут сохранены в хранилище, настроенном администратором (на диске или в базе данных). Чтобы позднее получить значение, которое было установлено, вы просто вызываете хранилище данных таким образом: echo \IPS\Data\Store::i()->my_key_name; Вы также можете проверить, был ли установлен ключ, и при необходимости удалить его: if( isset( \IPS\Data\Store::i()->my_key_name ) ) { unset( \IPS\Data\Store::i()->my_key_name ); } Библиотека хранилища данных позаботится об извлечении, сохранении и удалении значений автоматически при таком их использовании. Хранилище данных может быть очищено в любое время, поэтому важно сначала проверить наличие данных, перед обращением к ним. Для примера, вместо простого вывода командой echo, вы должны сделать что-то похожее: if( !isset( \IPS\Data\Store::i()->my_key_name ) ) { \IPS\Data\Store::i()->my_key_name = 'my value'; } echo \IPS\Data\Store::i()->my_key_name; Кроме того, важно, чтобы вы знали о хранилище данных при взаимодействии с централизованным контентом, например настройками. Если вы отредактируете значение настройки вручную, обновив таблицу core_sys_conf_settings, вы должны должны удалить кэш настроек в хранилище данных, иначе ваше изменение не вступит в силу сразу же. Обратите внимание, что значения хранилища данных автоматически перестраиваются по мере необходимости, поэтому вам не нужно перестраивать значение хранилища данных (просто удалите его). \IPS\Db::i()->update( 'core_sys_conf_setting', array( 'conf_value' => 'foo' ), array( 'conf_key=?', 'bar' ) ); unset( \IPS\Data\Store::i()->settings ); Имейте в виду, что запуск инструмента поддержки, обновление и другие функции программного обеспечения полностью очистят записи хранилища данных. Слои кэширования В дополнение к функции хранилища данных, встроенной в Invision Community, возможно также кэширование на слоях кэширования. По умолчанию поддерживаются следующие уровни кэширования: Memcache Redis Wincache APC Xcache Разработчики сторонних приложений могут добавлять поддержку других слоёв кэширования, однако пользовательский код не должен знать о конкретном используемом слое кэширования. Во-первых, стоит отметить, что любые значения, хранящиеся в хранилище данных, автоматически кэшируются на сконфигурированный альтернативный слой кэширования, если он существует. Это обрабатывается автоматически, и вы все равно должны просто вызывать \IPS\Data\Store::i()->xxxxx. Если вашему приложению будет полезно хранить дополнительные данные в механизме кэширования, которые не нужно хранить в хранилище данных, вы также можете получить доступ непосредственно к слою кэширования. Например, Invision Community имеет возможность кэшировать страницы для гостей в течение указанного в настройках количества времени, и этот кэш не сохраняется в хранилище данных, а хранится на альтернативном кэширующем слое, если он установлен (в действительности это означает, что ваш сайт может обслуживать страницы для гостей с помощью Memcache или аналогичный движок, даже не требуя установления соединения с базой данных). Слой кэширования автоматически работает на специальном классе None, если не настроен ни один слой кэширования, поэтому вам не нужно беспокоиться о том, настроен слой или нет. Вы просто вызываете его так же, как и хранилище данных: if( isset( \IPS\Data\Cache::i()->my_cache_key ) ) { echo \IPS\Data\Cache::i()->my_cache_key; } else { $variable = 'some data'; \IPS\Data\Cache::i()->my_cache_key = $variable; echo $variable; } Важно помнить, что системы кэширования обычно автоматически удаляют устаревшие или наименее часто используемые данные, поэтому (например хранилище данных) все данные, хранящиеся в кэширующем слое, должны считаться изменчивыми. Другие заметки кэширования Помимо этих явных классов кэширования, которые вы можете использовать, есть несколько других замечаний относительно кэширования, которые также стоит упомянуть. Встроенное кэширование Не редко при выполнении запроса страницы один и тот же метод может вызываться несколько раз, и если этот метод выполняет ресурсоемкую работу, это может замедлить ваше приложение. Хорошая практика, если это возможно, кэшировать данные, которые были извлечены или вычислены один раз и возвращать эти же данные. В большинстве случаев это так же просто, как и следующее (предположим, что это псевдокод внутри класса): /** * @brief Свойство для временного хранения вычисленных данных */ protected $temporaryCache = NULL; /** * Этот метод что-то высчитывает трудоёмко * * @return string */ public function resourceIntensiveMethod() { if( $this->temporaryCache !== NULL ) { return $this->temporaryCache; } // Do some work $variable = '....'; $this->temporaryCache = $variable; return $this->temporaryCache; } Предпосылка этого псевдокода заключается в том, что когда вызывается наш ресурсоёмкий метод, сначала проверяем, не выполнили ли мы уже эту работу, и если да, то мы её вернем из кэша. Если нет, мы выполняем работу, которую нам нужно выполнить, но затем сохраняем результат в переменной, чтобы в следующий раз мы могли её вернуть быстрее. Значения не будут сохраняться при загрузке другого процесса или страницы, но если этот метод занял 2 секунды для выполнения и был вызван 5 раз, для загрузки страницы потребуется не менее 10 секунд. Кэшируя данные после первого вызова, мы можем снизить время загрузки страницы до 2 секунд при первом выполнении этого метода. Однако, имейте ввиду, что использовать кэширование необходимо тогда, когда это целесообразно. Например, PHP имеет memory_limit и хранение слишком большого количества данных в свойствах класса может привести к тому, что ваше приложение будет быстро заполнять лимит памяти, что приведёт к ошибке PHP. При работе над вашим приложением вам нужно будет решить, какие данные стоит кэшировать, а какие нет. Такие инструменты, как XDebug, могут помочь вам определить проблемные места в вашем коде, чтобы сосредоточиться над их корректировкой. Кэширование HTML/Ресурсов Еще один способ воспользоваться кэшированием - это дать указание браузерам кэшировать ответ, который им отправляется. Стоит упомянуть, что на кеширование на основе браузера нельзя полагаться основательно. Некоторые User agent могут игнорировать отправленные им заголовки кэширования, могут быть настроены прокси-серверы, которые могут игнорировать заголовки кэширования (или могут кэшировать ресурсы неожиданно) и т.д. Кроме того, вы вообще можете не хотеть, чтобы браузеры кэшировали наиболее динамические сгенерированные страницы, т.к. они будут различаться при каждой загрузке (при первой загрузке вы можете быть гостем, затем вы можете авторизоваться и просмотреть страницу в качестве авторизованного пользователя, к пример). Поэтому вы должны быть осторожны и не полагаться на кеширование на основе браузера. Тем не менее, если вы отправляете статический ресурс в браузер, вы можете сказать браузеру кэшировать файл, чтобы уменьшить общую нагрузку на сервер для последующих запросов. Чтобы отправить заголовки кэширования с ответом, вы должны отправить соответствующие заголовки ответов HTTP в 4 параметре, переданном в \IPS\Output::i()->sendOutput(). Метод доступен для вас, чтобы помочь установить заголовки. \IPS\Output::i()->sendOutput( "Вывод для кэша, например файл", 200, 'text/html', \IPS\Output::getCacheHeaders( time(), 360 ) ); Первый параметр getCacheHeaders() это время последнего изменения файла, второй - как долго кэшировать ответ. Это используется, например, при загрузке вложения, если пользователь попытается повторно загрузить вложение в течение короткого периода времени, его браузер может извлечь уже загруженный файл из кеша браузера, не запрашивая его снова с сервера.
-
Центр Разработчика свой для каждого приложения и плагина это инструмент, который облегчает создание и обновление приложений и плагинов для Invision Community. Большинство функций, доступных в Центре Разработчика, можно изменить в файлах на сервере, однако рекомендуется использовать для этого именно Центр Разработчика, чтобы свести к минимуму время разработки, а также вероятность ошибок в вашем коде. Поскольку потребности приложения по сравнению с плагином разные, Центр Разработчика для каждого из них отличается. Приложения Центр Разработчика для каждого приложения позволяет вам управлять несколькими аспектами приложения и облегчает создание обновлений и управление версиями. Разберём каждую вкладку в Центре Разработчика и рассмотрим что в каждой из них можно выполнять. Modules - Front Данная вкладка позволяет вам создавать новые фронт модули, которые соответствуют директориям по адресу applications/(ваше-приложение)/modules/front/. После создания фронт модуля, вы можете создать один или несколько контроллеров под ним, а также установить, какой модуль будет загружаться по умолчанию (например, если вы посетите страницу index.php?app=(ваше-приложение), какой модуль должен быть загружен), а также какой контроллер является стандартным в каждом модуле. Здесь вы также можете редактировать и удалять модули и контроллеры. Modules - Admin Как и с фронт модулями, вы также можете управлять модулями админцентра. Функционал этой вкладки очень похож с функционалом вкладки фронт модулей, но есть одна большая разница: при создании контроллеров, вы можете одновременно создать пункты меню, ограничения доступа в админцентре, а также использовать один из трёх шаблонов для контроллера (нормальный контроллер, table helper контроллер и контроллер узла (node)). Если контроллер будет контроллером узла (например страница, позволяющая управлять категориями, для которой вы хотите использовать функционал узла), вы должны использовать шаблон контроллера узла. Аналогично, если вы собираетесь выводить таблицу данных (например список пользователей или системные журналы), вы должны использовать шаблон table helper контроллера. Settings Вкладка Settings позволяет добавлять новые настройки и определять их стандартные значения. Эти настройки будут записаны в файл settings.json в директории data вашего приложения, и при установке вашего приложения администратором, эти настройки будут импортированы. Вам всё равно необходимо создать один или несколько контроллеров для отображения настроек администратору, для возможности корректировать значения в нормальном удобном виде. Tasks Вы можете использовать эту вкладку для добавления любых задач, необходимых вашему приложению. Здесь вы указываете ключ, названием которого будет назван файл, настраиваете время запуска задачи, после чего автоматически создаётся шаблонный файл в директории applications/(ваше-приложение)/tasks/. Ваши задачи также будут записаны в файл tasks.json (в директории data вашего приложения) и автоматически установлены при установке вашего приложения. Versions При создании нового приложения, в этой вкладке вы увидите две записи: install, что представляет установку вашего приложения, и working, представляющую текущую невыпущенную версию (не определяйте номер версии, пока ваше приложение не будет готово к релизу). Как правило, вам не нужно определять какие-либо изменения в базе данных на этой вкладке. При внесении изменений во вкладке Database Schema (описание ниже), SQL запросы будут автоматически использованы при формировании приложения. Однако, если вы обновляете ваше приложение с 3.x на 4.x, возможно вам понадобится определить некоторые запросы, которые будут запущены в процессе обновления, или если вы настраиваете таблицы базы данных вне вашего приложения, вам нужно будет вручную определить эти изменения здесь. При необходимости вы также можете добавлять и удалять процедуры обновления и ручные запросы для более старых версий с этой страницы. Если вы создаёте релиз обновления, который требует выполнения кода, а не простой запрос к базе данных, вы можете щелкнуть значок кода </> для версии "working", тем самым создать upgrade.php файл в директории setup/upg_working/ вашего приложения. Затем вы должны открыть этот файл и следовать инструкциям в нём, чтобы создать шаги обновления, которые выполняют дополнительные действия, чем просто выполнение запросов к базе данных. Вы можете прочитать дополнительную информацию о версиях в приложениях в статье Версии/Обновление. Widgets Если ваше приложение добавляет какие-либо виджеты в боковой блок, вы можете определить их в этой вкладке. При добавлении нового виджета, вы укажете специальный ключ, а также класс, который расширяет ваш виджет (что обеспечивает работу определённого автоматического функционала, например кэширования виджета на основе разрешений). Вы можете указать, доступен ли ваш виджет для отображения в боковом блоке и/или в приложении Страницы для использования его на страницах. Вы также можете указать, должен ли ваш виджет отображаться в вашем приложении по умолчанию "из коробки", выбрать стиль формы настройки (меню или модальное окно), и определить, можно ли использовать виджет более одного раза на одной странице. После сохранения формы, шаблонный файл будет создан в директории applications/(ваше-приложение)/widgets/, который нужно будет заполнить необходимым образом, в итоге виджет будет добавлен в директорию /data/widgets.json при окончательном создании вашего приложения. Hooks Приложения, как и плагины, могут определять хуки, которые, по своей сути, переопределяют поведение стандартного кода в Invision Community. Extensions Расширения позволяют выполнять действия в определенных точках во время обычного выполнения кода без необходимости перезагружать функцию (тот же хук). В Invision Community есть множество различных типов расширений. Для создания нового расширения в вашем приложении, разверните список доступных расширений у приложения, расширение которого хотите подключить (обычно Core и Nexus), затем нажмите на иконку (+) справа от типа расширения. Файл с шаблоном будет создан в директории extensions/(app)/(extension)/. Если вы хотите в своём приложении определить свои собственные расширения, которые смогут создавать другие приложения, в директории data/ вашего приложения вы должны создать директорию defaults/ и в ней создать директорию extensions. В этой директории вы создаёте шаблоны своих расширений с расширением .txt, вместо .php. Вы можете просмотреть примеры расширений для приложения Core в вашем Центре Разработчика. Database Schema Всякий раз, когда вам нужно добавить новые таблицы в базу данных или изменить существующие таблицы для своего приложения, вы всегда должны делать это на вкладке "Database Schema" в Центре Разработчика вашего приложения. Мало того, что ваши изменения будут записаны автоматически, они также будут автоматически выполнены в процессе установки или обновления вашего приложения. Вы можете добавлять, редактировать и удалять таблицы базы данных, столбцы, индексы и стандартные вставки для этих таблиц из этой области вашего Центра Разработчика с помощью дружелюбного GUI интерфейса. Admin CP Restrictions Эта вкладка позволяет вам определять ограничения в админцентре, которые вы можете использовать в своём коде для определения, может ли текущий администратор выполнять определённые действия в вашем приложении. Нет никаких технических требований для использования Admin CP Restrictions, однако настоятельно рекомендуется, чтобы вы это делали, когда ваше приложение предоставляет различный функционал. Например, если ваше приложение позволяет администраторам добавлять контент и просматривать отчётную статистику, вы можете захотеть позволить одним администраторам делать всё это, а другим разрешить только просмотр статистики. Вы можете легко это сделать, указав эти ограничения в Центре Разработчика, а затем использовать в своём коде для проверки наличия ограничения. Ограничения привязаны к модулю, поэтому вам сперва необходимо создать админ модуль (и вы можете автоматически создать основное ограничение во время этого процесса). Однако, если ваш модуль обрабатывает просмотр, добавление, редактирование и удаление совместно в одном модуле (в качестве примера), вы можете создать дополнительные ограничения на вкладке Admin CP Restrictions, а затем настроить свои контроллеры так, чтобы проверить соответствующие ограничения, когда администратор пытается выполнить какое-либо конкретное действие. Также обратите внимание, что вам будет необходимо создать языковые строки для каждой группы ограничений и отдельно для каждого ограничения. Если вы создали ограничение "myappview", то ключ языковой фразы будет "r__myappview" для группы и "r__myappview_manage" для самого ограничения. Admin CP Menu Вкладка Admin CP Menu позволяет вам управлять ссылками в меню админцентра и создаёт меню в файле data/acpmenu.json вашего приложения. При добавлении админ модулей вы автоматически создадите меню в админцентре (если захотите), однако вы также можете вручную отредактировать этот файл для внесения изменений в меню. Если вы захотите расположить пункт меню (или несколько пунктов) во вкладке Статистика, вы должны использовать вкладку "stats" верхнего уровня. Плагины Единственная вкладка для плагинов, которой не существует для приложений в Центре Разработчика это вкладка 'Information', которая позволяет вам заполнить информацию о плагине, автора, название, версию и т.д. Остальные вкладки полностью идентичны как для плагинов, так и для приложений.