- <?php declare(strict_types=1);
- namespace Shopware\Core\Content\Seo\SalesChannel;
- use Shopware\Core\Content\Category\CategoryEntity;
- use Shopware\Core\Content\Product\SalesChannel\SalesChannelProductEntity;
- use Shopware\Core\Content\Seo\SeoUrl\SeoUrlCollection;
- use Shopware\Core\Content\Seo\SeoUrl\SeoUrlEntity;
- use Shopware\Core\Content\Seo\SeoUrlRoute\SeoUrlRouteInterface as SeoUrlRouteConfigRoute;
- use Shopware\Core\Content\Seo\SeoUrlRoute\SeoUrlRouteRegistry;
- use Shopware\Core\Framework\DataAbstractionLayer\DefinitionInstanceRegistry;
- use Shopware\Core\Framework\DataAbstractionLayer\Entity;
- use Shopware\Core\Framework\DataAbstractionLayer\Search\AggregationResult\AggregationResultCollection;
- use Shopware\Core\Framework\DataAbstractionLayer\Search\Criteria;
- use Shopware\Core\Framework\DataAbstractionLayer\Search\EntitySearchResult;
- use Shopware\Core\Framework\DataAbstractionLayer\Search\Filter\EqualsAnyFilter;
- use Shopware\Core\Framework\DataAbstractionLayer\Search\Filter\EqualsFilter;
- use Shopware\Core\Framework\DataAbstractionLayer\Search\Sorting\FieldSorting;
- use Shopware\Core\Framework\Struct\Collection;
- use Shopware\Core\Framework\Struct\Struct;
- use Shopware\Core\PlatformRequest;
- use Shopware\Core\System\SalesChannel\Entity\SalesChannelDefinitionInstanceRegistry;
- use Shopware\Core\System\SalesChannel\Entity\SalesChannelRepositoryInterface;
- use Shopware\Core\System\SalesChannel\SalesChannelContext;
- use Shopware\Core\System\SalesChannel\StoreApiResponse;
- use Symfony\Component\EventDispatcher\EventSubscriberInterface;
- use Symfony\Component\HttpKernel\Event\ResponseEvent;
- use Symfony\Component\HttpKernel\KernelEvents;
- class StoreApiSeoResolver implements EventSubscriberInterface
- {
-     /**
-      * @var SalesChannelRepositoryInterface
-      */
-     private $salesChannelRepository;
-     /**
-      * @var DefinitionInstanceRegistry
-      */
-     private $definitionInstanceRegistry;
-     /**
-      * @var SeoUrlRouteRegistry
-      */
-     private $seoUrlRouteRegistry;
-     /**
-      * @var SalesChannelDefinitionInstanceRegistry
-      */
-     private $salesChannelDefinitionInstanceRegistry;
-     /**
-      * @internal
-      */
-     public function __construct(
-         SalesChannelRepositoryInterface $salesChannelRepository,
-         DefinitionInstanceRegistry $definitionInstanceRegistry,
-         SalesChannelDefinitionInstanceRegistry $salesChannelDefinitionInstanceRegistry,
-         SeoUrlRouteRegistry $seoUrlRouteRegistry
-     ) {
-         $this->salesChannelRepository = $salesChannelRepository;
-         $this->definitionInstanceRegistry = $definitionInstanceRegistry;
-         $this->seoUrlRouteRegistry = $seoUrlRouteRegistry;
-         $this->salesChannelDefinitionInstanceRegistry = $salesChannelDefinitionInstanceRegistry;
-     }
-     public static function getSubscribedEvents(): array
-     {
-         return [
-             KernelEvents::RESPONSE => ['addSeoInformation', 10000],
-         ];
-     }
-     public function addSeoInformation(ResponseEvent $event): void
-     {
-         $response = $event->getResponse();
-         if (!$response instanceof StoreApiResponse) {
-             return;
-         }
-         if (!$event->getRequest()->headers->has(PlatformRequest::HEADER_INCLUDE_SEO_URLS)) {
-             return;
-         }
-         $dataBag = new SeoResolverData();
-         $this->find($dataBag, $response->getObject());
-         $this->enrich($dataBag, $event->getRequest()->attributes->get(PlatformRequest::ATTRIBUTE_SALES_CHANNEL_CONTEXT_OBJECT));
-     }
-     private function find(SeoResolverData $data, Struct $struct): void
-     {
-         if ($struct instanceof AggregationResultCollection) {
-             foreach ($struct as $item) {
-                 $this->findStruct($data, $item);
-             }
-         }
-         if ($struct instanceof EntitySearchResult) {
-             foreach ($struct->getEntities() as $entity) {
-                 $this->findStruct($data, $entity);
-             }
-         }
-         if ($struct instanceof Collection) {
-             foreach ($struct as $item) {
-                 $this->findStruct($data, $item);
-             }
-         }
-         $this->findStruct($data, $struct);
-     }
-     private function findStruct(SeoResolverData $data, Struct $struct): void
-     {
-         if ($struct instanceof Entity) {
-             $definition = $this->definitionInstanceRegistry->getByEntityClass($struct) ?? $this->salesChannelDefinitionInstanceRegistry->getByEntityClass($struct);
-             if ($definition && $definition->isSeoAware()) {
-                 $data->add($definition->getEntityName(), $struct);
-             }
-         }
-         foreach ($struct->getVars() as $item) {
-             if ($item instanceof Collection) {
-                 foreach ($item as $collectionItem) {
-                     if ($collectionItem instanceof Struct) {
-                         $this->findStruct($data, $collectionItem);
-                     }
-                 }
-             } elseif ($item instanceof Struct) {
-                 $this->findStruct($data, $item);
-             }
-         }
-     }
-     private function enrich(SeoResolverData $data, SalesChannelContext $context): void
-     {
-         foreach ($data->getEntities() as $definition) {
-             $ids = $data->getIds($definition);
-             $routes = $this->seoUrlRouteRegistry->findByDefinition($definition);
-             if (\count($routes) === 0) {
-                 continue;
-             }
-             $routes = array_map(static function (SeoUrlRouteConfigRoute $seoUrlRoute) {
-                 return $seoUrlRoute->getConfig()->getRouteName();
-             }, $routes);
-             $criteria = new Criteria();
-             $criteria->addFilter(new EqualsFilter('isCanonical', true));
-             $criteria->addFilter(new EqualsAnyFilter('routeName', $routes));
-             $criteria->addFilter(new EqualsAnyFilter('foreignKey', $ids));
-             $criteria->addFilter(new EqualsFilter('languageId', $context->getContext()->getLanguageId()));
-             $criteria->addSorting(new FieldSorting('salesChannelId'));
-             /** @var SeoUrlEntity $url */
-             foreach ($this->salesChannelRepository->search($criteria, $context) as $url) {
-                 /** @var SalesChannelProductEntity|CategoryEntity $entity */
-                 $entity = $data->get($definition, $url->getForeignKey());
-                 if ($entity->getSeoUrls() === null) {
-                     $entity->setSeoUrls(new SeoUrlCollection());
-                 }
-                 $entity->getSeoUrls()->add($url);
-             }
-         }
-     }
- }
-