Наследование значений MIGX TV между ресурсами MODX

Автозаполнение MIGX TV в MODX MODX Revo

При работе с проектами на MODX Revolution нередко возникает ситуация, когда в ресурсе нужно повторно использовать данные, уже заданные в родительской категории. Чаще всего это касается дополнительных полей (TV) с типом MIGX: т.е. мы выводим значения заполненные в одном ресурсе на других, с этим проблем нет и как это делать я уже рассказывал, вот например: Вывод TV поля MIGX одного ресурса на другом.

Например, конкретно данном случае при помощи Fenom можно вывести значения TV родителя можно так:

{set $rows = json_decode($_modx->resource.parent | resource : "name_tv", true)}
{foreach $rows as $row}
    и здесь весь код блока размеченный полями примерно вот так: {$row.title} {$row.znachenie} ...
{/foreach}

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

Постановка задачи

Ко мне обратились с задачей: расширить блок «Информация о товаре». Он сейчас заполняется в TV baseproduct (MIGX) на уровне категории. Нужно было добавить возможность дополнять/изменять отдельные значения на уровне карточки товара.

📄 Полный текст ТЗ: посмотреть / скачать PDF

Условия задачи

У нас есть TV baseproduct с конфигурацией MIGX, назначенный на родительские ресурсы (категории).

Пример конфигурации (фрагмент JSON):

{
  "formtabs":[
    {
      "fields":[
        {
          "field":"title",
          "caption":"Название"
        },
        {
          "field":"znachenie",
          "caption":"Значение"
        }
      ]
    }
  ],
  "columns":[
    {
      "header":"Название",
      "dataIndex":"title"
    },
    {
      "header":"Значение",
      "dataIndex":"znachenie"
    }
  ]
}

Категории уже заполнены — у каждой есть свои параметры.

Теперь мы создаём ещё одно TV (например, productparams) с типом MIGX с точно такой же конфигурацией полей и назначаем его для шаблона дочерних ресурсов.

Далее у нас есть 2 пути.

Решение «в лоб» (не совсем то, но похоже)

Первое, что приходит в голову: проверять TV на пустоту и подставлять либо свои значения, либо родительские.

Пример на Fenom:

{if $_modx->resource.productparams?}
	{set $rows = json_decode($_modx->resource.productparams, true)} 
    <div class="r_card__row">
        <div class="r_card__about-title">{$row.title}</div>
        <div class="r_card__about-value">{$row.znachenie}</div>
    </div>
	{/foreach}
{else}
	{set $rows = json_decode($_modx->resource.parent | resource : "baseproduct", true)}
    <div class="r_card__row">
        <div class="r_card__about-title">{$row.title}</div>
        <div class="r_card__about-value">{$row.znachenie}</div>
    </div>
	{/foreach}
{/if}

Что мы получаем:

  • Если у ресурса заполнено productparams → выводим его.
  • Если пусто → подставляем данные из baseproduct родителя.

Кому-то этого достаточно. Но по факту это неудобно: если нужно изменить всего одно значение, придётся переписать весь массив заново.

Решение с PHP и @EVAL

Правильнее подставлять значения родителя сразу в TV при редактировании ресурса. Тогда редактор увидит готовый список и изменит только нужное.

Для этого используем @EVAL.

Что такое @EVAL и зачем он нужен в MODX?

В MODX у TV есть полезная возможность — использовать префиксы для значений. Обычно мы встречаем такие как @INLINE, @FILE, @CHUNK, @RESOURCE и др. Они говорят MODX, откуда брать данные для TV.

@EVAL — один из таких префиксов, и он самый «гибкий». Его задача простая: выполнить PHP-код и вернуть результат. То есть всё, что вы напишете в @EVAL …, будет обработано PHP, а результат выполнения подставлен в TV.

Простейший пример:

@EVAL return date("Y-m-d");

Такое TV всегда будет содержать текущую дату.

Или чуть сложнее:

@EVAL return $modx->resource->get('pagetitle');

Здесь в TV автоматически подставится заголовок текущей страницы.

По сути, @EVAL превращает TV в «мини-скрипт», который каждый раз возвращает актуальное значение. Именно поэтому мы можем использовать его для динамического наследования данных из родителя: PHP-код берёт MIGX родителя, обрабатывает и подставляет готовый массив в дочерний ресурс.

⚠️ Важно: @EVAL — мощный, но опасный инструмент. Любая ошибка в коде может поломать вывод TV, а при неправильной работе — даже замедлить сайт. Поэтому:

  • всегда пишите аккуратный, проверенный код;
  • используйте только там, где реально нужна динамика.

В TV productparams, во вкладке Параметры ввода, в поле значение по умолчанию

Параметры ввода - значение по умолчанию

прописываем следующее:

@EVAL
global $modx;
$parentId = $modx->controller->resource->parent;
if (!$parentId) return '[]';

$category = $modx->getObject('modResource', $parentId);
if (!$category) return '[]';

$baseproductTV = $category->getTVValue('baseproduct');
if (empty($baseproductTV)) return '[]';

$data = $modx->fromJSON($baseproductTV);
$result = [];

if (is_array($data)) {
    foreach ($data as $item) {
        if (is_array($item) && !empty($item['title'])) {
            $value = '';
            if (!empty($item['znachenie'])) {
                $value = $item['znachenie'];
            } elseif (!empty($item['value'])) {
                $value = $item['value'];
            } elseif (!empty($item['default'])) {
                $value = $item['default'];
            }

            $result[] = [
                'title'     => $item['title'],
                'znachenie' => $value
            ];
        }
    }
}

return $modx->toJSON($result);

Ну и выводим это TV. Теперь в него автоматически подставляется массив с параметрами родителя. И при необходимости редактор может изменить отдельные значения — без копирования всего списка вручную.

Расширенный вариант

Более универсальное решение — с обработкой разных сценариев и определением parentId даже при создании ресурса:

@EVAL
global $modx;

$parentId = 0;
if (!empty($modx->controller) && !empty($modx->controller->resource)) {
    $parentId = (int)$modx->controller->resource->get('parent');
} elseif (!empty($modx->resource) && $modx->resource instanceof modResource) {
    $parentId = (int)$modx->resource->get('parent');
} elseif (!empty($_REQUEST['parent'])) {
    $parentId = (int)$_REQUEST['parent'];
}

if (!$parentId) return '[]';
$category = $modx->getObject('modResource', $parentId);
if (!$category) return '[]';

$baseproductTV = $category->getTVValue('baseproduct');
if (empty($baseproductTV)) return '[]';

$data = $modx->fromJSON($baseproductTV);
$result = [];

if (is_array($data)) {
    foreach ($data as $item) {
        if (is_string($item)) {
            $title = $item;
            $item = ['title' => $title];
        } elseif (is_array($item) && !empty($item['title'])) {
            $title = $item['title'];
        } else {
            continue;
        }

        $value = '';
        if (!empty($item['znachenie'])) {
            $value = $item['znachenie'];
        } elseif (!empty($item['value'])) {
            $value = $item['value'];
        } elseif (!empty($item['default'])) {
            $value = $item['default'];
        }

        $result[] = [
            'title'     => $title,
            'znachenie' => $value,
            'value'     => $value
        ];
    }
}

return $modx->toJSON($result);

Итог

Мы решили задачу так:

  • Родительская категория хранит полный набор параметров в MIGX.
  • При создании/редактировании дочернего ресурса TV автоматически заполняется значениями родителя.
  • Редактор меняет только то, что нужно.

✅ Экономия времени
✅ Минимум ошибок
✅ Гибкость

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

Заключение

Как видите, даже такие нетривиальные задачи в MODX, как наследование и автозаполнение MIGX TV, решаются довольно изящно — нужно лишь немного «поиграть» с Fenom и @EVAL. Это экономит время редакторам, снижает риск ошибок и делает работу с проектом более удобной.

Если у вас есть похожие задачи или вы хотите доработать сайт на MODX — пишите, помогу найти решение под ваш проект.

📩 Контакты для связи: [Telegram — @alex87ru]

Поделиться с друзьями
Алексей

Веб-дизайнер и SEO оптимизатор. Занимаюсь созданием сайтов с 2010 года и их продвижение с 2012 года!

Оцените автора
( 1 оценка, среднее 5 из 5 )
Web-Revenue.ru
Добавить комментарий