Материал, хочу надеяться, будет интересен профессиональным разработчикам расширений 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()
{
$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 будет более правильно, автор задался сугубо русским вопросом: а почему нельзя-то, что мешает? - вот раньше было можно а щас нет, как так? - бага?? ниче, ща мы набьем мике баки... и ринулся с этим разбираться.
Результатом усилий, как ни странно, явилась вполне себе полезная информация. Правда, не сразу.
Второе лирическое отступление. Кодовую базу, послужившую иллюстрацией к материалу - в любой момент возможно увидеть целиком (а не фрагментарно, как продиктовано форматом статьи) в этом репо, где-то там же без проблем найдете и старую версию модуля.
Идем дальше. Итак, попытка использовать JText в хелпере успехом не увенчалась, снова ждал афронт:
Class 'FooNamespace\Module\Foo\Site\Helper\JText' not found
Как вариант, в хелпере можно было попробовать использовать класс Text вместо JText, и это вполне работает, см. в качесте аргумента сказанному libraries/src/helper/ContentHelper.php.
Но почему же так странно, почему в хелпере модуля возможен, по-видимому, только Text, а для шаблона модуля сгодится и JText?
Как это? Возможно, отработало наследование шаблоном модуля? - вряд ли, правила импорта построены так, что включенные файлы не наследуют импорт файла родительского (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, позволяют включенному файлу наследовать область видимости, вот оно в чем дело, да?.
На самом деле нет, все гораздо проще.
Вспомним, как именно PHP обрабатывает пространства имен: каждый класс здесь находится в своем неймспейсе, поэтому, строго говоря, не существует никакого JText, а есть только \JText (FQN, fully qualified name). Обращение к FQN происходит еще на этапе парсинга файла (существует исключение для функций и констант, но к нашему кейсу это не имеет отношения), и если пространство имен в начале файла указано, то JText считается расположенным в нем, в противном же случае подразумевается глобальное пространство имен \. Поэтому внутри пространства имен или используем \JText, или же стандартно указываем на него в начале файла:
use \JText;
Вероятнее всего, в причинах нашей проблемы Joomla вообще ни при чем, поскольку не в состоянии повлиять на парсинг файла интерпретатором PHP.
К слову, для новых проектов - вместо \JText, который родом еще с Joomla 1.5, оптимально сразу использовать \Joomla\CMS\Language\Text, он доступен начиная с Joomla 3.8. Заметим, последовательность загрузки в 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, находящейся сейчас, видимо, в состоянии бурного своего развития... ок, в добрый час. Хотя более подробная дока тем более не помешала бы, чтоб не было необходимости и дальше ломать голову над изысками магии самого из всех дружелюбного к своим пользователям фреймворка.
Комментарии в блоге