<?php
declare(strict_types=1);
namespace BitBag\OpenMarketplace\Component\Elasticsearch\Controller;
use BitBag\OpenMarketplace\Component\Elasticsearch\Provider\RedirectResponseProviderInterface;
use BitBag\OpenMarketplace\Component\Organization\Checker\OrganizationStatusCheckerInterface;
use BitBag\OpenMarketplace\Component\Organization\Entity\OrganizationInterface;
use BitBag\OpenMarketplace\Component\Product\Entity\ProductInterface;
use BitBag\OpenMarketplace\Component\Taxonomy\Entity\TaxonInterface;
use BitBag\OpenMarketplace\Component\Vendor\Entity\VendorInterface;
use BitBag\SyliusElasticsearchPlugin\Controller\RequestDataHandler\DataHandlerInterface;
use BitBag\SyliusElasticsearchPlugin\Controller\RequestDataHandler\PaginationDataHandlerInterface;
use BitBag\SyliusElasticsearchPlugin\Controller\RequestDataHandler\SortDataHandlerInterface;
use BitBag\SyliusElasticsearchPlugin\Finder\ShopProductsFinderInterface;
use BitBag\SyliusElasticsearchPlugin\Form\Type\ShopProductsFilterType;
use Symfony\Component\Form\FormError;
use Symfony\Component\Form\FormFactoryInterface;
use Symfony\Component\Form\FormInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Twig\Environment;
final class ListProductsAction
{
private static iterable $currentPageProducts;
private static TaxonInterface $taxon;
public function __construct(
private FormFactoryInterface $formFactory,
private DataHandlerInterface $shopProductListDataHandler,
private SortDataHandlerInterface $shopProductsSortDataHandler,
private PaginationDataHandlerInterface $paginationDataHandler,
private ShopProductsFinderInterface $shopProductsFinder,
private Environment $twig,
private RedirectResponseProviderInterface $redirectResponseProvider,
private OrganizationStatusCheckerInterface $organizationStatusChecker,
) {
}
public function __invoke(Request $request): Response
{
$redirectResponse = $this->redirectResponseProvider->provide($request, [
'slug' => $request->get('slug'),
]);
if (null !== $redirectResponse) {
return $redirectResponse;
}
$form = $this->formFactory->create(ShopProductsFilterType::class);
$form->handleRequest($request);
$requestData = array_merge(
$form->getData(),
$request->query->all(),
['slug' => $request->get('slug')]
);
if (!$form->isValid()) {
$requestData = $this->clearInvalidEntries($form, $requestData);
}
$data = array_merge(
$this->shopProductListDataHandler->retrieveData($requestData),
$this->shopProductsSortDataHandler->retrieveData($requestData),
$this->paginationDataHandler->retrieveData($requestData)
);
$template = $request->get('template');
$products = $this->shopProductsFinder->find($data);
self::$currentPageProducts = $this->normalizeCurrentPageProducts($products->getCurrentPageResults());
$this->organizationStatusChecker->preload($this->extractOrganizations(self::$currentPageProducts));
self::$taxon = $data['taxon'];
return new Response($this->twig->render($template, [
'form' => $form->createView(),
'products' => $products,
'taxon' => $data['taxon'],
]));
}
private function clearInvalidEntries(FormInterface $form, array $requestData): array
{
foreach ($form->getErrors(true) as $error) {
if (!$error instanceof FormError) {
continue;
}
$errorOrigin = $error->getOrigin();
if (null === $errorOrigin) {
continue;
}
$parent = $errorOrigin->getParent();
if (null === $parent) {
continue;
}
$path = ($parent->getPropertyPath() ?? '') . $errorOrigin->getPropertyPath();
$keys = explode('][', trim($path, '[]'));
$dataRef = &$requestData;
foreach ($keys as $index => $key) {
if (isset($dataRef[$key])) {
if ($index === count($keys) - 1) {
unset($dataRef[$key]);
} else {
$dataRef = &$dataRef[$key];
}
}
}
}
return $requestData;
}
public static function getCurrentPageProducts(): iterable
{
return self::$currentPageProducts;
}
public static function getTaxon(): TaxonInterface
{
return self::$taxon;
}
private function normalizeCurrentPageProducts(iterable $products): array
{
if (is_array($products)) {
return $products;
}
return iterator_to_array($products, false);
}
private function extractOrganizations(array $products): array
{
$organizations = [];
foreach ($products as $product) {
if (!$product instanceof ProductInterface) {
continue;
}
$vendor = $product->getVendor();
if (!$vendor instanceof VendorInterface) {
continue;
}
$organization = $vendor->getOrganization();
if (!$organization instanceof OrganizationInterface) {
continue;
}
$organizationId = $organization->getId();
$cacheKey = null !== $organizationId ? (string) $organizationId : (string) spl_object_id($organization);
$organizations[$cacheKey] = $organization;
}
return array_values($organizations);
}
}