<?php
declare(strict_types=1);
namespace VioCustomerDocs\Administration\Subscriber;
use Shopware\Core\Framework\Api\Controller\ApiController;
use Shopware\Core\Framework\Context;
use Shopware\Core\Content\Media\Api\MediaUploadController;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Event\ControllerArgumentsEvent;
use Symfony\Component\HttpKernel\Event\ResponseEvent;
use Symfony\Component\HttpKernel\KernelEvents;
class MediaApiControllerSubscriber implements EventSubscriberInterface
{
private static array $scopedRoutes = [
'api.action.media.upload',
'api.media.search',
'api.media.detail',
'api.media.delete'
];
private array $arguments;
/**
* @var callable
*/
private $controller;
/**
* Returns an array of event names this subscriber wants to listen to.
*
* The array keys are event names and the value can be:
*
* * The method name to call (priority defaults to 0)
* * An array composed of the method name to call and the priority
* * An array of arrays composed of the method names to call and respective
* priorities, or 0 if unset
*
* For instance:
*
* * ['eventName' => 'methodName']
* * ['eventName' => ['methodName', $priority]]
* * ['eventName' => [['methodName1', $priority], ['methodName2']]]
*
* @return array The event names to listen to
*/
public static function getSubscribedEvents():array
{
return [
KernelEvents::CONTROLLER_ARGUMENTS => 'onControllerArguments',
KernelEvents::RESPONSE => 'onResponse'
];
}
/**
* @param ControllerArgumentsEvent $event
*/
public function onControllerArguments(ControllerArgumentsEvent $event):void
{
if (!in_array($event->getRequest()->attributes->get('_route'), self::$scopedRoutes, true)) {
return;
}
$controller = $event->getController();
if (is_array($controller)) {
$controller = $controller[0];
}
if (($controller instanceof MediaUploadController) && strpos($event->getRequest()->get('fileName'), '####CD####') === 0) {
$this->arguments = $event->getArguments();
$this->controller = $event->getController();
}
if ($controller instanceof ApiController) {
$this->arguments = $event->getArguments();
$this->controller = $event->getController();
}
}
public function onResponse(ResponseEvent $event): void
{
if (!in_array($event->getRequest()->attributes->get('_route'), self::$scopedRoutes, true)) {
return;
}
$result = $event->getResponse();
$controller = $this->controller;
if (is_array($controller)) {
$controller = $controller[0];
}
if( $controller instanceof ApiController ) {
$this->scopeMediaSearch($event, $result);
return;
}
if( $controller instanceof MediaUploadController ) {
if ($result->getStatusCode() !== Response::HTTP_NOT_FOUND) {
return;
}
if (strpos($event->getRequest()->get('fileName'), '####CD####') === 0) {
$this->scopeMediaUpload($event, $result);
}
}
}
/**
* @param ResponseEvent $event
* @param Response $result
* @return void
*/
private function scopeMediaUpload(ResponseEvent $event, Response $result): void
{
/** @var Context $arguments */
$context = $event->getRequest()->attributes->get('sw-context');
if (!$context instanceof Context) {
return;
}
$controller = $this->controller;
$arguments = $this->arguments;
$context->scope(Context::SYSTEM_SCOPE, function (Context $context) use (&$result, $controller, $arguments): void {
// replace arguments context with scoped context
/** @noinspection AlterInForeachInspection */
foreach ($arguments as &$argument) {
if ($argument instanceof Context) {
$argument = $context;
break;
}
if ($argument instanceof Request) {
$query = $argument->query->all();
$query['fileName'] = str_replace('####CD####', substr(md5(uniqid('', true)), 0, 6) . '_', $argument->query->get('fileName'));
$argument = $argument->duplicate($query);
break;
}
}
/** @var Response $result */
$result = $controller(...$arguments);
});
$event->setResponse($result);
}
/**
* @param ResponseEvent $event
* @param Response $result
* @return void
*/
private function scopeMediaSearch(ResponseEvent $event, Response $result): void
{
/** @var Context $arguments */
$context = $event->getRequest()->attributes->get('sw-context');
if (!$context instanceof Context) {
return;
}
$controller = $this->controller;
$arguments = $this->arguments;
$context->scope(Context::SYSTEM_SCOPE, function (Context $context) use (&$result, $controller, $arguments): void {
// replace arguments context with scoped context
/** @noinspection AlterInForeachInspection */
foreach ($arguments as &$argument) {
if ($argument instanceof Context) {
$argument = $context;
break;
}
}
/** @var Response $result */
$result = $controller(...$arguments);
});
$event->setResponse($result);
}
}