Skip to content

Instantly share code, notes, and snippets.

@zspine
Last active March 23, 2023 08:46
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save zspine/dc04af513137e5264b0e5d639722bb95 to your computer and use it in GitHub Desktop.
Save zspine/dc04af513137e5264b0e5d639722bb95 to your computer and use it in GitHub Desktop.
API Platform custom ContextBuilder and Denormalizer
########################################################################################################################
### 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}
<?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;
}
}
<?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 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);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment