Передать данные в getChildHtml () или вызвать метод для дочернего блока

12

Я хочу иметь возможность передавать данные в вызов getChildHtml (). Причина в том, что выход блока зависит от типа продукта. Поэтому я хочу передать продукт в getChildHtml, чтобы он мог принять решение о выводе.

Я делаю это внутри template/checkout/cart/item/default.phtml.

В идеале звонок должен выглядеть так:

echo $this->getChildHtml('child_block_name', $_item);

Тогда мой блок может получить тип продукта из элемента и отобразить правильный вывод.

Поскольку это определенно невозможно передать эти данные getChildHtml- как еще можно добиться такого поведения без необходимости переписывать основной блок

В настоящее время у меня есть два решения (ни одно из них не очень привлекательное):

1 - Создайте помощник и получите доступ к выводу html через помощника вместо того, чтобы позволить блоку и шаблону визуализировать его $this->helper('my_module')->getItemHtml($_item);

2 - Доступ к дочернему блоку и setData для него внутри шаблона:

 $this->getChild('child_name')->setData('item', $_item);
 echo $this->getChildHtml('child_name')

Я думаю, что с точки зрения архитектуры Magento, число 2 - меньшее из двух зол, но чертовски уродливо смотрит в шаблон.

Марти Уоллес
источник
Можете ли вы вместо этого предоставить «данные» в реестре или сеансе, которые использует дочерний блок? Вы используете это в итераторе? Какой вариант использования?
Philwinkle
Я не думаю, что здесь поможет реестр, так как желаемый результат зависит от типа продукта в корзине. Так что это должно быть передано в блок каким-то образом, чтобы можно было выводить правильные данные. В сценарии использования отображается дополнительная информация о товаре, но это зависит от типа продукта
Марти Уоллес
Вы можете создавать атрибуты типа продукта - возможно, вы создаете различные атрибуты на основе типов продукта? Если вы предпочитаете создать свой собственный блок, мы, безусловно, можем посоветовать в этом направлении, но здесь может быть какая-то другая встроенная победа, которую я пытаюсь выявить ...
philwinkle
Это атрибут уровня продукта, к которому я обращаюсь, но способ его отображения зависит от типа продукта. Сгруппированный продукт будет отображать один и тот же атрибут немного иначе, чем простой продукт. Я использую блок и шаблон для каждого вида выходных данных
Марти Уоллес
Я обновил свой вопрос некоторыми идеями, которые у меня есть, которые я обдумываю, но не на 100% доволен
Марти Уоллес

Ответы:

3

Вы можете добавить метод в родительский блок для извлечения дочернего элемента в зависимости от типа продукта (я видел такую ​​логику пару раз в ядре или что-то подобное):

class ParentBlock 
{
    public function getIntuitiveNameChild($item)
    {
        return $this->getChild("intuitive_child")
                    ->setProductType($item->getProductType()) 
                    // You can also decide the product type in this setter, in the Child block.
                    ->setItem($item);
    }

    public function getIntuitiveNameChildDinamically($item)
    {
        return $this->getChild("intuitive_child_" . $item->getProductType())
                    ->setItem($item); 
    }    
}

// parent tpl
// i suggest you avoid getChildHtml(), unless you're certain that methods won't need to be called from the tpl
echo $this->getIntuitiveNameChild($_item)
          // ->someOtherMethod()
          ->toHtml();

Тем не менее, видя, как вы изменяете макет XML для добавления дочерних блоков, вас может заинтересовать то, как Magento решила работать с разметкой рендеринга в зависимости от типов продуктов в Mage_Sales_Block_Items_Abstract::getItemHtml()и Mage_Checkout_Block_Cart_Abstract::getItemHtml().

nevvermind
источник
Этот метод обходит структуру макета и создает блоки, которые тесно связаны (как и все в Magento ...)
Виктор Шредер,
12

Приведенное выше решение не будет работать, если вы отображаете дочерний блок в foreachцикле.

Для этого вам нужно использовать следующий код:

<?php
foreach ($blocks as $block) {
    $this->getChild("child.block")->setData("my_data", $any_data);
    echo $this->getChildHtml('child.block', false);
}
?>

В child.block вы можете использовать $this->getMyData()для получения данных. Используя эту стратегию, дочерний блок всегда будет получать последние данные от родителя.

Вторым параметром getChildHtml()является $useCache. Установка его в false предотвращает кэширование первого вывода и вынуждает рендеринг снова.

Arvind07
источник
4

Блок, который может принимать данные, называется виджетом ; хотя это можно сделать с помощью нескольких определений блоков (в зависимости от свойств $_item).

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

<dd>
    <?php echo $this->getChildHtml('payment.method.'.$_code) ?>
</dd>

Вы можете сделать то же самое с этим псевдокодом:

if($type = $_item->getTypeId()){
    $this->getChildHtml('my.block.' . $type);
}

Все , что потребуется бы иметь другой тип блока для каждого типа продукта - bundle, simple, configurable, virtual, grouped. Не так уж и плохо.

Если вы действительно хотите использовать виджет - это будет эффектом вашей второй идеи в отредактированном вопросе:

<?php
echo $this->getLayout()->createBlock('yourcompany/widget_class')->setType($_item->getTypeId())->toHtml();

Создание виджета, вероятно, выходит за рамки этого ответа - но это не очень сложно, и имеет преимущество, заключающееся в возможности переназначения для блоков CMS, хотя для вашего случая использования я не думаю, что это применимо.

Для получения дополнительной информации о создании виджета:

http://www.magentocommerce.com/knowledge-base/entry/tutorial-creating-a-magento-widget-part-1

philwinkle
источник
Я не уверен на 100%, что это хороший подход, и я не принял ответ.
Марти Уоллес
1
Только блок виджетов может получать данные? Что вы имеете в виду? Все блоки могут получать данные. Виджет это нечто иное , с точки зрения Magento.
nevvermind
Я никогда не говорил, что они не могут; Я говорю, по определению, виджет требует ввода данных, чтобы отобразить что-то условно.
Philwinkle
0

Для Magento 2, вы можете использовать

<?php
foreach ($blocks as $block) {
    $block->getChildBlock("child.block")->setData("my_data", $any_data);
    echo $block->getChildHtml('child.block', false);
}
?>

Чтобы получить данные,

$block->getMyData();

Кейур Шах
источник