Попытаюсь рассказать здесь о некоей коллизии, с которой столкнулся, переписывая старый свой модуль Joomla 3 под Joomla 4. Материал, хочу надеяться, будет интересен профессиональным разработчикам расширений Joomla, несмотря на то обстоятельство, что автор данного текста таковым не является, давно отойдя не только от программирования под Joomla, но и вообще от кодинга на PHP. Но остались старые какие-то проекты, к которым изредка возвращаюсь, больше из ностальгических воспоминаний: что-то уже подзабыл, признаться, многое стало казаться скучным. И в этой связи хочу выразить искреннюю признательность Toivo Talikka, Global Moderator-у форума Joomla.org, чей неподдельный интерес и живое участие в обсуждении и тестировании проблемы сделали возможным написание этой статьи, вскрыв ряд недокументированных особенностей архитектуры четвертой ветки Joomla.
Сходу короткое лирическое отступление. Предпринята, как видите, попытка разбавить сухой технический материал рисунками замечательного петербургского художника Петра Изосимова, с которым автор немного знаком и чья изумительная всегда ирония вполне коррелирует в данном случае с вектором, скажем так, отношения автора к "наличию отсутствия" (в контексте ряда искомых кейсов только, разумеется) документации одного из самых популярных на сегодняшний день CMS-фреймворков. Хм, может статься, мы попросту не нашли; если так, буду благодарен за соответствующие ремарки в комментах. Но не думаю.
Описанный далее экзерсис основан, в частности, на анализе загрузочных файлов Joomla и вполне себе способен содержать gaps and inaccuracies, пробелы и неточности. И - тем не менее - я приступаю к рассказу: примеров и туториалов, доходчиво объясняющих простым смертным критичные подробности кодинга расширений долгожданной Joomla 4 на сегодняшний день в Сети немного, буквально считанные единицы. Уверен, пригодится и вообще в тему.
Итак. Дебажа модуль (это несложный виджет, представляющий собой удобный пользовательский интерфейс клиента ряда погодных API и сервисов определения геотаргетинга), отметил странный казус: в новой версии модуля я не мог так же запросто, как делал это ранее, использовать класс JText в хелпере модуля, объявляя, скажем, массив:
// Helper/FooHelper.php
namespace FooNamespace\Module\Foo\Site\Helper;
defined('_JEXEC') or die;
use Joomla\CMS\Factory;
class FooHelper
{
public static function getNames($params)
{
$main = array(
JText::_('STRING_ONE'),
JText::_('STRING_TWO')
);
return $main;
}
}
А вот в HTML-е модуля - мог. Например, так:
// tmpl/default.php
foreach (array_combine($names, $source) as $names => $source):
$html .= '<tr>';
$html .= '<td>' . JText::_($names) . '</td>';
$html .= '<td>' . $source . '</td>';
$html .= '</tr>';
$i++;
endforeach;
Не отвлекаясь в тот момент на увлекательные рассуждения о том, как именно в парадигме MVC будет более правильно, автор задался сугубо русским вопросом: а почему нельзя-то, что мешает? - вот раньше было можно а щас нет, как так? - бага?? ниче, ща мы набьем мике баки... и попер с этим разбираться.
Результатом усилий, как ни странно, явилась вполне себе полезная информация. Правда, не сразу.
Второе лирическое отступление. Кодовую базу, послужившую иллюстрацией к материалу - в любой момент возможно увидеть целиком (а не фрагментарно, как продиктовано форматом статьи) в этом репо.
Идем дальше. Спервоначалу пришло в голову, что элементарно не хватает алиаса:
use Joomla\CMS\Language\Text;
, примерно так, собственно, и выходит по актуальной доке и примерам кода базового модуля под Joomla 4. Но увы, здесь снова ждал афронт:
Class 'FooNamespace\Module\Foo\Site\Helper\JText' not found
Как вариант, в хелпере можно было попробовать использовать класс Text вместо JText, и это вполне должно работать, см. в качесте аргумента libraries/src/helper/ContentHelper.php.
Но почему же так странно, почему в хелпере модуля возможен, по-видимому, только Text, а для шаблона модуля сгодится и JText, причем нигде в файлах модуля Joomla 4 я не указывал этого импорта:
$ grep -Fri "use Joomla\CMS\Language\Text;"
$
Как это? Возможно, отработало наследование шаблоном модуля? - вряд ли, правила импорта построены так, что включенные файлы не наследуют импорт файла родительского (Importing rules are per file basis, meaning included files will NOT inherit the parent file's importing rules, Using namespaces: Aliasing/Importing). Объяснение, по-видимому, заключено в
require ModuleHelper::getLayoutPath('mod_foo', $params->get('layout', 'default'));
, именно эту строчку содержит foo.php, точка входа модуля. Операторы require и include, в отличие от use, позволяют включенному файлу наследовать область видимости, вот оно где собака порылась.
Резюме. Разница между классами JText и Text в том, что Text способен быть объявлен только лишь внутри пространства имен. Иными словами, для того, чтобы ссылаться непосредственно на Text вместо JText, необходимо определение неймспейса. К слову, последовательность загрузки в libraries/classmap.php - содержит сопоставление JText, обеспечивая совместимость с новым классом Text, предназначенным, видимо, в Прекрасной Джумла Будущего полностью заменить JText:
JLoader::registerAlias('JText', '\\Joomla\\CMS\\Language\\Text', '5.0');
Данное сопоставление концептуально связывает JText с файлом libraries/src/Language/Text.php, который начинается со следующего объявления пространства имен, общего для файлов в папке libraries/src/Language:
namespace Joomla\CMS\Language;
Вот, в принципе, и все решение. Задавшись пустяковым, в общем, вопросом, мы неожиданно пришли к попытке понимания логики архитектуры Joomla, находящейся сейчас, видимо, в состоянии бурного своего развития... ок, в добрый час. Хотя более подробная дока тем более не помешала бы, чтоб не было необходимости и дальше ломать голову над изысками магии самого из всех дружелюбного к своим пользователям фреймворка.
Комментарии (11)
mobi
23.03.2022 13:50+1Если честно, то не понял, в чем собственно была ошибка изначально. По идее,
JText
в Joomla является глобальным алиасом (т.е. расположенном в пространстве имен верхнего уровня) и должен работать в любом месте.Вообще, в расширениях Joomla! как правило код или помещается в глобальное пространство имен (т.е.
namespace
не используется) и тамJText
работает как положено, или код помещается в свое пространство имен, и тогда нужно использовать или\JText
, или\Joomla\CMS\Language\Text
(обычно для простоты черезuse Joomla\CMS\Language\Text
).cmirnow Автор
23.03.2022 22:08Если честно, практика показывает: в абсолютном большинстве случаев непонимание возможно лишь тогда, когда нет желания понять или попросту лениво чутка подвигать известным местом. Все ведь разжевано, буквально step-by-step; а в ответ тебе "все должно работать". Ровно бессмысленное утверждение ведь это у вас, нет? ну, ежели "должно работать", стало быть, "пусть работает", я совершенно не против. Ну, а дальше-то что? - тупиковый тезис. Схоластический.
Скачайте модуль с гитхаба или из JED, инсталлируйте на актуальную версию четверки, в точке входа оставьте, для чистоты эксперимента, только один вызов, в хелпере - только одну указанную в статье функцию, содержащую ссылку на класс JText. В темплейте также поудаляйте инициализацию всего HTML, включив лишь var_dump($names);. И перезагрузите страничку с опубликованным модулем, результат вас приятно удивит. Теперь есть возможность сколь угодно долго себе любимому твердить, что "должно работать", но работать оно не будет. )) P.S. Тестировал на PHP 7.4 и 8.0
mobi
24.03.2022 22:09Это как раз тот случай, когда "всё должно работать". Нужно только немного понимать, как PHP обрабатывает пространства имен. В PHP каждый класс находится в некотором пространстве имен, поэтому на самом деле нет никакого
JText
, а есть только\JText
(это называется fully qualified name, или сокращенно FQN). Причем, переход к FQN происходит еще на этапе парсинга файла (там есть исключение для функций и констант, но к данному случаю это не имеет отношения), и если пространство имен в начале файла указано, тоJText
будет считаться расположенным в нем, а если не указано, то подразумевается глобальное пространство имен\
. Поэтому внутри своего пространства имен или используйте FQN-форму\JText
, или укажите на нее PHP черезuse \JText;
. Но Joomla тут ни при чем — она повлиять на парсинг файла интерпретатором PHP не может.PS. Для новых проектов вместо
\JText
, который тянется еще со времен Joomla 1.5, я бы рекомендовал сразу использовать\Joomla\CMS\Language\Text
, который доступен начиная с Joomla 3.8. Так потом будет проще на Joomla 5 перейти.cmirnow Автор
25.03.2022 02:56Исчерпывающее объяснение. Вы правы, это логично и работает. Возражу лишь в частности: думаю, нет смысла сейчас говорить о переходе на Joomla 5, когда многие еще даже на Joomla 4 мигрировать не в состоянии, ввиду отсутствия для целого ряда знаковых расширений соответствующей адаптации. Например, в начале марта только-только появился RC Kunena, а для популярнейшего CCK K2 не вижу пока даже бетки. И это лишь начало списка.
Septdir
23.03.2022 15:02+1Интересное изыскание, однако по сути бессмысленное. Для того чтобы разобраться надо погрузиться в историю. Переход на namespaces начался еще в 2017.
Глобальные алисасы были добавлены тогда же в качестве legasy для упрощения обновления расширений для Joomla 4.
\Joomla\CMS\Language\Text
был одним из первых доступных для использования. Так что уже лет 5 в основном используется именно он.Сама же так же Joomla 4 является переходной версией, по заверению разработчиков в Joomla 5 Legasy, который тянется уже ни одну мажорную версию будет наконец убран.
b2z
24.03.2022 18:53Ruby Developer пишет о Joomla, и это прекрасно! :)
cmirnow Автор
24.03.2022 20:06Домашняя страничка ruby developer-a начиналась когда-то с J1.5, претерпев с тех давних лет ряд миграций; в чем совсем несложно убедиться, глянув последнюю его редакцию по ссылке в профиле. :)
К слову, Дмитрий, возможно, именно работа с рядом иных фреймфорков, нежели CMS-фреймворк Joomla, изменили мое отношение и к Joomla и к работе на нем тоже: увы, именно несомненное дружелюбие этого отличного, в общем, поделия - сыграло с ним, на мой субъективный взгляд, злую шутку. Когда читаешь тирады у вас на joomlaforum.ru, реально оторопь берет: абсолютное большинство "жумла-разработчиков" никогда не пробовали спуститься пусть даже на один уровень абстракций ниже веб-интерфейса панели управления или консоли отладчика браузера... что очень плохо, т.к., несомненно, дискредитирует в глазах заказчиков как собственно Joomla, так и разработку на нем.
Утверждение не голословно, несложно увидеть подтверждение сказанному пусть даже на основе комментариев этой странички: на данный момент ни одного ведь коммента по существу, ребята элементарно пиарится, подавая схоластические, оторванные от реальности реплики по типу "должно быть вот так а не эдак" или "а мне жумла нравится, несмотря ни на что". Черт возьми, да мне тоже "Joomla нравится", в отличие от безграмотного подхода к ней; могу вас уверить, что описанное абсолютно немыслимо в коммьюнити программистов, специализирующихся на иных фреймворках.
greenkey
Люблю joomla за ее программную архитектуру. Очень жаль, что 4 версия так сильно опоздала, и в сайтоподелках тотальное распространение получил вордпресс, с его нескучными шаблонами ;-)
impvision
Я как человек, кто создает именно проекты на этом движке - очень был удивлен изменениям в 4 версии, в целом очень даже понравилось. Хотя алогичность в основном меню опять присутствует.