Skip to content

Instantly share code, notes, and snippets.

@zspine
Last active March 23, 2023 08:46

Revisions

  1. zspine revised this gist Sep 23, 2019. 1 changed file with 0 additions and 4 deletions.
    4 changes: 0 additions & 4 deletions UserDenormalizer.php
    Original file line number Diff line number Diff line change
    @@ -28,10 +28,6 @@ class UserDenormalizer implements ContextAwareDenormalizerInterface, Denormalize
    */
    private const ALREADY_CALLED = 'USER_DENORMALIZER_ALREADY_CALLED';

    /**
    * @var DenormalizerInterface
    */
    private $decorated;
    /**
    * @var Security
    */
  2. zspine created this gist Sep 23, 2019.
    55 changes: 55 additions & 0 deletions SuperAdminGroupContextBuilder.php
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,55 @@
    <?php

    namespace App\Serializer\ApiPlatform;

    use ApiPlatform\Core\Serializer\SerializerContextBuilderInterface;
    use Psr\Log\LoggerAwareInterface;
    use Psr\Log\LoggerAwareTrait;
    use Symfony\Component\HttpFoundation\Request;
    use Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface;
    use App\Entity\User;

    /**
    * Class SuperAdminGroupContextBuilder
    * @package App\Serializer\ApiPlatform
    */
    class SuperAdminGroupContextBuilder implements SerializerContextBuilderInterface, LoggerAwareInterface
    {
    use LoggerAwareTrait;

    /**
    * @var SerializerContextBuilderInterface
    */
    private $decorated;

    /**
    * @var AuthorizationCheckerInterface
    */
    private $authorizationChecker;

    /**
    * AdminGroupContextBuilder constructor.
    * @param SerializerContextBuilderInterface $decorated
    * @param AuthorizationCheckerInterface $authorizationChecker
    */
    public function __construct(
    SerializerContextBuilderInterface $decorated,
    AuthorizationCheckerInterface $authorizationChecker
    ) {
    $this->decorated = $decorated;
    $this->authorizationChecker = $authorizationChecker;
    }

    /**
    * @param Request $request
    * @param bool $normalization
    * @param array|null $extractedAttributes
    * @return array
    */
    public function createFromRequest(Request $request, bool $normalization, ?array $extractedAttributes = null): array
    {
    $context = $this->decorated->createFromRequest($request, $normalization, $extractedAttributes);
    $this->logger->debug(self::class, $context);
    return $context;
    }
    }
    124 changes: 124 additions & 0 deletions UserDenormalizer.php
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,124 @@
    <?php

    namespace App\Serializer\Denormalizer;


    use App\Entity\User;
    use App\Model\User\UserInterface;
    use Psr\Log\LoggerAwareInterface;
    use Psr\Log\LoggerAwareTrait;
    use Symfony\Component\Security\Core\Security;
    use Symfony\Component\Serializer\Normalizer\CacheableSupportsMethodInterface;
    use Symfony\Component\Serializer\Normalizer\ContextAwareDenormalizerInterface;
    use Symfony\Component\Serializer\Normalizer\DenormalizerAwareInterface;
    use Symfony\Component\Serializer\Normalizer\DenormalizerAwareTrait;
    use Symfony\Component\Serializer\Normalizer\DenormalizerInterface;

    /**
    * Class UserDenormalizer
    * @package App\Serializer\Denormalizer
    */
    class UserDenormalizer implements ContextAwareDenormalizerInterface, DenormalizerAwareInterface, LoggerAwareInterface
    {
    use DenormalizerAwareTrait;
    use LoggerAwareTrait;

    /**
    * @var string
    */
    private const ALREADY_CALLED = 'USER_DENORMALIZER_ALREADY_CALLED';

    /**
    * @var DenormalizerInterface
    */
    private $decorated;
    /**
    * @var Security
    */
    private $security;

    /**
    * UserDenormalizer constructor.
    * @param Security $security
    */
    public function __construct(Security $security)
    {
    $this->security = $security;
    }

    /**\
    * {@inheritDoc}
    */
    public function denormalize($data, $type, $format = null, array $context = [])
    {
    $context['groups'] = ($context['groups']) ?? [];
    if(isset($context['collection_operation_name'])) {
    switch ($context['collection_operation_name']) {
    case 'post':
    $context['groups'][] = 'anon:write';
    break;
    }
    }

    if(isset($context['item_operation_name'])) {
    switch ($context['item_operation_name']) {
    case 'put':
    if($this->isSuperAdmin() || $this->isAllowed()) {
    $context['groups'][] = 'me:write';
    }
    break;
    }
    }

    if($this->isSuperAdmin()) {
    if(!in_array('super:write', $context['groups'], true)) {
    $context['groups'][] = 'super:write';
    }
    }
    array_unique($context['groups']);

    $context[self::ALREADY_CALLED] = true;

    $this->logger->debug(self::class, $context);
    return $this->denormalizer->denormalize($data, $type, $format, $context);
    }

    /**
    * {@inheritDoc}
    */
    public function supportsDenormalization($data, $type, $format = null, array $context = [])
    {
    if (isset($context[self::ALREADY_CALLED])) {
    return false;
    }
    return User::class === $type;
    }

    /**
    * @return bool
    */
    public function isSuperAdmin()
    {
    /** @var User|null $user */
    $user = $this->security->getUser();
    if(!($user instanceof UserInterface)) {
    return false;
    }

    return $user->hasRole(User::ROLE_SUPER_ADMIN);
    }

    /**
    * @return bool
    * @todo make sure to replace this method with a service (dummy_placeholder)
    */
    public function isAllowed()
    {
    /** @var User|null $user */
    $user = $this->security->getUser();
    if(!($user instanceof UserInterface)) {
    return false;
    }
    return $user->hasRole(User::DEFAULT_ROLE);
    }
    }
    12 changes: 12 additions & 0 deletions services.yaml
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,12 @@
    ########################################################################################################################
    ### API PLATFORM
    ########################################################################################################################

    App\Serializer\ApiPlatform\SuperAdminGroupContextBuilder:
    decorates: 'api_platform.serializer.context_builder'
    arguments: [ '@App\Serializer\ApiPlatform\SuperAdminGroupContextBuilder.inner' ]
    autoconfigure: false

    App\Serializer\Denormalizer\UserDenormalizer:
    tags:
    - { name: serializer.normalizer}