<?php
declare(strict_types=1);
namespace Expert\ExpertProductFinder\Storefront\Controller;
use GuzzleHttp\Client;
use Shopware\Core\Framework\Context;
use Shopware\Core\Framework\DataAbstractionLayer\Search\Criteria;
use Shopware\Core\Framework\DataAbstractionLayer\Search\Filter\EqualsAnyFilter;
use Shopware\Core\Framework\DataAbstractionLayer\Search\Filter\EqualsFilter;
use Shopware\Core\System\SalesChannel\SalesChannelContext;
use Shopware\Storefront\Controller\StorefrontController;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\Routing\Annotation\Route;
use Shopware\Core\Framework\Routing\Annotation\RouteScope;
use Shopware\Storefront\Page\GenericPageLoader;
use Shopware\Storefront\Framework\Cache\Annotation\HttpCache;
use Shopware\Core\Content\Product\ProductEntity;
use Shopware\Core\Content\Property\PropertyGroupCollection;
use Shopware\Core\Content\Property\Aggregate\PropertyGroupOption\PropertyGroupOptionCollection;
/**
* @RouteScope(scopes={"storefront"})
*/
class ExpertSearchController extends StorefrontController
{
/**
* @var Client
*/
private $client;
/**
* @var GenericPageLoader
*/
private $genericPageLoader;
/**
* MultiSearchByManufaturer constructor.
*
* @param GenericPageLoader $genericPageLoader
*/
public function __construct(GenericPageLoader $genericPageLoader)
{
$this->client = new Client();
$this->genericPageLoader = $genericPageLoader;
}
/**
* @TODO: @HttpCache() // => activates Route caching for this route
* @Route("/expert/suche", name="frontend.expert.search", options={"seo"="false"}, methods={"GET"})
*/
public function searchByManufacturer(Request $request, SalesChannelContext $context): Response
{
$page = $this->genericPageLoader->load($request, $context);
if ($request->query->has('searchterm')) {
$searchTerms = $request->query->get('searchterm');
} else {
$manufacturerName = $request->query->get('Hersteller');
$modelName = $request->query->get('Modell');
$typeName = $request->query->get('Typ');
$typeSearchTerms = $this->generateSearchTerms($manufacturerName, $modelName, $typeName);
$carDetails = $this->getCarDetails($typeSearchTerms[0]);
$searchTerms = $typeSearchTerms[1];
}
if (!is_null($searchTerms)) {
$explodedSearchTerms = explode('|', $searchTerms);
$productRepo = $this->container->get('product.repository');
$criteria = new Criteria();
$criteria->addFilter(new EqualsFilter('product.active', true));
$criteria->addFilter(new EqualsAnyFilter('product.manufacturerNumber', $explodedSearchTerms));
$criteria->addAssociation('manufacturer');
$criteria->addAssociation('seoUrls'); // $criteria->addAssociation('prices'); TODO: relevant for display price ranges
$criteria->addAssociation('price');
$criteria->addAssociation('media');
$criteria->addAssociation('cover');
$criteria->addAssociation('properties.group');
$criteria->addAssociation('deliveryTime');
$result = $productRepo->search($criteria, $context->getContext())->getEntities(); //SS-288 sortProperties for ProductEntity
foreach ($result as $product) {
if (($properties = $product->get('properties')) !== null && $properties instanceof PropertyGroupOptionCollection) {
$sortedProperties = $this->sortProperties($product);
$product->addExtension('sortedProperties', $sortedProperties);
}
}
$storefrontVariable = [
'page' => $page,
'resultData' => $result->getElements(),
'search' => $searchTerms,
];
if (isset($carDetails)) {
$storefrontVariable = [
'page' => $page,
'resultData' => $result->getElements(),
'search' => $searchTerms,
"carDetails" => $carDetails,
];
}
return $this->renderStorefront(
'@ExpertProductFinder/storefront/expert_search/expert-search-page.html.twig',
$storefrontVariable
);
}
return $this->renderStorefront(
'@ExpertProductFinder/storefront/expert_search/expert-search-page.html.twig',
[
'page' => $page,
'resultData' => null,
'search' => $searchTerms
]
);
}
/**
* @Route("/expert/get-makes", defaults={"_format"="xml"}, name="frontend.expert.getmakes", options={"seo"="false"}, methods={"GET"})
*/
public function getMakes(Request $request)
{
$allowReq = $request->get('makes');
$baseUrl = 'https://akkusysws.aldoc.eu';
$makesUrl = '/MMT/mmt.asmx/GetMakes?filter=0&message=""';
$url = $baseUrl . $makesUrl;
if ($allowReq === 'makes') {
$contents = $this->client->get($url)->getBody()->getContents();
return new Response($contents);
} else {
return new Response('No access allowed!');
}
}
/**
* @Route("/expert/get-models", defaults={"_format"="xml"}, name="frontend.expert.getmodels", options={"seo"="false"}, methods={"GET"})
*/
public function getModels(Request $request)
{
$modelsCode = $request->get('model');
$baseUrl = 'https://akkusysws.aldoc.eu';
$modelsUrl = '/MMT/mmt.asmx/GetModels?makecode=' . $modelsCode . '&message=""';
$url = $baseUrl . $modelsUrl;
$contents = $this->client->get($url)->getBody()->getContents();
return new Response($contents);
}
/**
* @Route("/expert/get-types", defaults={"_format"="xml"}, name="frontend.expert.gettypes", options={"seo"="false"}, methods={"GET"})
*/
public function getTypes(Request $request)
{
$typesCode = $request->get('type');
$baseUrl = 'https://akkusysws.aldoc.eu';
$typesUrls = '/MMT/mmt.asmx/GetTypes?modelcode=' . $typesCode . '&bygrouptype=0&withktyp=1&message=""';
$url = $baseUrl . $typesUrls;
$contents = $this->client->get($url)->getBody()->getContents();
return new Response($contents);
}
/**
* @Route("/expert/get-type-details", defaults={"_format"="xml"}, name="frontend.expert.gettypedetails", options={"seo"="false"}, methods={"GET"})
*/
public function getTypeDetails(Request $request)
{
$typesCode = $request->get('type');
$baseUrl = 'https://akkusysws.aldoc.eu';
$typesUrls = '/MMT/mmt.asmx/GetTypeDetails?typecode=' . $typesCode . '&bygrouptype=0&withktyp=1&message=""';
$url = $baseUrl . $typesUrls;
$contents = $this->client->get($url)->getBody()->getContents();
return new Response($contents);
}
public function getCarDetails(string $typesCode)
{
$baseUrl = 'https://akkusysws.aldoc.eu';
$typesUrls = '/MMT/mmt.asmx/GetTypeDetails?typecode=' . $typesCode . '&bygrouptype=0&withktyp=1&message=""';
$url = $baseUrl . $typesUrls;
$contents = $this->client->get($url)->getBody()->getContents();
$xml = new \SimpleXMLElement($contents);
return [ 'makename' => (string) $xml->makename,
'modelname' => (string) $xml->modelname,
'type_from' => (string) $xml->type_from,
'type_till' => (string) $xml->type_till,
'kw_cat' => (string) $xml->kw_cat,
'typename' => (string) $xml->typename
];
}
/**
* @Route("/expert/get-by-hsn-tsn", defaults={"_format"="xml"}, name="frontend.expert.getbyhsntsn", options={"seo"="false"}, methods={"GET"})
*/
public function getByHsnTsn(Request $request)
{
$kba = $request->get('kba');
$baseUrl = 'https://akkusysws.aldoc.eu/MMT/mmt.asmx/GetTypesByIdentifier?';
$kbaUrl = 'CollectionToQuery=KBA&beginOfIdentifier=' . $kba . '&StartAtIndex=0&maxNrOfRecs=100&message=h';
$url = $baseUrl . $kbaUrl;
$contents = $this->client->get($url)->getBody()->getContents();
return new Response($contents);
}
/**
* @Route("/expert/get-results", defaults={"_format"="xml"}, name="frontend.expert.getresults", options={"seo"="false"}, methods={"GET"})
*/
public function getResults(Request $request)
{
$typecode = $request->get('typecode');
$url = 'https://akkusysws.aldoc.eu:443/PartServices/api/Parts/2/' . $typecode . '?language=en&message=%22%22';
$contents = $this->client->get($url)->getBody()->getContents();
return new Response($contents);
}
/**
* @TODO: @HttpCache() // => activates Route caching for this route
* @Route("/expert/get-body-type-info", defaults={"_format"="xml"}, name="frontend.expert.getbodytypeinfo", options={"seo"="false"}, methods={"GET"})
*/
public function getBodyTypeInfo(Request $request)
{
$lang = $request->get('lang');
$baseUrl = 'https://akkusysws.aldoc.eu';
$modelsUrl = '/MMT/mmt.asmx/GetBodytypesInfo?lang=' . $lang . '&message=""';
$url = $baseUrl . $modelsUrl;
$contents = $this->client->get($url)->getBody()->getContents();
return new Response($contents);
}
private function sortProperties(ProductEntity $product): PropertyGroupCollection
{
$properties = $product->getProperties();
if ($properties === null) {
return new PropertyGroupCollection();
}
$sorted = [];
foreach ($properties as $option) {
$origin = $option->getGroup();
if (!$origin || !$origin->getVisibleOnProductDetailPage()) {
continue;
}
$group = clone $origin;
$groupId = $group->getId();
if (\array_key_exists($groupId, $sorted)) {
\assert($sorted[$groupId]->getOptions() !== null);
$sorted[$groupId]->getOptions()->add($option);
continue;
}
if ($group->getOptions() === null) {
$group->setOptions(new PropertyGroupOptionCollection());
}
\assert($group->getOptions() !== null);
$group->getOptions()->add($option);
$sorted[$groupId] = $group;
}
$collection = new PropertyGroupCollection($sorted);
$collection->sortByPositions();
$collection->sortByConfig();
return $collection;
}
private function generateSearchTerms($manufacturerName, $modelName, $typeName): ?array
{
if (!empty($manufacturerName)) {
$makeCode = $this->getMakeCodeByName($manufacturerName);
if (!empty($makeCode) && !empty($modelName)) {
$modelCode = $this->getModelCodeByName($makeCode, $modelName);
if (!empty($makeCode) && !empty($modelName)) {
$typeCode = $this->getTypeCodeByName($modelCode, $typeName);
if (!empty($typeCode)) {
$results = $this->getResultsByType($typeCode);
if (array_key_exists('Articles', $results)) {
$searchTerms = [];
foreach ($results['Articles'] as $item) {
array_push($searchTerms, $item['Reference']);
}
return [$typeCode, implode('|', $searchTerms)];
}
}
}
}
}
return null;
}
private function getMakeCodeByName($manufacturerName): ?string
{
$baseUrl = 'https://akkusysws.aldoc.eu';
$makesUrl = '/MMT/mmt.asmx/GetMakes?filter=0&message=""';
$url = $baseUrl . $makesUrl;
$response = $this->client->get($url)->getBody()->getContents();
$xml = simplexml_load_string($response, 'SimpleXMLElement', LIBXML_NOCDATA);
$data = json_decode(json_encode($xml), TRUE);
if (array_key_exists('makes', $data)) {
foreach ($data['makes']['Make'] as $make) {
if (strtolower($make['makename']) == strtolower($manufacturerName)) {
return $make['makecode'];
}
}
}
return null;
}
private function getModelCodeByName($makeCode, $modelName): ?string
{
$baseUrl = 'https://akkusysws.aldoc.eu';
$modelsUrl = '/MMT/mmt.asmx/GetModels?makecode=' . $makeCode . '&message=""';
$url = $baseUrl . $modelsUrl;
$response = $this->client->get($url)->getBody()->getContents();
$xml = simplexml_load_string($response, 'SimpleXMLElement', LIBXML_NOCDATA);
$data = json_decode(json_encode($xml), TRUE);
if (array_key_exists('models', $data)) {
foreach ($data['models']['Model'] as $model) {
if (strtolower($model['modelname']) == strtolower($modelName)) {
return $model['modelcode'];
}
}
}
return null;
}
private function getTypeCodeByName($modelCode, $typeName): ?string
{
$baseUrl = 'https://akkusysws.aldoc.eu';
$typesUrls = '/MMT/mmt.asmx/GetTypes?modelcode=' . $modelCode . '&bygrouptype=0&withktyp=1&message=""';
$url = $baseUrl . $typesUrls;
$response = $this->client->get($url)->getBody()->getContents();
$xml = simplexml_load_string($response, 'SimpleXMLElement', LIBXML_NOCDATA);
$data = json_decode(json_encode($xml), TRUE);
if (array_key_exists('types', $data)) {
try {
if (is_string(array_key_first($data['types']['Type']))) {
$model = $data['types']['Type'];
if (strtolower($model['typename']) == strtolower($typeName)) {
return $model['typecode'];
}
} else {
foreach ($data['types']['Type'] as $model) {
if (strtolower($model['typename']) == strtolower($typeName)) {
return $model['typecode'];
}
}
}
} catch (\Exception $e) {
return null;
}
}
return null;
}
private function getResultsByType($typecode): ?array
{
$url = 'https://akkusysws.aldoc.eu:443/PartServices/api/Parts/2/' . $typecode . '?language=en&message=%22%22';
$response = $this->client->get($url)->getBody()->getContents();
$data = json_decode($response, TRUE);
return $data;
}
}