Product Listing auf Startseite

Hi, wir haben ein CMS Element erstellt, das einen Filter und ein Produkt Grid beinhaltet (aufgebaut wie bei einer Product Listing Page).

Für dieses Element haben wir einen Resolver erstellt, der über Dependency Injection Zugriff auf folgende Services hat:

<argument type="service" id="property_group_option.repository" />
<argument type="service" id="sales_channel.product.repository" />

Über die enrich function vom Element Resolver haben wir die korrekten Produkte sowie Properties geladen und dem Filter im Template als „listing“ übergeben.

public function enrich(CmsSlotEntity $slot, ResolverContext $resolverContext, ElementDataCollection $result): void
    {
        $data = new HomeConfiguratorStruct();

        $criteria = new Criteria();
        $criteria->setLimit(6);
        $criteria->addAssociation('cover');
        $criteria->addAssociation('options');
        $criteria->addAssociation('properties');

        $criteria->addAggregation(
            new FilterAggregation(
                'properties',
                new EntityAggregation('properties', 'properties.groupId', 'property_group'),
                [
                    new EqualsFilter('properties.group.visibleOnProductDetailPage', true)
                ]
            )
        );

        $criteria->addAggregation(
            new EntityAggregation('options', 'properties.groupId', 'property_group_option')
        );

        // Only show parent products
        $criteria->addFilter(
            new EqualsFilter('product.parentId', null)
        );

        $result = $this->_salesChannelProductRepository->search(
            $criteria,
            $resolverContext->getSalesChannelContext()
        );

        $result->getAggregations()->getElements();

        $data->listing = $result;

        $slot->setData($data);
    }

Grundsätzlich funktioniert das Product Listing und auch die Properties werden korrekt geladen. Leider fehlen die options bei den properties, die der Filter jedoch braucht. Wir haben etwas mit den associations und aggregations herumgespielt, wirklich erfolgreich wurden wir hier jedoch nicht.

Wir konnten mit „nested aggregations“ zwar erreichen, dass die Properties auch die Options beinhalten, jedoch scheint das auch nur mit TermsAggregations zu funktionieren.

Meine Frage daher: Gibt es eine Möglichkeit EntityAggregations zu verschachteln, bzw. gibt es eine Möglichkeit die Buckets aus dem Result einer nested TermsAggregation in Entities umzuwandeln?

Oder sind wir bei dem Problem gar komplett am falschen Weg?

Im Shopware Core haben wir die Datei ProductListingFeaturesSubscriber.php gefunden, die in der function „groupOptionAggregations“ womöglich das Problem lösen könnte, jedoch kommt uns das ziemlich extrem vor, nur um options von properties bei einer Anfrage mitzuladen.

LG und Danke für jede Hilfe im voraus!

Moin hänge am selben Problem… Habt ihr eine lösung gefunden…

Grüße!

Hat eine Zeit lang gedauert und haben einiges versucht. Mit Folgendem hat’s zumindest bei uns funktioniert.

Wir haben zum einen, die Definition in der services.xml angepasst:

<tag name="shopware.cms.data_resolver"></tag>
<argument type="service" id="property_group.repository" />
<argument type="service" id="property_group_option.repository" />
<argument type="service" id="sales_channel.product.repository" />
<argument type="service" id="category.repository" />
<argument type="service" id="cms_page.repository" />
<argument type="service" id="Shopware\Core\Content\Product\SalesChannel\Listing\ProductListingRoute" />

Und zum anderen noch etwas am Resolver selbst:

		$data = new HomeConfiguratorStruct();
		$request = $resolverContext->getRequest();
		$context = $resolverContext->getSalesChannelContext();

		$criteria = new Criteria();
		$criteria->setTotalCountMode(Criteria::TOTAL_COUNT_MODE_NEXT_PAGES);
		$criteria->addAssociation('options.group');
		$criteria->addAssociation('properties');

		$criteria->addAggregation(
			new FilterAggregation(
				'properties',
				new EntityAggregation('properties', 'properties.groupId', 'property_group'),
				[
					new EqualsFilter('properties.group.visibleOnProductDetailPage', true)
				]
			)
		);

		$navigationId = $this->getNavigationId($request, $context);

		$listing = $this->listingRoute
			->load($navigationId, $request, $context, $criteria)
			->getResult();

		$data->listing = $listing;

		$data->properties = $this->_getProperties($resolverContext->getSalesChannelContext()->getContext());
    ...
	private function _getProperties(Context $context): EntitySearchResult
	{
		// Fetch all properties
		$propertyCriteria = new Criteria();
		$propertyCriteria->addFilter(new EqualsFilter('filterable', true));
		$propertyCriteria->addAssociation('options');
		$propertyCriteria->addAssociation('options.group');

		$properties = $this->_propertyRepository->search($propertyCriteria, $context);

		$entities = $properties->getEntities();
		$keys = array_keys($entities->getElements());

		foreach ($entities as $key => $property) {
			//
		}

		return $properties;
	}

Vielleicht hilfts

Hey moin,

sieht bei uns alles etwas anders aus.
Hole mir hier das listing rein


        $propertyId = "018b15cc386772fbae58e587d97399e6"; 
        $criteria = (new Criteria())->addAssociations(['properties.group', 'options.group']);
  
        $criteria->addFilter(new EqualsFilter('product.active', true));
        $criteria->addFilter(new EqualsFilter('product.properties.id', $propertyId));  
        $criteria->setLimit(5);

und hier ab zu twig

     $products = $this->productListingLoader->load($criteria, $context);
        return $this->renderStorefront('@DdpBrandProducts/storefront/page/example.html.twig', [
            'products' => $products
        ]);
    }

Funktionert wie bei dir auch ohne probleme.

    $criteria->addAssociation('options');
     $criteria->addAssociation('options.group');
     $criteria->addAggregation(
        new FilterAggregation(
            'properties',
            new EntityAggregation('properties', 'properties.groupId', 'property_group'),
            [
                
            ]
        )
    );

Wenn ich das so abgeänderlasse wie bei dir ploppen im listing die leeren filter auf. genau wie bei dir und die Options sind nicht gefüllt…

Hmm,

War doch schon ne Zeit lang her.

Haben aber sehr viel mit den Associations bei den Criterias sowie in der services.xml herumprobiert.
Aber glaub am Ende hat’s durch die _getProperties Function funktioniert, indem wir separat die Options aus dem Property-Repository gezogen haben.

	private function _getProperties(Context $context): EntitySearchResult
	{
		// Fetch all properties
		$propertyCriteria = new Criteria();
		$propertyCriteria->addFilter(new EqualsFilter('filterable', true));
		$propertyCriteria->addAssociation('options');
		$propertyCriteria->addAssociation('options.group');

		$properties = $this->_propertyRepository->search($propertyCriteria, $context);

		$entities = $properties->getEntities();
		$keys = array_keys($entities->getElements());

		foreach ($entities as $key => $property) {
		}

		return $properties;
	}

Ich hab jetzt die Option gesammelt


	$criteria->addAggregation(
			new FilterAggregation(
				'properties',
				new EntityAggregation('properties', 'properties.groupId', 'property_group'),
				[
				
				]
			)
		);

        
        $criteria->addAggregation(      <- da sind die jetzt drin
           new EntityAggregation('option', 'properties.id', 'property_group_option'),
        );

Nur wie bekomme ich die jetzt zusammen…