Passe dados para getChildHtml () ou chame o método no bloco filho

12

Quero poder passar dados para a chamada getChildHtml (). O motivo é que a saída do bloco depende de um tipo de produto. Então, eu quero passar o produto para o getChildHtml para que ele possa decidir sobre a saída.

Estou fazendo isso por dentro template/checkout/cart/item/default.phtml .

Idealmente, a chamada teria a seguinte aparência:

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

Então meu bloco pode obter o tipo de produto do item e exibir a saída correta.

Como definitivamente não é possível passar esses dados para getChildHtml - de que outra forma esse tipo de comportamento pode ser alcançado sem precisar reescrever o bloco principal

As duas soluções que tenho atualmente são as seguintes (nem muito atraentes):

1 - Crie um auxiliar e acesse a saída html através do auxiliar, em vez de deixar um bloco e um modelo renderizá-lo $this->helper('my_module')->getItemHtml($_item);

2 - Acesse o bloco filho e setData nele dentro do modelo:

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

Penso que, em termos de arquitetura Magento, o número 2 é o menor dos dois males, mas é muito feio olhando dentro de um modelo.

Marty Wallace
fonte
Em vez disso, você pode fornecer os 'dados' no registro ou na sessão que o bloco filho faz uso? Você está usando isso em um iterador? Qual é o caso de uso?
22613 philwinkle
Eu não acho que o registro ajudaria aqui, pois a saída desejada depende de um tipo de produto de itens de carrinho. Portanto, isso deve ser passado para o bloco de alguma forma, para que os dados corretos possam ser gerados. O caso de uso é mostrar alguma informação extra sobre o item carrinho, mas isso depende do tipo de produto
Marty Wallace
Você pode criar atributos do tipo de produto - talvez você crie atributos diferentes com base nos tipos de produto? Se você preferir criar seu próprio bloco certamente podemos aconselhar nesse sentido, mas pode haver alguma outra embutida vitória aqui que eu estou tentando farejar ...
philwinkle
Bem, é um atributo no nível do produto que estou acessando, mas a maneira como é exibida depende do tipo de produto. Um produto agrupado renderizará o mesmo atributo de maneira ligeiramente diferente do que um produto simples. Eu estou usando um bloco e modelo para cada sabor diferente de saída
Marty Wallace
Eu atualizei a minha pergunta com algumas idéias que tenho que eu estou pensando, mas não estou 100% confortável com
Marty Wallace

Respostas:

3

Você pode adicionar um método no bloco pai para buscar o filho, dependendo do tipo de produto (eu já vi esse tipo de lógica algumas vezes no núcleo ou algo semelhante):

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();

Ainda assim, vendo como você modifica o xml do layout para adicionar blocos filhos, você pode estar interessado em saber como o Magento decidiu trabalhar com a marcação de renderização, dependendo dos tipos de produto em Mage_Sales_Block_Items_Abstract::getItemHtml()e Mage_Checkout_Block_Cart_Abstract::getItemHtml().

nevvermind
fonte
Este método ignora a estrutura de layout e produz blocos que são fortemente acoplados (como tudo na Magento ...)
Victor Schröder
12

A solução acima não funcionará se você estiver exibindo um bloqueio filho no foreach loop.

Para isso, você precisa usar o seguinte código:

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

Em child.block você pode usar $this->getMyData() para obter os dados. Usando essa estratégia, o bloco filho sempre obterá os dados mais recentes dos pais.

O segundo parâmetro de getChildHtml()é $useCache. A configuração para false impede que a primeira saída seja armazenada em cache e força a renderização do filho novamente.

Arvind07
fonte
4

Um bloco que pode receber dados é chamado de widget ; embora isso possa ser feito através de várias definições de bloco (com base nas propriedades de $_item).

O Magento faz algo muito semelhante no núcleo, carregando o bloco da forma de pagamento com base no código curto do método:

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

Você poderia fazer o mesmo com este pseudocódigo:

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

Tudo o que exigiria seria ter um tipo de bloco diferente para cada tipo de produto - bundle, simple, configurable, virtual, grouped. Não é tão ruim, realmente.

Se você realmente deseja usar um widget - isso seria algo que afetaria sua segunda ideia na sua pergunta editada:

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

Criar um widget provavelmente fora do escopo desta resposta - mas não é muito difícil e tem a vantagem de poder ser redirecionado para blocos CMS, embora, para o seu caso de uso, eu não considere aplicável.

Para mais informações sobre como criar um widget:

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

philwinkle
fonte
Não estou 100% convencido de que essa seja uma boa abordagem, que não aceitei a resposta.
Marty Wallace 16/05
1
Apenas um bloco de widget pode receber dados? O que você quer dizer? Todos os blocos podem receber dados. Um widget é algo diferente em termos do Magento.
Nevevind #
Eu nunca disse que eles não podiam; Estou dizendo, por definição, que um widget requer entrada de dados para exibir algo condicionalmente.
Philwinkle
0

Para Magento 2, você pode usar

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

Para obter os dados,

$block->getMyData();

Keyur Shah
fonte