Covivo/mobicoop

View on GitHub
api/src/EventListener/DeserializeListener.php

Summary

Maintainability
A
0 mins
Test Coverage
<?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);
    }
}