Joomla для разработчиков
103 subscribers
15 photos
62 links
Полезное из мира Joomla:
- документация для разработчиков и опытных пользователей;
- интересные находки.

Мы ВКонтакте - https://vk.com/jpathru
Наш веб-сайт - https://jpath.ru

Есть интересный материал? @drekun
Download Telegram
Какой интерфейс нужно реализовать, чтобы создать пользовательский плагин с собственными обработчиками событий?
Anonymous Quiz
18%
EventInterface
18%
DispatcherInterface
64%
EventSubscriberInterface
Как в Joomla 5 получить активный пункт меню?
Anonymous Quiz
17%
Factory::getMenu()->getActive()
72%
Factory::getApplication()->getMenu()->getActive()
11%
MenuHelper::active()
Как получить текущего пользователя в Joomla 5?
Anonymous Quiz
35%
Factory::getApplication()->getUser()
18%
Factory::getUser()
47%
Factory::getApplication()->getIdentity()
Какой константой можно получить текущую версию Joomla?
Anonymous Quiz
67%
JVERSION
17%
JOOMLA_VERSION
17%
CMS_VERSION
Forwarded from WebTolkRu (Sergey Tolkachyov)
👩‍💻 Свои типы полей в Joomla.
Это большая тема, о которой можно говорить очень много. Самое главное, что возможности применения ограничиваются только вашей больной фантазией. Вы строите интерфейс своего модуля или плагина и вам нужно подтянуть данные из сторонней системы (список чего-нибудь по какому-нибудь API), чтобы сохранить выбранный id в Joomla. Или сделать какую-то проверку и в зависимости от неё показать то или иное сообщение пользователю. Для этого подойдут свои пользовательские типы полей.

Интерфейс Joomla по большей части описан в XML-файлах. У каждого из них свои параметры. Некоторые не описаны в документации (manual.joomla.org), поэтому самым любопытным будет полезно заглянуть в собственно файлы фреймворка по пути libraries/src/Form/FormField.php, а так же в libraries/src/Form/Fields. У каждого класса поля перечислены его специфические свойства, которые можно описывать в XML. А в своём типе поля вы можете устанавливать эти значения программно.

В моём модуле WT Quick links под капотом происходят изменения. Теперь для работы (в админке) ему нужен вспомогательный плагин. А в самом модуле нам бы проверить, а не выключен ли он?

В Joomla есть тип поля Note - заметка. Его можно использовать для вывода примечаний.
<field type="note"
name="your_note_for_user"
label="Заголовок примечания"
title="Альтернативный способ для заголовка"
description="Текст примечания"
class="col-12 alert alert-info"
heading="h1"
close="true"
/>

heading - указывать уровень заголовка. close - позволяет закрыть это примечание.

В классе поля libraries/src/Form/Field/NoteField.php описана логика вывода. И в принципе оно нам подходит для нашей задачи. Но оно будет выводить сообщение всегда, а нам нужно только тогда, когда плагин отключён.

Поэтому берём и создаём свой класс поля, который мы унаследуем от NoteField. Это значит, что у нас в руках будет весь инструментарий стандартного поля Note + то, что мы сами добавим.

В XML-манифест добавляем наше поле
<field type="systempluginstatus" 
name="systempluginstatus"
addfieldprefix="Joomla\Module\Wtquicklinks\Site\Fields"/>

- type - имя файла и класса,
- addfieldprefix - указываем namespace к нашему классу, может быть любой нам нужный
- name - нельзя полю без имени...
Это означает, что Joomla будет использовать класс поля из файла modules/mod_wt_quick_links/src/Fields/SystempluginstatusField.php.
А в классе поля будет написано следующее:
<?php
// namespace для атрибута addfieldprefix
namespace Joomla\Module\Wtquicklinks\Site\Fields;
// нельзя напрямую обращаться к этому файлу
defined('_JEXEC') or die;
// подключаем родительский класс для переопределения
use Joomla\CMS\Form\Field\NoteField;
use Joomla\CMS\Language\Text;
use Joomla\CMS\Plugin\PluginHelper;

// имя класса и имя файла точь-в-точь
class SystempluginstatusField extends NoteField
{
protected $type = 'Systempluginstatus';

protected function getLabel()
{
// если плагин не включён
if(PluginHelper::isEnabled('system','wtquicklinks')) {
// меняем свойства родительского класса
$this->class = 'alert alert-danger w-100';
$this->element['label'] = '⚠️ А-а-а-а!';
$this->element['description'] = 'Плагин не включён!!';
// и просто рендерим его с нашими свойствами
return parent::getLabel();
}
// А иначе всё хорошо, скрываем поле из виду.
$this->parentclass = 'd-none';
return '';
}
}

Просто и удобно. И людям приятно, что о них позаботились и рассказали почему что-то не работает.

@webtolkru

#joomla #php #webdev #разработка
Please open Telegram to view this post
VIEW IN TELEGRAM
1
Forwarded from Joomla Feed (Sergey Tolkachyov)
👩‍💻 Как триггерить события для плагинов на манер Joomla 5+?
В Joomla 6 должны удалить метод triggerEvent(), с помощью которого раньше вызывались события для плагинов. Теперь чтобы в своём коде вызвать событие для плагина и получить от него результаты нужно:
- создать объект класса события
- передать в него параметры
use Joomla\CMS\Event\AbstractEvent;
use Joomla\CMS\Factory;
use Joomla\CMS\Plugin\PluginHelper;

// Грузим плагины нужных групп
PluginHelper::importPlugin('system');
// Создаём объект события
$event = AbstractEvent::create('onAfterInitUniverse', [
'subject' => $this,
'data' => $data, // какие-то данные
'article' => $article, // ещё материал вдовесок
'product' => $product, // и товаров подвезли
]);
// Триггерим событие
Factory::getApplication()->getDispatcher()->dispatch(
$event->getName(), // Тут можно строку передать 'onAfterInitUniverse'
$event
);
// Получаем результаты
// В случае с AbstractEvent это может быть не 'result',
// а что-то ещё - куда сами отдадите данные.
// 2-й аргумент - значение по умолчанию,
// если не получены результаты
$results = $event->getArgument('result', []);

Плюсы такого подхода - вам не нужно запоминать порядок аргументов и проверять их наличие. Если вы написали свой класс события, то в плагине можно получать аргументы с помощью методов $event->getArticle(), $event->getData(), $event->getProduct() и подобными - реализуете сами под свои нужды.
Если такой класс события написали, то создаёте экземпляр своего класса события и укажите его явно в аргументе eventClass
use Joomla\Component\MyComponent\Administrator\Event\MyCoolEvent;

$event = MyCoolEvent::create('onAfterInitUniverse', [
'subject' => $this,
'eventClass' => MyCoolEvent::class, // ваш класс события
'data' => $data, // какие-то данные
'article' => $article, // ещё материал вдовесок
'product' => $product, // и товаров подвезли
]);

Ожидаемо, что класс вашего события будет расширять AbsractEvent или другие классы событий Joomla.

🙁 Есть неприятный нюанс - нельзя просто так вызывать событие и ничего не передать в аргументы. Аргумент subject обязательный. Но если вы всё-таки не хотите туда ничего передавать - передайте туда пустой stdClass или объект Joomla\registry\Registry.

@joomlafeed

#joomla #php #webdev
Please open Telegram to view this post
VIEW IN TELEGRAM
Переход на Joomla 6. Что сделано с пакетом Filesystem из пространства имён \Joomla\CMS\Filesystem?
Anonymous Quiz
27%
Полностью удалён
27%
Перенесён в плагин обратной совместимости
47%
Остался, но помечен deprecated
Forwarded from Joomla Feed (Sergey Tolkachyov)
👩‍💻 Совет по Joomla: несколько значений по умолчанию в XML-формах для стандартных полей типа list.
При работе над плагином возникла необходимость указать стандартный набор из нескольких элементов стандартного поля списка. И хотелось указать их в стандартном же атрибуте default для полей.

Когда это нужно?
Когда Ваши пользователи устанавливают плагин и НЕ заходят в настройки - в коде вы можете использовать значения по умолчанию с помощью класса Registry (писал об этом ранее) и всегда быть уверенным, что хоть какие-то жизненно необходимые параметры к вам придут всегда.

