Skip to content
Snippets Groups Projects
Commit 3c696f31 authored by Tobias Gross-Vogt's avatar Tobias Gross-Vogt
Browse files

BREAKING CHANGES: automatic adding of local data attributes via config;...

BREAKING CHANGES: automatic adding of local data attributes via config; renmaed LocalDataAware -> LocalData where used falsely
parent 4c468456
No related branches found
No related tags found
No related merge requests found
Pipeline #210057 passed
...@@ -10,6 +10,9 @@ use Symfony\Component\HttpFoundation\Response; ...@@ -10,6 +10,9 @@ use Symfony\Component\HttpFoundation\Response;
abstract class AbstractAuthorizationService abstract class AbstractAuthorizationService
{ {
public const RIGHTS_CONFIG_ATTRIBUTE = AuthorizationExpressionChecker::RIGHTS_CONFIG_ATTRIBUTE;
public const ATTRIBUTES_CONFIG_ATTRIBUTE = AuthorizationExpressionChecker::ATTRIBUTES_CONFIG_ATTRIBUTE;
/** @var AuthorizationExpressionChecker */ /** @var AuthorizationExpressionChecker */
private $userAuthorizationChecker; private $userAuthorizationChecker;
......
<?php
declare(strict_types=1);
namespace Dbp\Relay\CoreBundle\Entity;
/**
* Interface for entities with an identifier and a name.
*/
interface NamedEntityInterface
{
public function getIdentifier();
public function getName();
}
<?php
declare(strict_types=1);
namespace Dbp\Relay\CoreBundle\LocalData;
use Dbp\Relay\CoreBundle\Authorization\AbstractAuthorizationService;
use Symfony\Component\Config\Definition\Builder\TreeBuilder;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
abstract class AbstractLocalDataPostEventSubscriber extends AbstractAuthorizationService implements EventSubscriberInterface
{
public const CONFIG_NODE = 'local_data_mapping';
public const SOURCE_ATTRIBUTE_KEY = 'source_attribute';
public const LOCAL_DATA_ATTRIBUTE_KEY = 'local_data_attribute';
public const AUTHORIZATION_EXPRESSION_KEY = 'authorization_expression';
/** @var string[] */
private $attributeMapping;
public function setConfig(array $config)
{
$configNode = $config[self::CONFIG_NODE] ?? [];
$rights = [];
foreach ($configNode as $configMappingEntry) {
if (isset($this->attributeMapping[$configMappingEntry[self::LOCAL_DATA_ATTRIBUTE_KEY]])) {
throw new \RuntimeException(sprintf('multiple mapping entries for local data attribute %s', $configMappingEntry[self::LOCAL_DATA_ATTRIBUTE_KEY]));
}
$this->attributeMapping[$configMappingEntry[self::LOCAL_DATA_ATTRIBUTE_KEY]] = $configMappingEntry[self::SOURCE_ATTRIBUTE_KEY];
// the name of the local data attribute is used as name for the right to view that attribute
// the attribute is visible false by default
$rights[$configMappingEntry[self::LOCAL_DATA_ATTRIBUTE_KEY]] = $configMappingEntry[self::AUTHORIZATION_EXPRESSION_KEY] ?? 'false';
}
if (!empty($rights)) {
parent::setConfig([AbstractAuthorizationService::RIGHTS_CONFIG_ATTRIBUTE => $rights]);
}
}
public static function getSubscribedEvents(): array
{
return [static::getSubscribedEventName() => 'onPost'];
}
public static function getSubscribedEventName(): string
{
throw new \RuntimeException(sprintf('child classes must implement the \'%s\' method', __METHOD__));
}
public function onPost(LocalDataPostEvent $postEvent)
{
$sourceData = $postEvent->getSourceData();
foreach ($this->attributeMapping as $localDataAttributeName => $sourceAttributeName) {
if ($this->isGranted($localDataAttributeName)) {
if ($sourceAttributeValue = $sourceData[$sourceAttributeName] ?? null) {
$postEvent->trySetLocalDataAttribute($localDataAttributeName, $sourceAttributeValue);
} else {
throw new \RuntimeException(sprintf('attribute \'%s\' not available in source data', $sourceAttributeName));
}
}
}
}
public static function getConfigNode()
{
$treeBuilder = new TreeBuilder(self::CONFIG_NODE);
return $treeBuilder->getRootNode()
->arrayPrototype()
->children()
->scalarNode(self::SOURCE_ATTRIBUTE_KEY)->end()
->scalarNode(self::LOCAL_DATA_ATTRIBUTE_KEY)->end()
->scalarNode(self::AUTHORIZATION_EXPRESSION_KEY)
->defaultValue('false')
->end()
->end()
->end()
;
}
}
...@@ -35,4 +35,9 @@ class LocalData ...@@ -35,4 +35,9 @@ class LocalData
{ {
return $options[self::QUERY_PARAMETER_NAME] ?? null; return $options[self::QUERY_PARAMETER_NAME] ?? null;
} }
public static function toIncludeLocalParameterValue(array $attributeNames): string
{
return implode(LocalDataEventDispatcher::SEPARATOR, $attributeNames);
}
} }
...@@ -13,8 +13,10 @@ use Symfony\Component\EventDispatcher\EventDispatcherInterface; ...@@ -13,8 +13,10 @@ use Symfony\Component\EventDispatcher\EventDispatcherInterface;
use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpFoundation\Response;
use Symfony\Contracts\EventDispatcher\Event; use Symfony\Contracts\EventDispatcher\Event;
class LocalDataAwareEventDispatcher class LocalDataEventDispatcher
{ {
public const SEPARATOR = ',';
/** @var array */ /** @var array */
private $queryParameters; private $queryParameters;
...@@ -79,10 +81,10 @@ class LocalDataAwareEventDispatcher ...@@ -79,10 +81,10 @@ class LocalDataAwareEventDispatcher
*/ */
public function dispatch(Event $event, string $eventName): void public function dispatch(Event $event, string $eventName): void
{ {
if ($event instanceof LocalDataAwarePreEvent) { if ($event instanceof LocalDataPreEvent) {
$event->setQueryParameters($this->queryParameters); $event->setQueryParameters($this->queryParameters);
$this->eventDispatcher->dispatch($event, $eventName); $this->eventDispatcher->dispatch($event, $eventName);
} elseif ($event instanceof LocalDataAwarePostEvent) { } elseif ($event instanceof LocalDataPostEvent) {
$event->setRequestedAttributes($this->requestedAttributes); $event->setRequestedAttributes($this->requestedAttributes);
$this->eventDispatcher->dispatch($event, $eventName); $this->eventDispatcher->dispatch($event, $eventName);
...@@ -130,7 +132,7 @@ class LocalDataAwareEventDispatcher ...@@ -130,7 +132,7 @@ class LocalDataAwareEventDispatcher
$this->requestedAttributes = []; $this->requestedAttributes = [];
if (!Tools::isNullOrEmpty($includeParameter)) { if (!Tools::isNullOrEmpty($includeParameter)) {
$requestedAttributes = explode(',', $includeParameter); $requestedAttributes = explode(self::SEPARATOR, $includeParameter);
foreach ($requestedAttributes as $requestedAttribute) { foreach ($requestedAttributes as $requestedAttribute) {
$requestedAttribute = trim($requestedAttribute); $requestedAttribute = trim($requestedAttribute);
...@@ -155,7 +157,7 @@ class LocalDataAwareEventDispatcher ...@@ -155,7 +157,7 @@ class LocalDataAwareEventDispatcher
$this->queryParameters = []; $this->queryParameters = [];
if (!Tools::isNullOrEmpty($queryParameter)) { if (!Tools::isNullOrEmpty($queryParameter)) {
$localQueryParameters = explode(',', $queryParameter); $localQueryParameters = explode(self::SEPARATOR, $queryParameter);
foreach ($localQueryParameters as $localQueryParameter) { foreach ($localQueryParameters as $localQueryParameter) {
$localQueryParameter = trim($localQueryParameter); $localQueryParameter = trim($localQueryParameter);
......
...@@ -9,22 +9,31 @@ use Psr\Log\LoggerAwareInterface; ...@@ -9,22 +9,31 @@ use Psr\Log\LoggerAwareInterface;
use Psr\Log\LoggerAwareTrait; use Psr\Log\LoggerAwareTrait;
use Symfony\Contracts\EventDispatcher\Event; use Symfony\Contracts\EventDispatcher\Event;
class LocalDataAwarePostEvent extends Event implements LoggerAwareInterface class LocalDataPostEvent extends Event implements LoggerAwareInterface
{ {
use LoggerAwareTrait; use LoggerAwareTrait;
/** @var LocalDataAwareInterface */ /** @var LocalDataAwareInterface */
private $entity; private $entity;
/** @var array */
private $sourceData;
/** @var array */ /** @var array */
private $requestedAttributes; private $requestedAttributes;
protected function __construct(LocalDataAwareInterface $entity) public function __construct(LocalDataAwareInterface $entity, array $sourceData)
{ {
$this->entity = $entity; $this->entity = $entity;
$this->sourceData = $sourceData;
}
public function getSourceData(): array
{
return $this->sourceData;
} }
protected function getEntityInternal(): LocalDataAwareInterface public function getEntity(): LocalDataAwareInterface
{ {
return $this->entity; return $this->entity;
} }
...@@ -100,7 +109,7 @@ class LocalDataAwarePostEvent extends Event implements LoggerAwareInterface ...@@ -100,7 +109,7 @@ class LocalDataAwarePostEvent extends Event implements LoggerAwareInterface
if ($arrayKey === false) { if ($arrayKey === false) {
if ($warnfNotFound) { if ($warnfNotFound) {
if ($this->logger !== null) { if ($this->logger !== null) {
$this->logger->warning(sprintf("trying to set local data attribute '%s', which was not requested for entity '%s'", $key, LocalDataAwareEventDispatcher::getUniqueEntityName(get_class($this->entity)))); $this->logger->warning(sprintf("trying to set local data attribute '%s', which was not requested for entity '%s'", $key, LocalDataEventDispatcher::getUniqueEntityName(get_class($this->entity))));
} }
assert(false); assert(false);
} else { } else {
......
...@@ -6,7 +6,7 @@ namespace Dbp\Relay\CoreBundle\LocalData; ...@@ -6,7 +6,7 @@ namespace Dbp\Relay\CoreBundle\LocalData;
use Symfony\Contracts\EventDispatcher\Event; use Symfony\Contracts\EventDispatcher\Event;
class LocalDataAwarePreEvent extends Event class LocalDataPreEvent extends Event
{ {
public const NAME = 'dbp.relay.relay_core.local_data_aware_event.pre'; public const NAME = 'dbp.relay.relay_core.local_data_aware_event.pre';
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment