api/src/EventListener/DeserializeListener.php
<?php
/**
* Copyright (c) 2020, MOBICOOP. All rights reserved.
* This project is dual licensed under AGPL and proprietary licence.
***************************
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <gnu.org/licenses>.
***************************
* Licence MOBICOOP described in the file
* LICENSE
*/
namespace App\EventListener;
use ApiPlatform\Core\EventListener\DeserializeListener as DecoratedListener;
use ApiPlatform\Core\Serializer\SerializerContextBuilderInterface;
use ApiPlatform\Core\Util\RequestAttributesExtractor;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpKernel\Event\RequestEvent;
use Symfony\Component\Serializer\Normalizer\DenormalizerInterface;
/**
* To deserialize form-data request
* i.e. /rdex/connections POST.
*
* @author Maxime Bardot <maxime.bardot@mobicoop.org>
*/
final class DeserializeListener
{
public const AUTHORIZED_FORM_URL = ['/rdex/connections'];
public const URLS_FOR_ID_REMOVAL = ['/campaigns/unsubscribe'];
private $decorated;
private $denormalizer;
private $serializerContextBuilder;
public function __construct(DenormalizerInterface $denormalizer, SerializerContextBuilderInterface $serializerContextBuilder, DecoratedListener $decorated)
{
$this->denormalizer = $denormalizer;
$this->serializerContextBuilder = $serializerContextBuilder;
$this->decorated = $decorated;
}
public function onKernelRequest(RequestEvent $event): void
{
$request = $event->getRequest();
if ($request->isMethodCacheable(false) || $request->isMethod(Request::METHOD_DELETE)) {
return;
}
if ('form' === $request->getContentType() && in_array($request->getPathInfo(), self::AUTHORIZED_FORM_URL)) {
$this->denormalizeFormRequest($request);
} else {
$this->_removeIdOfOriginalPostRequestBody($request);
$this->decorated->onKernelRequest($event);
}
}
private function _removeIdOfOriginalPostRequestBody(Request $request): void
{
if ('POST' == $request->getMethod() && in_array($request->getPathInfo(), self::URLS_FOR_ID_REMOVAL)) {
$body = json_decode($request->getContent(), true);
unset($body['id']);
$query = $request->query->all();
$requestParameters = $request->request->all();
$attributes = $request->attributes->all();
$cookies = $request->cookies->all();
$files = $request->files->all();
$server = $request->server->all();
$request->initialize($query, $requestParameters, $attributes, $cookies, $files, $server, json_encode($body));
}
}
private function denormalizeFormRequest(Request $request): void
{
if (!$attributes = RequestAttributesExtractor::extractAttributes($request)) {
return;
}
$context = $this->serializerContextBuilder->createFromRequest($request, false, $attributes);
$populated = $request->attributes->get('data');
if (null !== $populated) {
$context['object_to_populate'] = $populated;
}
$data = $request->request->all();
$object = $this->denormalizer->denormalize($data, $attributes['resource_class'], null, $context);
$request->attributes->set('data', $object);
}
}