Ausgabe eines Produktes in einem Template

Hallo,

ich würde gerne an einer bestimmten Stelle in meinem Twig Template ein Produkt (product card?) ausgeben. Die ID habe ich in einer Variable. Kurzer Denkanstoß oder wo ich mir das mal anschauen kann würde schon reichen :slight_smile:

Lg Alex

Keiner eine Ahnung? :frowning:

Ich pushe den Beitrag nochmal, in der Hoffnung auf Hilfe :frowning:

Ich weiß mittlerweile, dass ich über den Code-Schnipsel
{% sw_include '@Storefront/storefront/component/product/card/box.html.twig' with {'layout': boxLayout, 'displayMode': displayMode } %}

eine Product Card einfügen kann. Aber benötigt wird das Object „product“, das irgendwo befüllt wird. Gibt es so eine Funktion, die im Twig implementiert ist?

LG

Du brauchst einen Subscriber, dieser Subscriber muss die ID des Produktes kennen (z.B. via SystemConfigService). Und braucht den Service product.repository.

https://docs.shopware.com/en/shopware-platform-dev-en/how-to/register-subscriber

Je nachdem wo die Box hin soll musst du das Event kennen. HeaderPageletLoadedEvent wird z.B. auf jeder Storefront Seite geladen. CMS Elemente sind da etwas komplexer, da brauchst du einen CmsElementResolver.

Mit diesem Subscriber musst du eine ProductEntity erstellen und als Extension einem beliebigen Struct des Events hinzufügen… z.B. $event->getSalesChannelContext()->addExtension('meinProdukt', $productEntity) dann kann man das Produkt im Twig-Template vor dem include laden {% set product = context.extensions.meinProdukt %}

Viel Spaß :wink:

1 Like

Auweija :smiley: Danke für die ausführliche Erklärung, ich schaue mir das mal an.

Ich habe im Katalog bei den übergeordneten Menüpunkten ein Custom Field. Wenn dort eine Produkt-ID eingetragen ist, wird das Flyout Menü für diesen Menüpunkt nur 3-spaltig, statt 4-spaltig. Dafür soll in der 4. Spalte dann das jeweilige Produkt mit der angegeben ID ausgeben werden.

Das bedeutet, ich brauche das Event HeaderPageletLoadedEvent richtig?

Hallo Moorleiche,

ich bin diesbezüglich etwas weiter gekommen und habe mein erstes Plugin geschrieben.
Ich hole mir ein Produkt über das product.repostory via
$product = $this->productRepository->search(new Criteria([$productID]), $context)->first();

Anfangs hatte ich das Ganze zu Testzwecken an den HeaderPageletLoadedEvent subscribed. Das habe ich wieder entfernt, weil ich das ganze ja dann in meiner Klasse aufgerufen werden soll, die die Twig Extension erstellt.

Dazu habe ich eine Klasse mit AbstractExtension etweitert und meine Twig Extension registriert, die als Parameter sowohl eine Produkt-ID als auch context.context bekommt. Dort Instanziere ich dann meine Produktsuch-Klasse und gebe im Construktur sowohl $productRepository als auch meinen $context mit. Ich rufe die Methode auf, die mir das Produkt holt und gebe die Produkt ID mit.

Meine services.xml:

<?xml version="1.0" ?>
<container xmlns="http://symfony.com/schema/dic/services"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">
    <services>
        <service id="Bs\TwigGetProduct\Storefront\Pagelet\Header\Subscriber\AddTwigFunction">
            <tag name="twig.extension"/>
            <argument type="service" id="product.repository"/>
        </service>
    </services>
</container>

Das ganze funktioniert super. Er findet das Produkt und gibt es mir auch korrekt zurück.

{% set product1 %}
{{ getProductByID('2a88d9b59d474c7e869d8071649be43c', context.context) }}
{% endset %}

{{ dump(product1) }}

Das Ergebnis meines dumps, zeigt mir, was falsch läuft. Klassisch ist ja ein Produkt ein Objekt vom Typ SalesChannelProductEntity. Mein Objekt ist aber vom Typ ProductEntity. Wie kann ich statt einem ProductEntity ein SalesChannelProductEntity bekommen?

Danke für den Ansatz, hat mir weitergeholfen :slight_smile:

Lg Alex

Habs mittlerweile gelöst.

