-
Перед тем, как приступить к разработке плагинов или приложений для Invision Community, Вам необходимо включить Режим Разработчика. Активация данного режима приводит к тому, что программное обеспечение будет загружать необходимые файлы непосредственно из файловой системы, а не из кэшированных версий или базы данных.
В Режиме Разработчика программное обеспечение работает намного медленнее и может привести к уязвимостям в системе безопасности. Включайте режим разработчика только, если вы PHP разработчик и намерены разрабатывать приложения и плагины. Активировать Режим Разработчика следует только на локальном сервере, который не доступен через интернет.
Включение Режима Разработчика
Чтобы включить Режим Разработчика на вашем форуме, нужно выполнить следующие действия:
Загрузить инструменты разработчика, убедившись, что вы выбрали версию, подходящую для вашего Invision Community. Инструменты разработчика для более новых версий так же будут доступны, поэтому вам может понадобиться, загрузить более раннюю версию из раздела «Предыдущие версии».
Извлечь инструменты разработчики и переместить их в папку, где установлен ваш Invision Community, объединяя с существующими файлами. Существует папка "Dev" в инструментах разработчика, и "Dev" папка для каждого приложения. Если у вас не установлены все приложения Invision Community, вы должны удалить папки, которые вам не нужны из папки Tools Developer перед копированием. Наличие средств разработчика для неустановленных приложений может привести к ошибкам.
Если у вас нет файла constants.php в корневой папке Invision Community, то создайте его.
Добавьте следующие строки в файл constants.php:
<?
define( 'IN_DEV', TRUE );
Важные замечания
Инструменты разработки включают в себя файлы, необходимые для всех приложений IPS. Если вы включаете режим разработчика на IPS на котором установлены сторонние приложения и плагины, вам также необходимо получить и применить инструменты разработчика (т.е. положить папку "Dev") для них. Получить их вы можете у автора приложения.
Обратите внимание, что при обновлении версии Invision Community, вам необходимо будет загрузить новые инструменты разработчика.
-
Классы в Invision Community 4 являются "автоматически подгружаемыми". Это означает, что вам не нужно подключать исходный файл IPS4.
Для справки, метод автоподгрузки \IPS\IPS::autoloader() находится в файле init.php корневого каталога.
Местонахождение классов
Классы должны быть расположены в правильной дериктории и быть корректно названы, чтобы загрузчик мог найти их.
Существует всего три дериктории:
Классы фреймворка
Структура имени класса: \IPS\Namespace\Class.
Расположение на диске: system/Namespace/Class.php.
Классы приложений
Структура имени класса: \IPS\app\Namespace\Class (обратите внимание, что ключ приложения в нижнем регистре, но части после используют PascalCase).
Расположение на диске: applications/app/sources/Namespace/Class.php
Расширения приложений и модули
Структура имени класса : \IPS\app\modules\front\module\controller (обратите внимание, все части в нижнем регистре)
Расположение на диске: applications/app/modules/front/module/controller.php
Для классов фреймворка и классов приложений, конечный файл всегда должен находиться в пределах папки (не беспорядочно в системном каталоге). Если он будет находится хотя бы на один уровень глубже, система будет искать файл в каталоге с тем же именем. Например \IPS\Member находится в директории system/Member/Member.php в то время как \IPS\Member\Group находится в system/Member/Group.php
Подмена кода (Monkey Patching)
При обьявлении, классы всегда начинаются с подчеркивания. Например, в Invision Community вы вызываете так: \IPS\Member, однако, если посмотреть в исходном файле вы увидите, что он объявлен следующим образом:
namespace IPS;
class _Member { ...
Этот прием называется “Обезьяним патчем” (Monkey Patching), который позволяет сторонним разработчикам перегрузить любой класс без какого-либо пересмотра кода и не конфликтовать хукам друг с другом.
В этом примере система, сразу после автозагрузки файла Member.php, выполнит такой код:
namespace IPS;
class Member extends \IPS\_Member { }
Если сторонний разработчик хочет перегрузить \IPS\Member, система вставит это внутрь, так что в итоге получится примерно так:
\IPS\Member extends hook1
hook1 extends \IPS\_Member
Или, если два хука хотят перегрузить \IPS\Member:
\IPS\Member extends hook1
hook1 extends hook2
hook2 extends \IPS\_Member
Это означает, что фреймворк, или любой сторонний код должен только вызвать \IPS\Member, и система не только автоматически подгрузит источник, но и создаст цепочку любых хуков, которые хотят перегрузить класс.
Если эта технология выглядит пугающе (это не обычная практика) - вы не обязаны это понимать. Вам нужно только знать, что классы должны начинаться с подчеркивания при объявлении, но это подчеркивание обычно никогда не используется.
Это также означает, что вместо того, чтобы вызвать "self::" внутри класса, вы должны вызвать "static::", так что вы обращаетесь к перегруженному классу, а не к оригинальному.
Сторонние библиотеки
Если вы хотите использовать сторонние PHP библиотеки, они, конечно, должны быть включены вручную и не могут использовать замену кода (Monkey patching).
Если библиотека соответствует стандарту нэйминга PSR-0, вы можете добавить её в \IPS\IPS::$PSR0Namespaces таким образом, и автозагрузчик затем подгрузит ее:
\IPS\IPS::$PSR0Namespaces['Libary'] = \IPS\ROOT_PATH . '/applications/app/system/3rd_party/Library';
В противном случае, вам нужно будет включать исходники вручную.
-
Большинство URL-адресов в Invision Community являются "дружественными", также известные как FURLs (ЧПУ – человекопонятные ссылки) - то есть, они на простом английском и легко читаются пользователями и поисковыми системами. FURL (ЧПУ) отображаются с помощью Invision Community в виде традиционных URL с параметрами, на основе преобразования, предоставляемого приложением.
Например, FURL site.ru/messenger/compose может быть отображен как site.ru/index.php?app=core&module=messaging&controller=messenger&do=compose.
Как загружаются контроллеры
Контроллеры автоматически запускаются, когда совпадает URL. Параметры URL используются Invision Community, чтобы найти нужный контроллер:
app=core
Указывает, что контроллер находится в приложении “core”
module=messaging
Указывает, что контроллер находится в модуле обмена сообщениями “messaging”, в базовом приложении “core”
controller=messenger
Указывает, что мы загружаем контроллер “messenger”, в модуле обмена сообщениями “messaging”, в базовом приложении “core”
do=сompose
Параметр do не является обязательным, и позволяет вызывать конкретный метод в контроллере, чтобы обработать запрос. Если этот параметр опущен, то по умолчанию будет вызываться метод manage.
Так, для URL site.ru/index.php?app=core&module=messaging&controller=messenger&do=compose, загружаемый контроллер будет находиться в /applications/core/modules/front/messaging/messenger.php, и будет вызываться метод compose внутри контроллера, чтобы обработать запрос.
По этой структуре очень легко определить, какой именно способ, в каком контроллере обрабатывает запрос для любого заданного URL.
Определение дружественных URL-адресов
При разработке приложения, ваша FURL конфигурация создается в файле furl.json в каталоге /data вашего приложения. JSON структура определяет дружественный URL, реальный URL, который ему соответствует, и некоторые другие данные которые могут быть использованы.
Простой пример FURL
...
"messenger_compose": {
"friendly": "messenger/compose",
"real": "app=core&module=messaging&controller=messenger&do=compose"
},
...
Ключ (в данном случае messenger_compose) это то, что идентифицирует этот FURL в IPS4. При создании ссылок в шаблонах или контроллерах, вы будете использовать этот ключ, чтобы указать, какой FURL будет использоваться для генерации и парсинга URL-адреса.
Значение friendly это ЧПУ, который будут видеть пользователи. Значение real является фактическим URL, который будет использовать Invision Community, чтобы найти правильное app/module/controller для обработки запроса.
FURLs с использованием параметров
Хотя многие FURL статичные и простые, как в вышеуказанном примере, некоторые будут динамическими и будут включать в себя параметры, идентифицирующие конкретную запись, которая должна отображаться - например, просмотр темы на форуме. Для облегчения этой задачи, FURL определения поддерживают параметры.
...
"profile": {
"friendly": "profile/{#id}-{?}",
"real": "app=core&module=members&controller=profile"
},
...
Параметры, находящиеся внутри FURL заключены в фигурные скобки {}. Первый символ может быть либо #, чтобы соответствовать номеру, или @, чтобы соответствовать строкам. За этим следует имя параметра, и оно должно совпадать с именем параметра, который будет подставлен в реальном URL. Например, здесь мы используем {#id}, который совпадает с номером и приведет к &id=123 и передается в наш реальный URL.
Тег {?} может быть использован для SEO заголовков; то есть дружественный текст, который идентифицирует отдельные записи, но который не является частью реального URL. Примером этого было бы название темы - оно включено в URL, чтобы помочь пользователям и поисковым системам, но только id темы используется для её поиска в реальном URL-адресе.
Вы можете использовать несколько SEO заголовков в пределах URL, используя нулевой индексированный номер в теге, например {?0}, {?1} и {?2}.
Вам не следует указывать FURL параметры, которые вы собираете в реальном URL; они автоматически добавляются к реальному URL-адресу диспетчером. В приведенном выше примере URL пользователь будет видеть что-то вроде site.ru/profile/123-имя-пользователя.
Специфика FURL
Порядок, в котором вы указываете ваши FURL значения имеет большое значение. Когда диспетчер пытается соотнести URL, он проходит последовательно через значения FURL, и останавливается на первом значении, которое подходит. Отсюда следует, что ваши более специфичные значения должны идти перед менее специфичными в furl.json.
Например, предположим, у нас есть два значения, относящиеся к профилю пользователя. Одним из них является домашняя страница профиля, другой – страница редактирования профиля. Если мы указали значения таким образом:
"profile": {
"friendly": "profile/{#id}-{?}",
"real": "app=core&module=members&controller=profile"
},
"edit_profile": {
"friendly": "profile/{#id}-{?}/edit",
"real": "app=core&module=members&controller=profile&do=edit"
},
…Тогда edit_profile не будет использоваться. profile/1-имя-пользователя URL будет найден первым и вызван диспетчером.
Вместо этого следует сделать так, указав значения следующим образом:
"edit_profile": {
"friendly": "profile/{#id}-{?}/edit",
"real": "app=core&module=members&controller=profile&do=edit"
},
"profile": {
"friendly": "profile/{#id}-{?}",
"real": "app=core&module=members&controller=profile"
},
... это означает что edit_profile будет пропущен, пока не будет определено более частное значение, что позволяет более точно определить все запросы для обработки.
-
Центр Разработчика свой для каждого приложения и плагина это инструмент, который облегчает создание и обновление приложений и плагинов для 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', которая позволяет вам заполнить информацию о плагине, автора, название, версию и т.д. Остальные вкладки полностью идентичны как для плагинов, так и для приложений.
-
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() это время последнего изменения файла, второй - как долго кэшировать ответ. Это используется, например, при загрузке вложения, если пользователь попытается повторно загрузить вложение в течение короткого периода времени, его браузер может извлечь уже загруженный файл из кеша браузера, не запрашивая его снова с сервера.
-
Журналирование неожиданных ошибок, возникших в вашем приложении или плагине это способ #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 выбрасывает Исключения в случае необходимости и пытается бросить наиболее подходящий класс исключения (включая кастомные классы исключений, которые расширяют стандартные классы исключений 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.
Когда возникает непредвиденная ошибка, вы также должны записывать некоторые дополнительные данные в системных журналах, чтобы позже диагностировать проблему. Ознакомьтесь с документацией Журналирование для получения дополнительной информации о записи данных в системных журналах.