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.
Example of is owner denormalizer
<?php
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;
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, ContextAwareDenormalizerInterface, DenormalizerAwareInterface
{
use NormalizerAwareTrait;
use DenormalizerAwareTrait;
private const ALREADY_CALLED = 'USER_NORMALIZER_ALREADY_CALLED';
private $security;
/**
* @var RequestStack
*/
private $requestStack;
public function __construct(Security $security, RequestStack $requestStack)
{
$this->security = $security;
$this->requestStack = $requestStack;
}
/**
* @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;
}
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;
/** @var User $apiResource */
$apiResource = $this->requestStack->getCurrentRequest()
->attributes->get('data');
/*
* 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';
}
/*
* 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) {
throw new \Exception('This should be a User! Something went wrong!');
}
return $object;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment