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

localData mechanism docu

parent da80e649
No related branches found
No related tags found
No related merge requests found
Pipeline #103269 passed
#Local Data #Local Data
Local data provides a mechanism to extend base-entities by attributes which are not part of the entities default set of attributes. Local data can be added in custom base-entity (post-)event subscribers. Local data provides a mechanism to extend entities by attributes which are not part of the entities default set of attributes. Local data can be added in custom entity (post-)event subscribers.
## Local Data requests ## Local Data requests
Local data can be requested using the `inlucde` parameter provided by base-entity GET operations by default. The format is the following: Local data can be requested using the `inlucde` parameter provided by entity GET operations. The format is the following:
```php ```php
include=<ResourceName>.<attributeName>,... include=<ResourceName>.<attributeName>,...
``` ```
It is a comma-separated list of 0 ... n `<ResourceName>.<attributeName>` pairs. Note that `ResourceName` is the `shortName` defined in the `ApiResource` annotation of an entity. The backend will return an error if It is a comma-separated list of 0 ... n `<ResourceName>.<attributeName>` pairs, where `ResourceName` is the `shortName` defined in the `ApiResource` annotation of an entity. The list may contain attributes form different resources.
The backend will return an error if
* The `shortName` of the entity contains `.` or `,` characters
* The format of the `include` parameter is invalid * The format of the `include` parameter is invalid
* Any of the requested attributes could not be provided * Any of the requested attributes could not be provided
* The backend tries to set an attribute which was not requested * The backend tried to set an attribute which was not requested
##Adding local data attributes ##Adding Local Data Attributes to Existing Entities
Integraters have to make sure that local attributes requested by their client applications are added in the backend. This can be done in custom base-entity event subscribers. Integraters have to make sure that local attributes requested by their client applications are added in the backend. This can be done in custom entity (post-)event subscribers:
```php ```php
class BaseEntityEventSubscriber implements EventSubscriberInterface class EntityEventSubscriber implements EventSubscriberInterface
{ {
public static function getSubscribedEvents(): array public static function getSubscribedEvents(): array
{ {
return [ return [
BaseEntityPostEvent::NAME => 'onPost', EntityPostEvent::NAME => 'onPost',
]; ];
} }
public function onPost(BaseEntityPostEvent $event) public function onPost(EntityPostEvent $event)
{ {
$data = $event->getBaseEntityData(); $data = $event->getSourceData();
if ($event->isLocalDataAttributeRequested('foo')) { $event->trySetLocalDataAttribute('foo', $data->getFoo());
$event->setLocalDataAttribute('foo', $data->getFoo());
}
} }
} }
``` ```
Events of built-in entities provide a `getSourceData()` and a `getEntity()` method by convention, where
* `getSourceData()` provides the full set of available attributes for the entity
* `getEntity()` provides the entity itself
The event's `trySetLocalDataAttribute` method provides a convient way for setting attributes without causing an error in case the attribute was not requested by the client.
Note that local data values have to be serializable to JSON.
##Creating Local Data aware Entities ##Creating Local Data aware Entities
You can easily add Local Data to your Entity (`MyEntity`) by: You can easily add local data to your Entity (`MyEntity`) by:
* Using the `LocalDataAwareTrait` in `MyEntity` * Using the `LocalDataAwareTrait` in `MyEntity`
* Implementing the `LocalDataAwareInterface` in `MyEntity` * Implementing the `LocalDataAwareInterface` in `MyEntity`
* Adding the `LocalData:output` group to the normalization context of `MyEntity` * Adding the `LocalData:output` group to the normalization context of `MyEntity`. For example:
* Adding an event dispatcher of type `LocalDataAwareEventDispatcher` to your Entity provider ```php
normalizationContext={"groups" = {"MyEntity:output", "LocalData:output"}}
```
* Adding an event dispatcher member variable of type `LocalDataAwareEventDispatcher` to your entity provider
* On GET-requests, passing the value of the `include` parameter to the event dispatcher * On GET-requests, passing the value of the `include` parameter to the event dispatcher
```php ```php
$this->eventDispatcher->initRequestedLocalDataAttributes($includeParameter); $this->eventDispatcher->initRequestedLocalDataAttributes($includeParameter);
``` ```
* Creating a (post-)event `MyEntityPostEvent` extending the `LocalDataAwareEvent`, which you pass to the event dispatcher once your Entity provider is done setting up a new instance of `MyEntity`: * Creating a (post-)event `MyEntityPostEvent` extending `LocalDataAwareEvent`, which you pass to the event dispatcher's `dispatch` method once your entity provider is done setting up a new instance of `MyEntity`:
```php ```php
// get some data // get some data
$myEntityData = $externalApi->getEntityData($identifier); $mySourceData = $externalApi->getSourceData($identifier);
// craete a new instance of MyEntity
$myEntity = new MyEntity(); $myEntity = new MyEntity();
// first, set the default attributes: // first, set the entity's default attributes:
$myEntity->setIdentifier($myEntityData->getIdentifier()); $myEntity->setIdentifier($mySourceData->getIdentifier());
$myEntity->setName($myEntityData->getName()); $myEntity->setName($mySourceData->getName());
// now, for custom attributes:
$postEvent = new MyEntityPostEvent($myEntity, $myEntityData); // now, fire the event allowing event subscribers to add local data attributes
$this->eventDispatcher->dispatch($postEvent); $postEvent = new MyEntityPostEvent($myEntity, $mySourceData);
$this->eventDispatcher->dispatch($postEvent, MyEntityPostEvent::NAME);
return $myEntity;
``` ```
In case your entity has nested entities (sub-resources), your entity provider is responsible of passing the `include` parameter to sub-resource providers.
\ No newline at end of file
...@@ -20,6 +20,11 @@ class LocalDataAwareEvent extends Event ...@@ -20,6 +20,11 @@ class LocalDataAwareEvent extends Event
$this->entity = $entity; $this->entity = $entity;
} }
public function getEntity(): LocalDataAwareInterface
{
return $this->entity;
}
/** /**
* Sets the list of requested local data attribute names for this event's entity. * Sets the list of requested local data attribute names for this event's entity.
* *
...@@ -51,15 +56,19 @@ class LocalDataAwareEvent extends Event ...@@ -51,15 +56,19 @@ class LocalDataAwareEvent extends Event
*/ */
public function setLocalDataAttribute(string $key, $value): void public function setLocalDataAttribute(string $key, $value): void
{ {
$arrayKey = array_search($key, $this->requestedAttributes, true); $this->setLocalDataAttributeInternal($key, $value, true);
if ($arrayKey === false) {
// TODO: maybe ignore or just emit warning?
throw new ApiError(500, sprintf("trying to set local data attribute '%s', which was not requested for entity '%s'", $key, LocalDataAwareEventDispatcher::getUniqueEntityName(get_class($this->entity))));
} }
// once set, remove the attribute from the list of requested attributes /**
array_splice($this->requestedAttributes, $arrayKey, 1); * Tries to set a local data attribute of this event's entity and removes it from the list of requested attributes.
$this->entity->setLocalDataValue($key, $value); *
* @parem string $key The name of the attribute.
*
* @param mixed|null $value the value for the attribute
*/
public function trySetLocalDataAttribute(string $key, $value): void
{
$this->setLocalDataAttributeInternal($key, $value, false);
} }
/** /**
...@@ -71,4 +80,29 @@ class LocalDataAwareEvent extends Event ...@@ -71,4 +80,29 @@ class LocalDataAwareEvent extends Event
{ {
return in_array($key, $this->requestedAttributes, true); return in_array($key, $this->requestedAttributes, true);
} }
/**
* Sets a local data attribute of this event's entity and removes it from the list of requested attributes.
*
* @parem string $key The name of the attribute.
*
* @param mixed|null $value the value for the attribute
*
* @throws ApiError if attribute $key is not in the set of requested attributes
*/
private function setLocalDataAttributeInternal(string $key, $value, bool $throwIfNotFound): void
{
$arrayKey = array_search($key, $this->requestedAttributes, true);
if ($arrayKey === false) {
if ($throwIfNotFound) {
throw new ApiError(500, sprintf("trying to set local data attribute '%s', which was not requested for entity '%s'", $key, LocalDataAwareEventDispatcher::getUniqueEntityName(get_class($this->entity))));
} else {
return;
}
}
// once set, remove the attribute from the list of requested attributes
array_splice($this->requestedAttributes, $arrayKey, 1);
$this->entity->setLocalDataValue($key, $value);
}
} }
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment