Navigation Menu

Skip to content

Instantly share code, notes, and snippets.

@weaverryan
Last active July 19, 2020 14:28
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save weaverryan/a1940302b96b203fc651809fc93ee087 to your computer and use it in GitHub Desktop.
Save weaverryan/a1940302b96b203fc651809fc93ee087 to your computer and use it in GitHub Desktop.

Revisions

  1. weaverryan revised this gist Jul 19, 2020. 1 changed file with 14 additions and 0 deletions.
    14 changes: 14 additions & 0 deletions UserNormalizer.php
    @@ -112,6 +112,20 @@ public function denormalize($data, $class, $format = null, array $context = [])
    $context['groups'][] = 'owner:write';
    }

    /*
    * This is an alternate solution: the resource object is already available
    * in the $context variable via the object_to_populate key.
    * thanks to Hans Grinwi in the comments for this tip!
    */
    /*
    if (
    !isset($context['object_to_populate']) ||
    $context['object_to_populate']->getOwner() === $this->security->getUser()
    ) {
    $context['groups'][] = 'owner:write';
    }
    */

    $object = $this->denormalizer->denormalize($data, $class, $format, $context);

    if (!$object instanceof User) {
  2. weaverryan revised this gist Apr 28, 2020. 1 changed file with 8 additions and 1 deletion.
    9 changes: 8 additions & 1 deletion UserNormalizer.php
    @@ -101,7 +101,14 @@ public function denormalize($data, $class, $format = null, array $context = [])
    /** @var User $apiResource */
    $apiResource = $this->requestStack->getCurrentRequest()
    ->attributes->get('data');
    if ($this->userIsOwner($apiResource)) {

    /*
    * Add the owner:write group if:
    * A) the object is being created (the null case) because, by
    * definition, if you are creating the object, you are the owner!
    * B) the object is being updated and the current user is the owner.
    */
    if ($apiResource === null || $this->userIsOwner($apiResource)) {
    $context['groups'][] = 'owner:write';
    }

  3. weaverryan revised this gist Nov 18, 2019. 1 changed file with 14 additions and 5 deletions.
    19 changes: 14 additions & 5 deletions UserNormalizer.php
    @@ -3,6 +3,7 @@
    namespace App\Serializer\Normalizer;

    use App\Entity\User;
    use Symfony\Component\HttpFoundation\RequestStack;
    use Symfony\Component\Security\Core\Security;
    use Symfony\Component\Serializer\Exception\BadMethodCallException;
    use Symfony\Component\Serializer\Exception\ExceptionInterface;
    @@ -27,10 +28,15 @@ class UserNormalizer implements ContextAwareNormalizerInterface, CacheableSuppor
    private const ALREADY_CALLED = 'USER_NORMALIZER_ALREADY_CALLED';

    private $security;
    /**
    * @var RequestStack
    */
    private $requestStack;

    public function __construct(Security $security)
    public function __construct(Security $security, RequestStack $requestStack)
    {
    $this->security = $security;
    $this->requestStack = $requestStack;
    }

    /**
    @@ -92,16 +98,19 @@ public function denormalize($data, $class, $format = null, array $context = [])
    {
    $context[self::ALREADY_CALLED] = true;

    /** @var User $apiResource */
    $apiResource = $this->requestStack->getCurrentRequest()
    ->attributes->get('data');
    if ($this->userIsOwner($apiResource)) {
    $context['groups'][] = 'owner:write';
    }

    $object = $this->denormalizer->denormalize($data, $class, $format, $context);

    if (!$object instanceof User) {
    throw new \Exception('This should be a User! Something went wrong!');
    }

    if ($this->userIsOwner($object)) {
    $context['groups'][] = 'owner:write';
    }

    return $object;
    }
    }
  4. weaverryan revised this gist Nov 12, 2019. 1 changed file with 39 additions and 1 deletion.
    40 changes: 39 additions & 1 deletion UserNormalizer.php
    @@ -4,14 +4,25 @@

    use App\Entity\User;
    use Symfony\Component\Security\Core\Security;
    use Symfony\Component\Serializer\Exception\BadMethodCallException;
    use Symfony\Component\Serializer\Exception\ExceptionInterface;
    use Symfony\Component\Serializer\Exception\ExtraAttributesException;
    use Symfony\Component\Serializer\Exception\InvalidArgumentException;
    use Symfony\Component\Serializer\Exception\LogicException;
    use Symfony\Component\Serializer\Exception\RuntimeException;
    use Symfony\Component\Serializer\Exception\UnexpectedValueException;
    use Symfony\Component\Serializer\Normalizer\CacheableSupportsMethodInterface;
    use Symfony\Component\Serializer\Normalizer\ContextAwareDenormalizerInterface;
    use Symfony\Component\Serializer\Normalizer\ContextAwareNormalizerInterface;
    use Symfony\Component\Serializer\Normalizer\DenormalizerAwareInterface;
    use Symfony\Component\Serializer\Normalizer\DenormalizerAwareTrait;
    use Symfony\Component\Serializer\Normalizer\NormalizerAwareInterface;
    use Symfony\Component\Serializer\Normalizer\NormalizerAwareTrait;

    class UserNormalizer implements ContextAwareNormalizerInterface, CacheableSupportsMethodInterface, NormalizerAwareInterface
    class UserNormalizer implements ContextAwareNormalizerInterface, CacheableSupportsMethodInterface, NormalizerAwareInterface, ContextAwareDenormalizerInterface, DenormalizerAwareInterface
    {
    use NormalizerAwareTrait;
    use DenormalizerAwareTrait;

    private const ALREADY_CALLED = 'USER_NORMALIZER_ALREADY_CALLED';

    @@ -66,4 +77,31 @@ public function hasCacheableSupportsMethod(): bool
    {
    return false;
    }

    public function supportsDenormalization($data, $type, $format = null, array $context = [])
    {
    // avoid recursion: only call once per object
    if (isset($context[self::ALREADY_CALLED])) {
    return false;
    }

    return $type === User::class;
    }

    public function denormalize($data, $class, $format = null, array $context = [])
    {
    $context[self::ALREADY_CALLED] = true;

    $object = $this->denormalizer->denormalize($data, $class, $format, $context);

    if (!$object instanceof User) {
    throw new \Exception('This should be a User! Something went wrong!');
    }

    if ($this->userIsOwner($object)) {
    $context['groups'][] = 'owner:write';
    }

    return $object;
    }
    }
  5. weaverryan created this gist Nov 12, 2019.
    69 changes: 69 additions & 0 deletions UserNormalizer.php
    @@ -0,0 +1,69 @@
    <?php

    namespace App\Serializer\Normalizer;

    use App\Entity\User;
    use Symfony\Component\Security\Core\Security;
    use Symfony\Component\Serializer\Normalizer\CacheableSupportsMethodInterface;
    use Symfony\Component\Serializer\Normalizer\ContextAwareNormalizerInterface;
    use Symfony\Component\Serializer\Normalizer\NormalizerAwareInterface;
    use Symfony\Component\Serializer\Normalizer\NormalizerAwareTrait;

    class UserNormalizer implements ContextAwareNormalizerInterface, CacheableSupportsMethodInterface, NormalizerAwareInterface
    {
    use NormalizerAwareTrait;

    private const ALREADY_CALLED = 'USER_NORMALIZER_ALREADY_CALLED';

    private $security;

    public function __construct(Security $security)
    {
    $this->security = $security;
    }

    /**
    * @param User $object
    */
    public function normalize($object, $format = null, array $context = array()): array
    {
    if ($this->userIsOwner($object)) {
    $context['groups'][] = 'owner:read';
    }

    $context[self::ALREADY_CALLED] = true;

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

    // Here: add, edit, or delete some data

    return $data;
    }

    public function supportsNormalization($data, $format = null, array $context = [])
    {
    // avoid recursion: only call once per object
    if (isset($context[self::ALREADY_CALLED])) {
    return false;
    }

    return $data instanceof User;
    }

    private function userIsOwner(User $user): bool
    {
    /** @var User|null $authenticatedUser */
    $authenticatedUser = $this->security->getUser();

    if (!$authenticatedUser) {
    return false;
    }

    return $authenticatedUser->getEmail() === $user->getEmail();
    }

    public function hasCacheableSupportsMethod(): bool
    {
    return false;
    }
    }