Создание уведомлений в расширениях

Обсуждение новой системы расширения функциональности phpBB 4.0-dev, разработки новых расширений.
Аватара пользователя
rxu
Сообщения: 1125
Зарегистрирован: 21 янв 2014, 21:20
Откуда: Krasnoyarsk
Github repo: https://github.com/rxu
Контактная информация:

Создание уведомлений в расширениях

Сообщение rxu »

  • Внести изменения в services.yml, добавив сервис нового типа уведомления. Наименование сервиса должно иметь формат (начиная с phpBB 3.1.0-RC4, в более ранних версиях часть <vendor>.<extension>. не разрешалась)

    Код: Выделить всё

    <vendor>.<extension>.notification.type.something
    а его определение должно включать в себя обязательный тег

    Код: Выделить всё

            tags:
                - { name: notification.type }
    
    Например:

    Код: Выделить всё

        gfksx.ThanksForPosts.notification.type.thanks:
            class: gfksx\ThanksForPosts\notification\thanks
            scope: prototype # scope MUST be prototype for this to work!
            arguments:
                - @user_loader
                - @dbal.conn
                - @cache.driver
                - @user
                - @auth
                - @config
                - %core.root_path%
                - %core.php_ext%
                - %tables.notification_types%
                - %tables.notifications%
                - %tables.user_notifications%
            tags:
                - { name: notification.type }
    
  • Создать файл нового типа уведомления. Файлы должны располагаться в папке ext/<vendor>/<ext_name>/notification.
    В данном случае, файл называется thanks.php. Объявленный в файле уведомления класс расширяет базовый класс уведомлений \phpbb\notification\type\base. Пример:

    Код: Выделить всё

    /**
    * Thanks for posts notifications class
    * This class handles notifying users when they have been thanked for a post
    */
    
    class thanks extends \phpbb\notification\type\base
    {
    
    Файл содержит ряд свойств и функций, необходимых для создания уведомления:
    1. Функция, возвращающая тип уведомления, в данном случае это 'thanks' - по имени файла и класса уведомления.

      Код: Выделить всё

      	public function get_type()
      	{
      		return 'thanks';
      	}
      
      
    2. Свойство, определяющее языковую переменную для создания уведомления - protected $language_key.

      Код: Выделить всё

      protected $language_key = 'NOTIFICATION_THANKS';
      и сама переменная

      Код: Выделить всё

      'NOTIFICATION_THANKS'		=> '<strong>Благодарность</strong> от пользователя %1$s за сообщение:',
    3. Свойство, определяющее место настройки нового уведомления на странице настроек уведомлений в личном разделе - public static $notification_option. Используются ключи 'id', 'lang', и 'group'.
      Удобство представляет использование двух последних ключей, которые имеют следующий смысл:
      'group' - группа настроек, в которой будет расположена настройка нового расширения, представляет из себя ключ соответствующей имени этой группы языковой переменной. Например:

      Код: Выделить всё

      'group'	=> 'NOTIFICATION_GROUP_MISCELLANEOUS',
      значение которой

      Код: Выделить всё

      'NOTIFICATION_GROUP_MISCELLANEOUS'					=> 'Прочие уведомления',
      'lang' - непосредственно заголовок (имя) новой настройки. Например:

      Код: Выделить всё

      'lang'	=> 'NOTIFICATION_TYPE_THANKS',
      значение которой будет

      Код: Выделить всё

      'NOTIFICATION_TYPE_THANKS'	=> 'Вас поблагодарили за сообщение',
      Конечный результат:

      Код: Выделить всё

      	public static $notification_option = array(
      		'lang'	=> 'NOTIFICATION_TYPE_THANKS',
      		'group'	=> 'NOTIFICATION_GROUP_MISCELLANEOUS',
      	);
      
    4. Функция, определяющая условия, при которых данное уведомление доступно. В случае, если оно доступно всегда:

      Код: Выделить всё

      	public function is_available()
      	{
      		return true;
      	}
      
    5. Функция, возвращающая идентификатор основного элемента item_id. Оно будет записано в поле item_id таблицы уведомлений в БД. Обратите внимание, что если уведомление с данным item_id уже имеется, другие уведомления с тем же Item_id добавлены не будут. Пример:

      Код: Выделить всё

      	/**
      	* Get the id of the item
      	*
      	* @param array $thanks_data The data from the thank
      	*/
      	public static function get_item_id($thanks_data)
      	{
      		return (int) $thanks_data['post_id'];
      	}
      
      
      В данном случае, за основной идентификатор выбран id сообщения, за которое выдана благодарность. В общем случае, может быть выбрано любое целое значение (идентификатор любого имеющего для контекста смысл элемента, задействованного в коде, где будет обрабатываться создание уведомления).
    6. Функция, возвращающая идентификатор родительского элемента, по отношению к item_id - item_parent_id. Например, идентификатор темы по отношению к идентификатору сообщения в данной теме, и т.п. Пример:

      Код: Выделить всё

      	/**
      	* Get the id of the parent
      	*
      	* @param array $thanks_data The data from the thank
      	*/
      	public static function get_item_parent_id($thanks_data)
      	{
      		return (int) $thanks_data['topic_id'];
      	}
      
      
    7. Функция, отбирающая массив с идентификаторами пользователей, которым должно поступить уведомление. Массив должен быть передан функции check_user_notification_options() для формирования данных о видах уведомлений, которые должны быть направлены пользователям из данного списка. Пример:

      Код: Выделить всё

      	/**
      	* Find the users who want to receive notifications
      	*
      	* @param array $thanks_data The data from the thank
      	* @param array $options Options for finding users for notification
      	*
      	* @return array
      	*/
      	public function find_users_for_notification($thanks_data, $options = array())
      	{
      		$options = array_merge(array(
      			'ignore_users'		=> array(),
      		), $options);
      
      		$users = array((int) $thanks_data['poster_id']);
      
      		return $this->check_user_notification_options($users, $options);
      	}
      
      В общем случае, не имеет значение, каким образом получен массив идентификаторов пользователей - всё зависит от конкретных обстоятельств, учитываемых в работе расширения. Например, идентификаторы могут быть отобраны по определенным условиям из базы данных.
    8. Функция, возвращающая аватар пользователя. Пример:

      Код: Выделить всё

      	/**
      	* Get the user's avatar
      	*/
      	public function get_avatar()
      	{
      		return $this->user_loader->get_avatar($this->get_data('user_id'));
      	}
      
      В данном случае для получения идентификатора пользователя использован метод get_data(). Обратите внимание, что данный метод предназначен для получения данных, предварительно записанных в БД через метод create_insert_array() (см. ниже). Т.е. определенный необходимый для уведомления набор данных должен быть сохранен в БД (в сериализованном виде).
    9. Функция, создающая заголовок уведомления - например, "Получена благодарность от пользователя rxu за сообщение:", после которого может следовать заголовок сообщения, за которое получена благодарность (создание последнего будет пояснено ниже). Пример:

      Код: Выделить всё

      	/**
      	* Get the HTML formatted title of this notification
      	*
      	* @return string
      	*/
      	public function get_title()
      	{
      		$username = $this->user_loader->get_username($this->get_data('user_id'), 'no_profile');
      
      		return $this->user->lang($this->language_key . '_' . $this->get_data('lang_act'), $username);
      	}
      
      Обратите внимание, что здесь использовано описанное выше свойство $language_key - языковая переменная класса.
    10. Функция, возвращающая список идентификаторов пользователей (user_id) для последующей загрузки в класс данных указанных пользователей, необходимых для работы уведомления. Загрузка происходит при помощи класса user_loader(). Пример:

      Код: Выделить всё

      	/**
      	* Users needed to query before this notification can be displayed
      	*
      	* @return array Array of user_ids
      	*/
      	public function users_to_query()
      	{
      		$thankers = $this->get_data('thankers');
      		$users = array(
      			$this->get_data('user_id'),
      		);
      
      		if (is_array($thankers))
      		{
      			foreach ($thankers as $thanker)
      			{
      				$users[] = $thanker['user_id'];
      			}
      		}
      
      		return $users;
      	}
    11. Функция, формирующая ссылку для перехода при клике на уведомлении. Пример:

      Код: Выделить всё

      	/**
      	* Get the url to this item
      	*
      	* @return string URL
      	*/
      	public function get_url()
      	{
      		return append_sid($this->phpbb_root_path . 'viewtopic.' . $this->php_ext, "p={$this->item_id}#p{$this->item_id}");
      	}
      
    12. Функция, возвращающая ссылку для использования при клике на уведомление. Использует выше описанный метод get_url(). Пример:

      Код: Выделить всё

      	public function get_redirect_url()
      	{
      		return $this->get_url();
      	}
      
    13. Функция, определяющая шаблон email для отправки уведомления. Пример:

      Код: Выделить всё

      	/**
      	* Get email template
      	*
      	* @return string|bool
      	*/
      	public function get_email_template()
      	{
      		return '@gfksx_ThanksForPosts/user_thanks';
      	}
      
    14. Функция, возвращающая строку, расположенную под заголовком уведомления (например, после "Получена благодарность от пользователя rxu за сообщение:"), например, заголовок темы или сообщения. В результате получается конструкция вида Получена благодарность от пользователя rxu за сообщение: "Re: Test TFP notifications".
      В данном случае "Re: Test TFP notifications" - результат работы этой функции. Пример:

      Код: Выделить всё

      	/**
      	* Get the HTML formatted reference of the notification
      	*
      	* @return string
      	*/
      	public function get_reference()
      	{
      		return $this->user->lang(
      			'NOTIFICATION_REFERENCE',
      			censor_text($this->get_data('post_subject'))
      		);
      	}
      
    15. Функция, возвращающая массив для присвоения значений переменным шаблона email. Пример:

      Код: Выделить всё

      	/**
      	* Get email template variables
      	*
      	* @return array
      	*/
      	public function get_email_template_variables()
      	{
      		$user_data = $this->user_loader->get_user($this->get_data('poster_id'));
      
      		return array(
      				'THANKS_SUBG'	=> htmlspecialchars_decode($this->user->lang['GRATITUDES']),
      				'USERNAME'		=> htmlspecialchars_decode($this->user->data['username']),
      				'POST_THANKS'	=> htmlspecialchars_decode($this->user->lang['THANKS_PM_MES_'. $this->get_data('lang_act')]),
      				'U_POST_THANKS'	=> generate_board_url() . '/viewtopic.' . $this->php_ext . "?p={$this->item_id}#p{$this->item_id}",
      		);
      	}
      
      Об использовании шаблонов email в расширениях см. тему viewtopic.php?f=5&t=73
    16. Функция, предназначенная для записи в БД в (в сериализованном виде) регулярно необходимых для вывода уведомления данных. перечень таких данных определяется исходя из конкретных обстоятельств, но обязательно должны записываться значения, получаемые методом get_data()/ Пример:

      Код: Выделить всё

      	/**
      	* Function for preparing the data for insertion in an SQL query
      	* (The service handles insertion)
      	*
      	* @param array $thanks_data Data from insert_thanks
      	* @param array $pre_create_data Data from pre_create_insert_array()
      	*
      	* @return array Array of data ready to be inserted into the database
      	*/
      	public function create_insert_array($thanks_data, $pre_create_data = array())
      	{
      		$this->set_data('user_id', $thanks_data['user_id']);
      		$this->set_data('post_id', $thanks_data['post_id']);
      		$this->set_data('lang_act', $thanks_data['lang_act']);
      		$this->set_data('post_subject', $thanks_data['post_subject']);
      
      		return parent::create_insert_array($thanks_data, $pre_create_data);
      	}
      
    17. Свойство в виде массива, содержащее необходимые данные для создания уведомления, в т.ч. и те, которые должны быть записаны в БД, передается во внешнем скрипте как параметр функции add_notifications(). В ланном конкретном примере - это массив $thanks_data. Пример:

      Код: Выделить всё

      					$thanks_data = array(
      						'user_id'	=> (int) $this->user->data['user_id'],
      						'post_id'	=> $post_id,
      						'poster_id'	=> $to_id,
      						'topic_id'	=> (int) $row['topic_id'],
      						'forum_id'	=> (int) $row['forum_id'],
      						'thanks_time'	=> time(),
      						'username'	=> $this->user->data['username'],
      						'lang_act'	=> $lang_act,
      						'post_subject'	=> $row['post_subject'],
      					);
      
  • Обработать создание уведомления во внешнем скрипте. Пример:

    Код: Выделить всё

    					$thanks_data = array(
    						'user_id'	=> (int) $this->user->data['user_id'],
    						'post_id'	=> $post_id,
    						'poster_id'	=> $to_id,
    						'topic_id'	=> (int) $row['topic_id'],
    						'forum_id'	=> (int) $row['forum_id'],
    						'thanks_time'	=> time(),
    						'username'	=> $this->user->data['username'],
    						'lang_act'	=> $lang_act,
    						'post_subject'	=> $row['post_subject'],
    					);
    
    					$this->notification_manager->add_notifications(array(
    						'thanks',
    					), $thanks_data);
    
    Очевидно, что для этого сначала необходимо сделать инжекцию зависимости класса менеджера уведомлений.
    В services.yml:

    Код: Выделить всё

                - @notification_manager
    В конструкторе класса слушателя:

    Код: Выделить всё

    \phpbb\notification\manager $notification_manager
    с последующим присвоением (имя переменной может быть произвольным)

    Код: Выделить всё

    $this->notification_manager = $notification_manager;
  • ВАЖНО! В файл ext.php необходимо добавить инструкции по включению, выключению, удалению уведомлений вместе с расширением, во избежание возникновения неисправимых обычными средствами админраздела ошибок, связанных с отсутствием соответствующих сервисов для работы добавленных уведомлений. Пример можно увидеть в файле ext.php расширения Board rules.
Пример расширения с уведомлениями: Thanks for posts.
Патч, которым в данное расширение добавлены уведомления: #1b61df0f8.
Последний раз редактировалось rxu 31 авг 2014, 21:21, всего редактировалось 1 раз.
Причина: Добавление сведений о файле ext.php и функции users_to_query().

Аватара пользователя
Sheer
Сообщения: 23
Зарегистрирован: 22 янв 2014, 01:10

Создание уведомлений в расширениях

Сообщение Sheer »

Это ппц!
Как я сразу не увидел эту тему! Весь моск изломал себе, пока сам разобрался!
Но так и не понял такую фишку.
Создал новый тип уведомления.

Код: Выделить всё

'group'    => 'NOTIFICATION_GROUP_MODERATION', 
То есть это уведомление для модераторов, но почему оно присутствует в списке Личный раздел-->Личные настройки-->Изменить настройки уведомлений у всех пользователей, то есть там появляется строка Уведомления о модерации
По идее должно быть только у модеров.
Это косяк системы расширений или я чего-то не понял?
notify.jpg

Аватара пользователя
rxu
Сообщения: 1125
Зарегистрирован: 21 янв 2014, 21:20
Откуда: Krasnoyarsk
Github repo: https://github.com/rxu
Контактная информация:

Создание уведомлений в расширениях

Сообщение rxu »

Sheer писал(а):QR_BBPOST Это косяк системы расширений или я чего-то не понял?
Скорее второе ;) На примере post_in_queue.php.
Функция is_available() решает. Если в класс добавить, к примеру