@AlexBS Ich stehe gerade vor dem selben Problem, habe ein ProductEntity, brauche aber ein SalesChannelProductEntity. Du schreibst du hast es gelöst, kannst du mir da vielleicht auch weiterhelfen? Danke schon mal

Ich habe in der services.xml einfach
<argument type="service" id="sales_channel.product.repository"/>
statt id=„product.repository“ übergeben.

Und dann in der Exension Klasse

/**
* @var SalesChannelRepositoryInterface
*/
 private $salesChannelProductRepository;  

/*
 *   Construct
*/
public function __construct(SalesChannelRepositoryInterface $salesChannelProductRepository)
{
    $this->salesChannelProductRepository = $salesChannelProductRepository
}

Hoffe ich kann dir damit helfen.

Lg Alex

Super, danke dir, ich habe vorher nur im Subscriber mir den SalesChannelContext geholt, leider ohne es auch schon in der services.xml zu ändern. Jetzt klappt es auch.
Ich wünsche noch einen sonnigen Tag :slightly_smiling_face:
Alex

Gerne. Wir Alexe müssen uns ja gegenseitig helfen! :slight_smile:
Lg Alex

Moin @AlexBS,

ich hoffe du hilfst mir, auch wenn ich kein Namensvetter von euch bin :wink:

Ich versuche gerade die selbe Twig Extension zu bauen. Das zweite Argument (context.context), dass ich neben der ID an „search“ übergebe, macht allerdings Probleme:

Argument 2 passed to Shopware\Core\System\SalesChannel\Entity\SalesChannelRepository::search() must be an instance of Shopware\Core\System\SalesChannel\SalesChannelContext, instance of Shopware\Core\Framework\Context given

Hier stehe ich auf dem Schlauch :frowning: Aktuell sieht meine Twig-Extension so aus:


declare(strict_types=1);

namespace Halabalusa\Twig;

use Twig\Extension\AbstractExtension;
use Twig\TwigFunction;
use Shopware\Core\System\SalesChannel\Entity\SalesChannelRepositoryInterface;
use Shopware\Core\Framework\DataAbstractionLayer\Search\Criteria;
use Shopware\Core\System\SalesChannel\SalesChannelContext;

class Productinfo extends AbstractExtension
{

  /**
   * @var SalesChannelRepositoryInterface
   */
  private $salesChannelProductRepository;

  /*
  *   Construct
  */
  public function __construct(SalesChannelRepositoryInterface $salesChannelProductRepository)
  {
    $this->salesChannelProductRepository = $salesChannelProductRepository;
  }

  public function getFunctions()
  {
    return [
      new TwigFunction('getProductByID', [$this, 'searchProductByID']),
    ];
  }

  public function searchProductByID($productID, $context)
  {
    return
      $this->salesChannelProductRepository->search(new Criteria([$productID]), $context)->first();;
  }
}

Muss ich noch etwas mit SalesChannelContext machen? Vielleicht hast du ja einen Hinweis für mich, das würde mir super helfen!

Danke und viele Grüße!

Hey,

versuchs mal mit „context“ statt „context.context“.

Lg
Alex

Hey @AlexBS , vielen Dank! Das hatte ich gerade schon getestet. Mit

{% set product1 %}
	{{ getProductByID('1403141fa6bc43428d5941a6caf50da6', context) }}

	{% endset %}

	{{ dump(product1) }}

gibt mir der dump aber

Twig\Markup {#10459 ▼
  -content: """
    \t
    
    \t
    """
  -charset: "UTF-8"
}

aus :thinking: Ich hab es doch richtig verstanden, dass kein Subscriber nötig ist, oder?

Viele Grüße!

Ok, hat sich erledigt. Mit

{{ dump(getProductByID('1403141fa6bc43428d5941a6caf50da6', context)) }}

bekomme ich das Produkt. Verstehe nicht, wieso das mit dem set nicht klappt, aber im Grunde egal, so komme ich weiter. Vielen Dank!

Hey,

das Problem hatte ich auch schon. Mit set kann man wohl nur Strings setzen.
Funktioniert es jetzt?

Lg

Ja, jetzt klappt alles. Ich bekomme meine Product Box angezeigt. Perfekt! Danke dir, ohne deine Posts hätte ich das nicht so schnell hinbekommen!

Freut mich dir geholfen zu haben.