Программное создание материалов с пользовательскими полями в Joomla 5+

Моя цель - предложение широкого ассортимента товаров и услуг на постоянно высоком качестве обслуживания по самым выгодным ценам.

С помощью материалов Joomla на сайте можно сделать не только контентный сайт-статейник или новостник, но каталог, простую доску объявлений и т.д. Начиная примерно года с 2016 очень много трафика из поисковиков уходит в соц.сети, стриминговые платформы, мессенджеры. Много контента стало создаваться напрямую в интерфейсе, например, Telegram. И в связи с этим встаёт вопрос об автоматическом наполнении сайта контентом из соц.сетей и мессенджеров. Для этого как раз и нужно знать как создавать материалы в Joomla 4 / Joomla 5 и старше программным способом.

Ко мне обратился один из пользователей моих расширений с просьбой помочь с импортом данных из сервиса парсинга объявлений о продаже автомобилей в Telegram. Со стороны сайта по CRON периодически выполнялся запрос к сервису, тот, видимо, проверял наличие новых объявлений и если они были - выполнял вебхук (запрос) к сайту с новыми данными. В одном запросе передавалось одно объявление. К слову сказать. у сервиса была интеграция с Joomla 4+, так как у Joomla есть REST API и всё в целом работало, материалы создавались. Однако, проблема заключалась в том, что необходимо было передавать данные в поля материалов, а их названия и id уникальные для каждого сайта и универсально сделать такую интеграцию проблематично. Поэтому было принято решение сделать отдельный плагин группы ajax для решения этой задачи.

Задача

Создание плагина создания материала Joomla по запросу из стороннего сервиса. Плагин должен преобразовать входные данные в структуру, понятную для Joomla, сохранять данные пользовательских полей. Во входящих данных также передаются фотографии в base64 кодировке, поэтому их нужно сохранить как файлы в папку на сайте и добавить в созданный материал.

Список литературы

Прежде хочу упомянуть другие источники и статьи, которые уже описывали похожие задачи:

  1. Статья Дмитрия Рекуна @b2z  Как программно создать материал с настраиваемыми полями на PHP

  2. Пример CLI-расширения для Joomla из этой статьи на GitHub

  3. Плагин создания материала из формы обратной связи для плагина Radical Form. Код на GitHub.

  4. Статья Владимира Егорова Как программно добавить статью в Joomla 3 и Joomla 4

  5. Моя статья Создание плагинов с учётом новой структуры Joomla 4

Зачем нужна ещё одна статья? Затем, что здесь будут описаны некоторые нюансы, которые нужно учитывать в процессе разработки подобных плагинов.

Решение задачи. Создание ajax плагина в Joomla.

По условиям заказчика плагин нужно было написать для Joomla 4.4.6. В пятой линейке на этот момент была актуальной Joomla 5.1.2, разработка велась на ней. 

Краткий обзор задачи

Технически, для разработчика задача представляет из себя следующее: сделать на стороне Joomla точку входа вида index.php?option=com_ajax&group=ajax&plugin=autodealerpro&format=raw, получить данные в виде JSON (чаще всего), разобрать на составляющие и создаём материал в нужной нам категории. Для этого мы должны взять модель материала (паттерн MVC, где M - Model) и скормить ей подготовленные должным образом данные. То же самое проделать потом для пользовательских полей. Затем, обработать и сохранить картинки, добавить в уже созданный материал и снова его сохранить. Почему будем делать именно так - читаем далее.

Выбор группы для плагина

В Joomla развитая система плагинов. Во время работы Приложения Joomla в разные моменты его жизненного цикла вызываются разные события. Эти события "слушают" плагины, получают данные для работы и возвращают их обратно, если это необходимо или выполняют любую необходимую в данный момент времени работу. Плагины группы system вызываются всегда и раньше, чем плагины конкретных групп. Если ваш плагин работает всегда и везде и решает разные задачи в разных местах сайта - делаем системный плагин, но учитываем, что к нему будет обращение даже тогда, когда он не нужен. Плагины конкретных групп вызываются в определенный момент времени, в определенном контексте и не создают дополнительную нагрузку, так как необходимый код выполняется только в нужный момент времени. Но это накладывает определенные ограничения и порой нужно создавать 2-3 плагина, которые можно было бы объединить в одном системном.

Создание плагина

Я предполагаю, что со статьёй Создание плагинов с учётом новой структуры Joomla 4 вы уже ознакомились и имеете общее представление о том, как плагин сделать, поэтому здесь будет описана конкретика для решения данной задачи.

Наш плагин называется autodealerpro, поэтому все неймспейсы включают данное имя. В ajax плагине будет метод onAjaxAutodealerpro - точка входа для обработки запроса и вызова функций. 

<?php
namespace Joomla\Plugin\Ajax\Autodealerpro\Extension;

// use Joomla\CMS\Event\Plugin\AjaxEvent; // for Joomla 5+
use Joomla\Event\Event; // For Joomla 4+  and Joomla 5
use Joomla\CMS\Form\Form;
use Joomla\CMS\HTML\HTMLHelper;
use Joomla\Database\DatabaseAwareTrait;
use Joomla\Filesystem\File;
use Joomla\Registry\Registry;
use Joomla\CMS\Plugin\CMSPlugin;
use Joomla\Event\SubscriberInterface;
use Joomla\CMS\Log\Log;

// phpcs:disable PSR1.Files.SideEffects
\defined('_JEXEC') or die;
// phpcs:enable PSR1.Files.SideEffects

