Przekaż dane do getChildHtml () lub metody wywołania w bloku potomnym

12

Chcę móc przekazywać dane do wywołania getChildHtml (). Powodem jest to, że wyjście bloku zależy od typu produktu. Więc chcę przekazać produkt do getChildHtml, aby mógł zdecydować o wyniku.

Robię to w środku template/checkout/cart/item/default.phtml.

Idealnie połączenie wyglądałoby tak:

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

Następnie mój blok może uzyskać typ produktu z elementu i wyświetlić prawidłowy wynik.

Ponieważ zdecydowanie nie jest możliwe przekazanie tych danych getChildHtml- w jaki sposób można osiągnąć tego rodzaju zachowanie bez konieczności przepisywania bloku podstawowego

Dwa obecnie dostępne rozwiązania są następujące (żadne bardzo atrakcyjne):

1 - Utwórz pomocnika i uzyskaj dostęp do wyjścia HTML za pomocą pomocnika, zamiast pozwolić blokowi i szablonowi renderować go jako ala $this->helper('my_module')->getItemHtml($_item);

2 - Uzyskaj dostęp do bloku potomnego i ustaw na nim dane w szablonie:

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

Myślę, że jeśli chodzi o architekturę Magento, numer 2 jest mniejszym z dwóch zła, ale cholernie brzydko wygląda w szablonie.

Marty Wallace
źródło
Czy możesz zamiast tego podać „dane” w rejestrze lub sesji, z których korzysta blok podrzędny? Czy używasz tego w iteratorze? Jaki jest przypadek użycia?
philwinkle
Nie sądzę, aby rejestr pomógłby tutaj, ponieważ pożądana wydajność zależy od rodzaju produktu koszyka. Musi to zostać w jakiś sposób przekazane do bloku, aby można było wyprowadzić prawidłowe dane. W przypadku użycia są wyświetlane dodatkowe informacje o elemencie koszyka, ale zależy to od rodzaju produktu
Marty Wallace
Możesz tworzyć atrybuty typu produktu - być może tworzysz różne atrybuty w zależności od typu produktu? Jeśli wolisz stworzyć własny blok, z pewnością możemy doradzić w tym kierunku, ale może być tu jeszcze inna wbudowana wygrana, którą próbuję powąchać ...
philwinkle
Cóż, jest to atrybut poziomu produktu, do którego mam dostęp, ale sposób jego wyświetlania zależy od typu produktu. Zgrupowany produkt będzie renderował ten sam atrybut nieco inaczej niż zwykły produkt. Używam bloku i szablonu dla każdego innego smaku produktu
Marty Wallace
Zaktualizowałem moje pytanie o kilka pomysłów, które rozważam, ale nie jestem w 100% z nimi zadowolony
Marty Wallace

Odpowiedzi:

3

Możesz dodać metodę do bloku nadrzędnego , aby pobrać dziecko w zależności od typu produktu (kilka razy widziałem taką logikę w rdzeniu lub coś podobnego):

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

Mimo to, widząc, jak modyfikujesz układ xml w celu dodania bloków potomnych, możesz być zainteresowany tym, jak Magento zdecydował się pracować z renderowaniem znaczników w zależności od typów produktów w Mage_Sales_Block_Items_Abstract::getItemHtml()i Mage_Checkout_Block_Cart_Abstract::getItemHtml().

nevvermind
źródło
Ta metoda omija strukturę układu i tworzy bloki, które są ściśle ze sobą powiązane (jak wszystko w Magento ...)
Victor Schröder
12

Powyższe rozwiązanie nie będzie działać, jeśli wyświetlasz blok potomny w foreachpętli.

W tym celu musisz użyć następującego kodu:

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

W child.block możesz użyć $this->getMyData()do uzyskania danych. Korzystając z tej strategii, blok potomny zawsze otrzyma najnowsze dane od rodzica.

Drugi parametr getChildHtml()to $useCache. Ustawienie wartości false uniemożliwia buforowanie pierwszego wyjścia i wymusza ponowne renderowanie dziecka.

Arvind07
źródło
4

Blok, który może odbierać dane, nazywa się widżetem ; chociaż można to zrobić za pomocą wielu definicji bloków (w oparciu o właściwości $_item).

Magento robi coś bardzo podobnego w rdzeniu, ładując blok metody płatności na podstawie krótkiego kodu metody:

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

Możesz zrobić to samo z tym pseudo-kodem:

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

Wszystko, co wymagałoby byłoby mieć inny typ bloku dla każdego rodzaju produktu - bundle, simple, configurable, virtual, grouped. Naprawdę nie tak źle.

Jeśli naprawdę chcesz użyć widżetu - byłby to efekt twojego drugiego pomysłu w edytowanym pytaniu:

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

Utworzenie widżetu prawdopodobnie poza zakresem tej odpowiedzi - ale nie jest to strasznie trudne i ma tę zaletę, że można go zmienić na bloki CMS, chociaż w twoim przypadku użycia nie sądzę, aby miało to zastosowanie.

Aby uzyskać więcej informacji na temat tworzenia widżetu:

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

philwinkle
źródło
Nie jestem w 100% przekonany, że jest to dobre podejście, na które nie przyjąłem odpowiedzi.
Marty Wallace
1
Tylko blok widżetów może odbierać dane? Co masz na myśli? Wszystkie bloki mogą odbierać dane. Widget jest coś innego pod względem Magento.
nevvermind
Nigdy nie powiedziałem, że nie mogą; Mówię z definicji, że widżet wymaga wprowadzania danych, aby wyświetlić coś warunkowo.
philwinkle
0

Dla Magento 2, można użyć

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

Aby uzyskać dane,

$block->getMyData();

Keyur Shah
źródło