🧐 Но как сделать то же самое для интерфейса админки?
Пользователя нужно направлять, предлагать очевидный работоспособный сценарий для начала, а дальше он уже сам разберется. Когда человек заходит в параметры свежеустановленного плагина в Form ещё нет данных и параметры по умолчанию выставляются из атрибутов default в xml-полях.
<field name="showdesc" type="radio"
label="PLG_CFI_PARAM_SHOWDESC"
class="btn-group btn-group-yesno"
default="1">
<option value="0">JNO</option>
<option value="1">JYES</option>
</field>

Здесь по умолчанию будет включено "Да". И если пользователь не переключит параметр, то при сохранении мы ожидаемо получим "да" в params плагина.
Для поля списков type="list" можно указать значение по умолчанию и многие знают, что его можно указать только одно.
<field type="list"
name="article_fields"
label="article_fields"
description="article_fields_desc"
layout="joomla.form.field.list-fancy-select"
multiple="true"
default="id"
>
<option value="id">id</option>
<option value="title">title</option>
<option value="alias">alias</option>
<option value="introtext">introtext</option>
<option value="fulltext">fulltext</option>
<option value="state">state</option>
</field>

Но у нас поле с множественным выбором (атрибут multiple) и хотелось бы указать несколько значений по умолчанию...
Оказывается, так можно сделать. Для этого в атрибуте default нужно указать json с нужными параметрами в виде {int}key : {string} value.
Например, default='{"0":"id","1":"title"}'.
<field type="list"
name="article_fields"
label="article_fields"
description="article_fields_desc"
layout="joomla.form.field.list-fancy-select"
multiple="true"
default='{"0":"id","1":"title"}'
>
<option value="id">id</option>
<option value="title">title</option>
<option value="alias">alias</option>
<option value="introtext">introtext</option>
<option value="fulltext">fulltext</option>
<option value="state">state</option>
</field>

⚠️ Обратите внимание на кавычки! Поскольку json_decode не понимает одинарные кавычки собственно json нужно писать с двойными, а значение для атрибута default писать в одинарные.

🙏 За подсказанное решение огромное спасибо участникам нашего сообщества - разработчикам Дмитрию Васюкову (@fictionlabs) и Игорю Бердичевскому (@septdir).

@joomlafeed

#joomla #разработка #webdev #development
Please open Telegram to view this post
VIEW IN TELEGRAM
Forwarded from WebTolkRu (Sergey Tolkachyov)
👩‍💻 Совет по Joomla: замена File::append() в Joomla 6.
В Joomla постепенно, хоть порой и непоследовательно, убирают старое API, доставшееся в наследство от CMS и заменяют его на API от Joomla Framework. При этом порой не обходится без потерь. Многие классы и методы ядра годами имеют статус deprecated, многим имеется альтернатива.

Такими классами являются классы для работы с файловой системой сервера Joomla\CMS\Filesystem. Они перемещены в плагин обратной совместимости Joomla 6 и могут ещё работать. Но лучше постепенно переходить на новые методы, а в новых расширениях использовать их сразу.
Одним из "пострадавших" методов стал File::append(), который добавлял содержимое в конец файла. Это обёртка для file_put_contents() с разными проверками, использованием потоков, если надо и т.д. Заменой для этого метода станет File::write() с флагом appendToFile.
Параметры метода
- string $file – Абсолютный путь к файлу
- string $buffer – Содержимое
- bool $useStreams false – Использовать потоки
- bool $appendToFile false – дописывать ли в конец или перезаписывать файл
use Joomla\Filesystem\Filesystem;

$absoluteFilePath = JPATH_SITE . '/dir/file.txt';
$content = 'Содержимое файла';

// appentToFile - 4-й аргумент
File::write($absoluteFilePath, $content, false, true);

Либо с PHP 8.0 можно использовать именованные аргументы, и тогда не важен их порядок и наличие необязательных.
use Joomla\Filesystem\Filesystem;

$absoluteFilePath = JPATH_SITE . '/dir/file.txt';
$content = 'Содержимое файла';

//Именованные аргументы, appentToFile теперь 3-й аргумент
File::write(file: $absoluteFilePath, buffer: $content, appendToFile: true);

Класс находится в libraries/vendor/joomla/filesystem/src/File.php. Кстати, для некоторых удалённых методов теперь нужно использовать нативные функции php.
- вместо Folder::exists() ➡️ is_dir()
- вместо File::exists() ➡️ is_file() или file_exists()

@webtolkru

#joomla #php #webdev #разработка #development
Please open Telegram to view this post
VIEW IN TELEGRAM
1
Forwarded from Joomla Feed (Sergey Tolkachyov)
👩‍💻 Обработка HTTP ответа в Joomla 6+. Изменения по сравнению с Joomla 3 - Joomla 5.
В Joomla для выполнения внешних запросов из PHP к сторонним API используется класс Joomla\Http\Http напрямую или же Joomla\Http\HttpFactory, который возвращает для работы преднастроенный по умолчанию класс Http. О работе с HTTP-запросами подробно рассказывалось в статье 2021 года Создание внешних запросов с использованием HttpFactory (Joomla). Некоторые изменения касаются работы с ответами на запросы. Например, наш запрос:
use Joomla\Http\HttpFactory;

$http = (new HttpFactory)->getHttp($options, ['curl', 'stream']);
$response = $http->get('https://any-url.ru/api/any/endpoint');

Раньше можно было получить код ответа или тело ответа как свойство $response - $response->code или $response->body. Однако, Joomla, начиная с Joomla 4 во многом переходит на стандарты PSR. В частности для работы с HTTP-ответами - на PSR-7. Также хорошая статья на Хабре о PSR-7: PSR-7 в примерах.
Прямое обращение к свойствам code, headers, body объявлено устаревшим в Joomla 6.0.0 и обещают удалить в Joomla 7.0.0.

Вместо этого нужно работать с HTTP-ответом по стандартам PSR-7.
Код ответа.
Было $response->code. Стало $response->getStatusCode().
Заголовки ответа.
Было $response->headers. Стало $response->getHeaders().
Тело ответа.
Было $response->body. Стало (string)$response->getContents().

В тело ответа теперь приходит не строка, а поток - объект класса Laminas\Diactoros\Stream. Поэтому его нужно привести к строке (если это json, к примеру): (string)$response->getContents(). Чаще всего в коде Joomla встречается именно такой вариант. Однако, есть и вариант с перемещением указателя чтения на начало потока:
// Получили ответ в виде потока
$stream = $response->getBody();
// "перемотали" на начало
$stream->rewind();
// Получили строковый ответ
$json = $stream->getContents();

В итоге результат одинаковый.

@joomlafeed

#joomla #разработка #php
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥2
Forwarded from Joomla Feed (Sergey Tolkachyov)
This media is not supported in your browser
VIEW IN TELEGRAM
👩‍💻 Совет по Joomla: использовать выключенное состояние для кнопок в списках элементов админки - listCheck().
Мы добавляем в тулбар панели администратора Joomla некую кнопку, которая что-то делает со списком id выделенных элементов и ajax-запросом отсылаем их в свой плагин. Но нам надо предупредить нажатия на кнопку в тех случаях, когда ни один элемент не был выбран. Для этого можно написать свою проверку на js. А можно воспользоваться встроенной в Joomla.
Как это сделать - читаем в посте на Хабре.

@joomlafeed

#joomla #php #разработка #webdev
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2
Forwarded from Joomla Feed (Sergey Tolkachyov)
👩‍💻 События плагинов и порядок их срабатывания при работе с пользовательскими полями Joomla и использовании FieldsHelper.

В процессе работы с Joomla бывает необходимо работать с пользовательским интерфейсом более тонко, чем обычно. Все формы Joomla состоят из стандартных полей, содержанием, стилем отображения, состоянием (включено/выключено, доступно для редактирования или нет и т.д.) можно управлять с помощью плагинов. Да и для нестандартных проектов хорошей практикой является создание одного системного или нескольких плагинов групп "под проект", в которых храниться весь "нестандарт".

В этой статье описаны все триггеры, которые вызываются через Event Dispatcher из administrator/components/com_fields/src/Helper/FieldsHelper.php, с привязкой к жизненному циклу (порядку этапов работы запроса), аргументам, изменяемым данным и дальнейшему распространению по Joomla. Это поможет вам работать с Joomla свободнее и не опасаясь при этом потерять изменения при очередном обновлении движка.

