Covivo/mobicoop

View on GitHub
api/src/Serializer/ApiNormalizer.php

Summary

Maintainability
A
0 mins
Test Coverage
<?php
/**
 * Copyright (c) 2021, 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\Serializer;

use App\Carpool\Repository\ProposalRepository;
use App\Carpool\Ressource\Ad;
use App\Community\Entity\CommunityUser;
use App\Gamification\Entity\GamificationNotifier;
use App\Gamification\Entity\Reward;
use App\Gamification\Entity\RewardStep;
use App\Gamification\Repository\RewardRepository;
use App\Gamification\Repository\RewardStepRepository;
use App\Service\FormatDataManager;
use App\User\Entity\User;
use App\User\Service\IdentityProofManager;
use App\User\Service\UserManager;
use Doctrine\ORM\EntityManagerInterface;
use Psr\Log\LoggerInterface;
use Symfony\Component\HttpFoundation\RequestStack;
use Symfony\Component\Security\Core\Security;
use Symfony\Component\Serializer\Normalizer\DenormalizerInterface;
use Symfony\Component\Serializer\Normalizer\NormalizerInterface;
use Symfony\Component\Serializer\SerializerAwareInterface;
use Symfony\Component\Serializer\SerializerInterface;

final class ApiNormalizer implements NormalizerInterface, DenormalizerInterface, SerializerAwareInterface
{
    private $decorated;
    private $gamificationNotifier;
    private $rewardStepRepository;
    private $rewardRepository;
    private $proposalRepository;
    private $security;
    private $entityManager;
    private $badgeImageUri;
    private $gamificationActive;
    private $logger;
    private $request;
    private $userManager;

    private $log = false;

    private $currentRewardStep;

    private $gratuityActive;
    private $gratuityNotificationNormalizer;

    private $formatDataManager;
    private $identityProofManager;

    public function __construct(
        NormalizerInterface $decorated,
        GamificationNotifier $gamificationNotifier,
        RewardStepRepository $rewardStepRepository,
        RewardRepository $rewardRepository,
        ProposalRepository $proposalRepository,
        Security $security,
        EntityManagerInterface $entityManager,
        string $badgeImageUri,
        bool $gamificationActive,
        LoggerInterface $logger,
        RequestStack $request,
        UserManager $userManager,
        bool $gratuityActive,
        GratuityNotificationNormalizer $gratuityNotificationNormalizer,
        FormatDataManager $formatDataManager,
        IdentityProofManager $identityProofManager
    ) {
        if (!$decorated instanceof DenormalizerInterface) {
            throw new \InvalidArgumentException(sprintf('The decorated normalizer must implement the %s.', DenormalizerInterface::class));
        }

        $this->decorated = $decorated;
        $this->gamificationNotifier = $gamificationNotifier;
        $this->rewardStepRepository = $rewardStepRepository;
        $this->rewardRepository = $rewardRepository;
        $this->proposalRepository = $proposalRepository;
        $this->security = $security;
        $this->entityManager = $entityManager;
        $this->badgeImageUri = $badgeImageUri;
        $this->gamificationActive = $gamificationActive;
        $this->logger = $logger;
        $this->request = $request->getCurrentRequest();
        $this->userManager = $userManager;
        $this->gratuityActive = $gratuityActive;
        $this->gratuityNotificationNormalizer = $gratuityNotificationNormalizer;
        $this->formatDataManager = $formatDataManager;
        $this->identityProofManager = $identityProofManager;
    }

    public function getCurrentRewardStep(): RewardStep
    {
        return $this->currentRewardStep;
    }

    public function setCurrentRewardStep(RewardStep $rewardStep)
    {
        $this->currentRewardStep = $rewardStep;
    }

    public function supportsNormalization($data, $format = null)
    {
        return $this->decorated->supportsNormalization($data, $format) && $this->security->getUser() instanceof User;
    }

    public function normalize($object, $format = null, array $context = [])
    {
        if ($this->log) {
            $this->logger->info('Api Normalize on '.get_class($object));
        }

        $data = $this->decorated->normalize($object, $format, $context);

        // add adType to User in admin

        if (isset($context['collection_operation_name']) && 'ADMIN_get' === $context['collection_operation_name'] && ($object instanceof User || $object instanceof CommunityUser)) {
            if ($object instanceof User) {
                $user = $data['id'];
            } else {
                $user = $data['userId'];
            }
            $nbDriver = $this->proposalRepository->getNbActiveAdsForUserAndRole($user, Ad::ROLE_DRIVER);
            $nbPassenger = $this->proposalRepository->getNbActiveAdsForUserAndRole($user, Ad::ROLE_PASSENGER);
            if ($nbDriver > 0 && $nbPassenger > 0) {
                $data['adType'] = User::AD_DRIVER_PASSENGER;
            } elseif ($nbDriver > 0) {
                $data['adType'] = User::AD_DRIVER;
            } elseif ($nbPassenger > 0) {
                $data['adType'] = User::AD_PASSENGER;
            } else {
                $data['adType'] = User::AD_NONE;
            }

            return $data;
        }
        if (true == $this->gratuityActive && $object instanceof User && $object->getId() === $this->security->getUser()->getId()) {
            $this->gratuityNotificationNormalizer->setUser($this->security->getUser());
            $data = $this->gratuityNotificationNormalizer->normalize($data);
        }
        // We check if there is some gamificationNotifications entities in waiting for the current User
        if (true == $this->gamificationActive && $object instanceof User && $object->getId() === $this->security->getUser()->getId()) {
            // Waiting RewardSteps
            $waitingRewardSteps = $this->rewardStepRepository->findWaiting($this->security->getUser());
            if (is_array($data) && is_array($waitingRewardSteps) && count($waitingRewardSteps) > 0) {
                $data['gamificationNotifications'] = [];
                foreach ($waitingRewardSteps as $waitingRewardStep) {
                    $data['gamificationNotifications'][] = $this->formatRewardStep($waitingRewardStep);
                }
            }

            // Waiting Rewards
            $waitingRewards = $this->rewardRepository->findWaiting($this->security->getUser());
            if (is_array($data) && is_array($waitingRewards) && count($waitingRewards) > 0) {
                $data['gamificationNotifications'] = [];
                foreach ($waitingRewards as $waitingReward) {
                    $data['gamificationNotifications'][] = $this->formatReward($waitingReward);
                }
            }

            // New gamification notifications
            if (is_array($data) && count($this->gamificationNotifier->getNotifications()) > 0) {
                // We init the array only if it's not already filled
                if (!isset($data['gamificationNotifications'])) {
                    $data['gamificationNotifications'] = [];
                }
                foreach ($this->gamificationNotifier->getNotifications() as $gamificationNotification) {
                    if ($gamificationNotification instanceof Reward) {
                        $rewardIds = [];
                        foreach ($data['gamificationNotifications'] as $notification) {
                            if ('Reward' == $notification['type']) {
                                $rewardIds[] = $notification['id'];
                            }
                        }
                        if (!in_array($gamificationNotification->getId(), $rewardIds)) {
                            $data['gamificationNotifications'][] = $this->formatReward($gamificationNotification);
                        }
                    } elseif ($gamificationNotification instanceof RewardStep) {
                        $rewardStepIds = [];
                        foreach ($data['gamificationNotifications'] as $notification) {
                            if ('RewardStep' == $notification['type']) {
                                $rewardStepIds[] = $notification['id'];
                            }
                        }
                        if (!in_array($gamificationNotification->getId(), $rewardStepIds)) {
                            $data['gamificationNotifications'][] = $this->formatRewardStep($gamificationNotification);
                        }
                        $this->entityManager->persist($gamificationNotification);
                    }
                }
            }
            if (isset($data['gamificationNotifications'])) {
                // we remove RewardStep if he's associated to a gained badge
                $badgeIds = [];
                foreach ($data['gamificationNotifications'] as $gamificationNotification) {
                    if ('Badge' == $gamificationNotification['type']) {
                        $badgeIds[] = $gamificationNotification['id'];
                    }
                }
                foreach ($data['gamificationNotifications'] as $key => $gamificationNotification) {
                    if ('RewardStep' == $gamificationNotification['type'] && in_array($gamificationNotification['badge']['id'], $badgeIds)) {
                        unset($data['gamificationNotifications'][$key]);
                    }
                }
            }
            $this->entityManager->flush();
        }

        if ($object instanceof User && isset($data['identityProofs'])) {
            foreach ($data['identityProofs'] as $key => $proof) {
                $data['identityProofs'][$key]['fileSize'] = $this->formatDataManager->convertFilesize($proof['size']);
                $data['identityProofs'][$key]['fileName'] = $this->identityProofManager->getFileUrlFromArray($proof);
            }
        }

        return $data;
    }

    public function supportsDenormalization($data, $type, $format = null)
    {
        return $this->decorated->supportsDenormalization($data, $type, $format);
    }

    public function denormalize($data, $class, $format = null, array $context = [])
    {
        if ($this->log) {
            $this->logger->info('Api Denormalize on '.$class);
        }

        return $this->decorated->denormalize($data, $class, $format, $context);
    }

    public function setSerializer(SerializerInterface $serializer)
    {
        if ($this->decorated instanceof SerializerAwareInterface) {
            $this->decorated->setSerializer($serializer);
        }
    }

    private function replaceDynamicValuesInRewardStep(string $chain): string
    {
        $chain = str_replace('{minCount}', $this->getCurrentRewardStep()->getSequenceItem()->getMinCount(), $chain);
        $chain = str_replace('{minUniqueCount}', $this->getCurrentRewardStep()->getSequenceItem()->getMinUniqueCount(), $chain);

        return str_replace('{value}', $this->getCurrentRewardStep()->getSequenceItem()->getValue(), $chain);
    }

    /**
     * Format a RewardStep to be notified.
     */
    private function formatRewardStep(RewardStep $rewardStep): array
    {
        if ($this->log) {
            $this->logger->info('Api Normalize formatRewardStep '.$rewardStep->getId());
        }

        $this->setCurrentRewardStep($rewardStep);

        return [
            'type' => 'RewardStep',
            'id' => $rewardStep->getId(),
            'title' => $this->replaceDynamicValuesInRewardStep($rewardStep->getSequenceItem()->getGamificationAction()->getTitle()),
            'notifiedDate' => $rewardStep->getNotifiedDate(),
            'badge' => [
                'id' => $rewardStep->getSequenceItem()->getBadge()->getId(),
                'name' => $rewardStep->getSequenceItem()->getBadge()->getName(),
                'title' => $rewardStep->getSequenceItem()->getBadge()->getTitle(),
            ],
        ];
    }

    /**
     * Format a Reward to be notified.
     */
    private function formatReward(Reward $reward): array
    {
        if ($this->log) {
            $this->logger->info('Api Normalize formatReward '.$reward->getId());
        }

        return [
            'type' => 'Badge',
            'id' => $reward->getBadge()->getId(),
            'rewardId' => $reward->getId(),
            'name' => $reward->getBadge()->getName(),
            'title' => $reward->getBadge()->getTitle(),
            'notifiedDate' => $reward->getNotifiedDate(),
            'text' => $reward->getBadge()->getText(),
            'pictures' => [
                'icon' => (!is_null($reward->getBadge()->getIcon())) ? $this->badgeImageUri.$reward->getBadge()->getIcon()->getFileName() : null,
                'decoratedIcon' => (!is_null($reward->getBadge()->getDecoratedIcon())) ? $this->badgeImageUri.$reward->getBadge()->getDecoratedIcon()->getFileName() : null,
                'image' => (!is_null($reward->getBadge()->getImage())) ? $this->badgeImageUri.$reward->getBadge()->getImage()->getFileName() : null,
                'imageLight' => (!is_null($reward->getBadge()->getImageLight())) ? $this->badgeImageUri.$reward->getBadge()->getImageLight()->getFileName() : null,
            ],
        ];
    }
}