Log::addLogger(
	['text_file' => 'plg_ajax_autodiealderpro.php'],
	Log::ALL,
	['plg_ajax_autodiealderpro']
);


final class Autodealerpro extends CMSPlugin implements SubscriberInterface
{
	use DatabaseAwareTrait;
	
	/**
	 *
	 * @return array
	 *
	 * @throws \Exception
	 * @since 4.1.0
	 *
	 */
	public static function getSubscribedEvents(): array
	{
		return [
			'onAjaxAutodealerpro' => 'onAjaxAutodealerpro'
		];
	}
	/**
	 * В аргументе функции для Joomla 4+ тип переменной $event должен быть Event
	 * Для Joomla 5+ - AjaxEvent. 
	 * Соответственно в начале файле в секции с use раскомментировать 
	 * use Joomla\CMS\Event\Plugin\AjaxEvent; для Joomla 5
	 * и ЗАкомментировать use Joomla\Event\Event;
	 * 
	 * Сделать это после обновления до Joomla 5. Хотя и так будет работать.
	 */
	public function onAjaxAutodealerpro(Event $event): void
	{

		/**
		 * Проверка безопасности. В парамтерах плагина есть "код". Этот же код
		 * должен указываться в каждом входящем запросе из сервиса.
		 * Если этого кода нет или он не совпадает - ничего не делаем.
		 */
		$input = $this->getApplication()->getInput();
		/** @var string $code Токен безопасности, указанный в настройках плагина */
		$code = $this->params->get('code');
		/** @var string $external_code Токен безопасности, который получаем в запросе */
		$external_code = $input->get('code', '');

		if ($code != $external_code)
	
		{
			return;
		}

 
		/** ПОЛУЧАЕМ ДАННЫЕ ИЗ JSON */
		$json = (new Registry())->loadArray($input->json->getArray());
		
		// А это было для тестов из файла
//		$json = (new Registry())->loadFile(__DIR__ . '/test.json');

		try
		{
			$this->createArticle($json);
		}
		catch (\Exception $e)
		{
			Log::add($e->getMessage(), Log::ERROR, 'plg_' . $this->_type . '_' . $this->_name);
		}
	}
}

В Joomla 5 для разных типов событий стали создавать кастомные классы этих событий для того, чтобы можно было использовать методы работы с данными, характерными для этих только событий. Для контентных плагинов - $event->getContext() вместо получения $event->getArgument(0); или $event->updateEventResult($data) для AjaxEvent для и т.д. Поэтому, как указано в комментариях к коду, тип аргумента $event для Joomla 4 и Joomla 5 различается. В Joomla 5 стоит использовать Joomla\CMS\Event\Plugin\AjaxEvent. Однако, можно указать тип Event и тогда плагин будет поддерживать обе линейки CMS.

Структура данных

На вход мы получаем json следующей структуры. Сразу обращаем внимание, что из Telegram с точки зрения web приходит довольно "грязный" текст, который нужно очищать от всяких эмодзи, специфичных для Telegram тегов а-ля <tg-spoiler>, но это не входило в круг задач на данном этапе.

{
    "title": "Продам: Honda CR-V 2.0 л.,2021 г., 61 000 км.",
    "articletext": "<b>Продам: Honda CR-V 2.0 л.,  2021 г.,  61 000 км.</b>\n\n<b>Характеристики</b>\n\n • <b>Пробег:</b> 61 000 км.\n • <strong>Год выпуска автомобиля</strong>: 2021\n • <strong>Цвет автомобиля</strong>: синий\n • <strong>Тип кузова</strong>: внедорожник 5-дв.\n • <strong>Состояние</strong>: не битый\n • <strong>Тип топлива</strong>: бензин\n • <strong>КПП</strong>: вариатор\n • <strong>Привод</strong>: полный привод\n • <strong>Расположение руля</strong>: левый\n • <strong>Объем двигателя</strong>: 2.0 л.\n\n<b>Стоимость</b>: 3 850 000 RUB\n\n<strong>Дополнительно:</strong> Продам хонда срв2.0гибрид комплектация туринг.машинка в отличном состоянии.все расходники поменяны.дачики слепых зон.электро сидения.память сидений подогрев.двухзоный климат.кнопка старт стоп.дачик сближения авто само торможение.удержание в полосе.дачик дождя.+7******* телеграм\n\n						
Источник: https://habr.com/ru/articles/832854/


Интересные статьи

Интересные статьи

Привет, HABR!Все те кто пользуются системой мониторинга Zabbix, с большой вероятностью, уже использовали UserParameter. Это, безусловно, очень полезный инструмент позволяющий значительно расширить баз...
На Joomla CMS сделано очень много сайтов для образовательных учреждений самого разного уровня и сложности. На сайты образовательных учреждений распространяется (на момент написания статьи) Приказ Росо...
В этом дайджесте обсуждаем ужасную документацию Apple, запуск Android Studio на любом устройстве, переезд на Kotlin (в том числе и Multiplatform), создание бэкенда без серверных разработч...
Доброго времени суток! В данной статье я опишу создания своих элементов для C# Windows Form. Для примера буду создавать таблицу со всем функционалом DataGridView. Позже перейдем на свои эл...
Я хотел, чтобы в моей игре The Last Boundary была туманность. Они потрясающе выглядят и космос без них не космос, а просто разбросанные по фону белые пиксели. Но так как игру я делаю в стиле «пик...