Подходы, описанные в статье, полезны в тех случаях, когда вы работаете с данными в com_fields - механизме создания и редактирования пользовательских полей ядра Joomla и при использовании FieldsHelper. Многие сторонние компоненты не используют эту возможность, поэтому данная статья будет полезна лишь частично.

Читать статью на Хабре.

@joomlafeed

#joomla #разработка
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1
Forwarded from WebTolkRu (Sergey Tolkachyov)
👩‍💻 Особенность Joomla: json-значения для пользовательских полей и их рендер в subform и вне дочерней формы.

Опять длинное название, но куда уж без этого...

Итак, если вы делаете плагин пользовательского поля - его можно использовать через FieldsHelper. И в процессе ваши данные проходят через различные этапы обработки (недавно был пост+статья на эту тему). И может так оказаться, что ваше поле хранит в rawvalue json (и в базе данных соответственно тоже), а в value вы на его основе рендерите значение. Это стандартный подход Joomla. Так работают, например, поля accessiblemedia. Однако, если вы поместили ваше поле в дочернюю форму (пользовательское поле типа subform и включили "Рендеринг значений = Да", то у вашего замечательного поля может появиться поломанный Json в value вместо нормального значения.
Например:
{&quot;basePath&quot;:&quot;...&quot;,&quot;layout&quot;:&quot;...&quot;}

Что там под капотом Joomla происходит?

1. В обычном потоке Joomla сначала вызывает событие onCustomFieldsBeforePrepareField, а потом onCustomFieldsPrepareField.
2. Внутри subform же для подполей при render_values=1 вызывается только событие - onCustomFieldsPrepareField.
3. Если преобразование значения (например, json_decode) сделано в вашем плагине только в beforePrepareField, оно не обработает данные для подполя и...
4. В шаблоне поля строка заэкранируется (htmlentities), кавычки превратятся в тыкву в &quot; и вы получите кривой json, вместо вашего значения

👉 Собственно полезный совет по Joomla:
Для полей, которые могут жить внутри subform, делайте нормализацию значения и в onCustomFieldsPrepareField тоже, не только в beforePrepareField.

@webtolkru

#joomla #webdev #разработка #php #development
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3
Forwarded from Joomla Feed (Sergey Tolkachyov)
👩‍💻 Переопределение классов ядра Joomla с помощью плагина на примере MVCFactory.

Разработчики сайтов, веб-мастера, рассматривая Joomla как CMS, чаще всего используют компоненты ядра такими, какие они есть. Но компоненты ядра, обеспечивающие CRUD-ы в Joomla, следует рассматривать ещё и как примеры использования Joomla в качестве фреймворка. Иногда реалии проекта таковы, что требуется внести изменения именно в логику классов ядра Joomla. Я покажу это на нескольких примерах: как исхитрялись раньше и какие возможности появились в современных версиях Joomla.

В статье речь идёт не о том, чтобы править файлы ядра. Это плохая идея почти всегда. При обновлении Joomla такие изменения будут потеряны, а сопровождать их потом придётся вручную. Речь о другом: как изменить точку создания MVC-классов компонента через плагин и DI-контейнер, не залезая в core-файлы.

Ну и приятный бонус - Joomla-археология и немного красивого и ужасного треша из практики 😎

Читать статью

#joomla #разработка
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2
Forwarded from Joomla Feed (Sergey Tolkachyov)
👩‍💻 Общая информация о принципе действия Joomla 6. Жизненный цикл Приложений Joomla.

Как работает ядро Joomla 6 на уровне Приложения (Application)? Сколько видов Приложений на самом деле есть в Joomla и в чём между ними разница? Какой жизненный цикл каждого Приложения Joomla, включая роутинг, диспетчеризацию и события плагинов? На эти и другие вопросы попытается дать ответ эта статья, опирающаяся на кодовую базу Joomla 6.1.0. Также в статье хронология вызова триггеров плагинов в разных сценариях.

👉 Бонус для любопытных читателей: а вы знали, что Joomla можно использовать в качестве daemon-процесса?

Читать статью

@joomlafeed

#joomla #разработка
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2