<?php declare(strict_types=1);
namespace DreiscSeoPro\Core\Routing;
use DreiscSeoPro\Core\Content\DreiscSeoRedirect\DreiscSeoRedirectEntity;
use DreiscSeoPro\Core\Content\DreiscSeoRedirect\DreiscSeoRedirectRepository;
use DreiscSeoPro\Core\Routing\Category\CategoryRedirectSearcher;
use DreiscSeoPro\Core\Routing\Product\ProductRedirectSearcher;
use Shopware\Core\Framework\DataAbstractionLayer\Exception\InconsistentCriteriaIdsException;
use Shopware\Core\SalesChannelRequest;
use Symfony\Component\HttpFoundation\Request;
class RequestTransformer
{
public const SALES_CHANNEL_BASE_URL = 'sw-sales-channel-base-url';
/**
* @var DreiscSeoRedirectRepository
*/
private $dreiscSeoRedirectRepository;
/**
* @var RedirectExecutor
*/
private $redirectExecutor;
/**
* @var ProductRedirectSearcher
*/
private $productRedirectSearcher;
/**
* @var CategoryRedirectSearcher
*/
private $categoryRedirectSearcher;
/**
* @param DreiscSeoRedirectRepository $dreiscSeoRedirectRepository
* @param RedirectExecutor $redirectExecutor
* @param ProductRedirectSearcher $productRedirectSearcher
* @param CategoryRedirectSearcher $categoryRedirectSearcher
*/
public function __construct(DreiscSeoRedirectRepository $dreiscSeoRedirectRepository, RedirectExecutor $redirectExecutor, ProductRedirectSearcher $productRedirectSearcher, CategoryRedirectSearcher $categoryRedirectSearcher)
{
$this->dreiscSeoRedirectRepository = $dreiscSeoRedirectRepository;
$this->redirectExecutor = $redirectExecutor;
$this->productRedirectSearcher = $productRedirectSearcher;
$this->categoryRedirectSearcher = $categoryRedirectSearcher;
}
/**
* This method will be run after the sales channel and the seo url information was fetched
* by the decorated class
*
* @param Request $shopwareRequest
* @param Request $request
* @return Request
* @throws InconsistentCriteriaIdsException
*/
public function transform(Request $shopwareRequest, Request $request): Request
{
/** Abort, if it's not a sales channel url */
if(true !== $shopwareRequest->attributes->has(SalesChannelRequest::ATTRIBUTE_IS_SALES_CHANNEL_REQUEST)) {
return $shopwareRequest;
}
/** Check for entity redirects */
$this->checkForEntityRedirects($shopwareRequest);
/** Fetch the path info */
$pathInfo = $this->getAdjustedRequestUri($request, $shopwareRequest);
/** Try to fetch a redirect for this path */
$dreiscSeoRedirectEntity = $this->dreiscSeoRedirectRepository->getSourceTypeUrlByDomainIdAndSourcePath(
$shopwareRequest->attributes->get(SalesChannelRequest::ATTRIBUTE_DOMAIN_ID),
$pathInfo
);
/** Abort, if there is no redirect */
if (!$dreiscSeoRedirectEntity instanceof DreiscSeoRedirectEntity) {
return $shopwareRequest;
}
/** Check, if this is a test run for PHPUnit */
$isPhpUnitTest = !empty($request->server->get('IS_PHP_UNIT_TEST'));
/** Execute the redirect */
$this->redirectExecutor->redirect(
$dreiscSeoRedirectEntity,
$shopwareRequest->attributes->get(SalesChannelRequest::ATTRIBUTE_DOMAIN_ID),
$isPhpUnitTest
);
return $shopwareRequest;
}
/**
* @param Request $shopwareRequest
* @return bool
* @throws InconsistentCriteriaIdsException
*/
private function checkForEntityRedirects(Request $shopwareRequest): bool
{
$pathInfoExplode = explode('/', $shopwareRequest->getPathInfo());
/** Abort, if path info has more or less than three parts */
if (empty($pathInfoExplode) || 3 !== count($pathInfoExplode)) {
return false;
}
if (empty($pathInfoExplode[0]) && 'detail' === $pathInfoExplode[1] && !empty($pathInfoExplode[2])) {
/** Check if there is redirect for the product */
$this->productRedirectSearcher->search(
$shopwareRequest,
$pathInfoExplode[2]
);
return true;
}
if (empty($pathInfoExplode[0]) && 'navigation' === $pathInfoExplode[1] && !empty($pathInfoExplode[2])) {
/** Check if there is redirect for the product */
$this->categoryRedirectSearcher->search(
$shopwareRequest,
$pathInfoExplode[2]
);
return true;
}
return false;
}
/**
* @param Request $request
* @param Request $shopwareRequest
* @return bool|string
*/
private function getAdjustedRequestUri(Request $request, Request $shopwareRequest)
{
$adjustedRequestUri = $request->getRequestUri();
/**
* Remove the base url from the beginning if available
*/
$baseUrl = $shopwareRequest->attributes->get(self::SALES_CHANNEL_BASE_URL);
if(!empty($baseUrl)) {
/** Make sure, that there is a slash at the end of the base url */
$baseUrl = rtrim($baseUrl, '/') . '/';
/** Remove the base url from the request uri */
$adjustedRequestUri = substr($adjustedRequestUri, strlen($baseUrl));
/**
* There are some special cases. For example, when $adjustedRequestUri is "/en"
* and $baseUrl is "/en/". In this case $baseUrl is longer then $adjustedRequestUri
* and substr will return false. In this case we set "/" as the new value
*/
if(false === $adjustedRequestUri) {
$adjustedRequestUri = '/';
}
}
/** Make sure that there is no slash at the beginning */
$adjustedRequestUri = ltrim($adjustedRequestUri, '/');
return $adjustedRequestUri;
}
}