Код: Выделить всё

protected $permission = 'm_approve';
и в функцию что-то типа

Код: Выделить всё

		$has_permission = $this->auth->acl_getf($this->permission, true);

		return (!empty($has_permission));

Аватара пользователя
Sheer
Сообщения: 23
Зарегистрирован: 22 янв 2014, 01:10

Создание уведомлений в расширениях

Сообщение Sheer »

То есть Функция is_available() не проверяет можно ли отправить уведомление, а смотрит будет ли этот тип в списке уведомлений?

Аватара пользователя
rxu
Сообщения: 1125
Зарегистрирован: 21 янв 2014, 21:20
Откуда: Krasnoyarsk
Github repo: https://github.com/rxu
Контактная информация:

Создание уведомлений в расширениях

Сообщение rxu »

В целом да. По названию понятно, от возвращаемого значения зависит, доступно уведомление пользователю, или нет.

Аватара пользователя
Sheer
Сообщения: 23
Зарегистрирован: 22 янв 2014, 01:10

Создание уведомлений в расширениях

Сообщение Sheer »

Надо бы отдельный форум "Для авторов", и подобные темы туда.

Отправлено спустя 2 минуты 48 секунд:
rxu писал(а):QR_BBPOST По названию понятно
По названию не совсем. Я понял это не так.

Код: Выделить всё

	/**
	* Is available
	*/
	public function is_available()
Хрен чё тут понятно... Кодеры, на каждый параметр в комментах целую портянку напишуть, а тут Доступно? Кому, где?

Ответить