Skip to content

alwaysIdentifier annotation option implementation #1528

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jan 15, 2018
Merged

alwaysIdentifier annotation option implementation #1528

merged 1 commit into from
Jan 15, 2018

Conversation

adelplace
Copy link

@adelplace adelplace commented Nov 28, 2017

Q A
Bug fix? no
New feature? yes
BC breaks? no
Deprecations? no
Tests pass? yes
Fixed tickets #1130
License MIT
Doc PR api-platform/docs#373

The goal here is to allow the users to display only the IRI of a nested resource. It's very usefull on trees or on big entities which have multiple links on a same other entity.

As the MaxDepth annotation doesn't allow us to do that I have created a new annotation option :

/**
 * @ApiResource(attributes={
 *     "normalization_context"={"groups": {"alwaysIdentifierGroup"}, "enable_always_identifier"=true}
 * })
 * @ORM\Entity
 */
class AlwaysIdentifierDummy 
{
    /**
     * @var ArrayCollection children dummies
     *
     * @ORM\ManyToMany(targetEntity="AlwaysIdentifierDummy")
     * @ApiProperty(alwaysIdentifier=true)
     * @Groups({"alwaysIdentifierGroup"})
     */
    private $children;
}

Will be displayed as :

{
      "children": [
          "/always_identifier_dummies/1"
      ]
}

I don't know if this work fit with the project guidelines but i would be happy to discuss about it ;)

@soyuka
Copy link
Member

soyuka commented Nov 29, 2017

We're successfully doing this by using groups and max depth. (going to check that anyway, coming back with an answer soon).

Nevermind I don't think we managed to do it.

What about using an attribute of @ApiProperty instead of a new annotation? For example @ApiProperty(skip_serialization=true) (not sure about the key).

I'm not fond of the word IriOnly by the way because we have to keep in mind that IRI's are related to JSON-ld and sometimes we might just want id's properties (ie force to skip serialization of the property).

@adelplace
Copy link
Author

What about using an attribute of @ApiProperty instead of a new annotation? For example @ApiProperty(skip_serialization=true) (not sure about the key).

Yes it would surely be a better solution.

I'm not fond of the word IriOnly by the way because we have to keep in mind that IRI's are related to JSON-ld and sometimes we might just want id's properties (ie force to skip serialization of the property).

I'll look to implement it on the other formats.

*
* @return bool
*/
private function isIriOnlyItem(array &$context)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is $context passed by reference?

*
* @return bool
*/
private function isIriOnlyAttribute($propertyMetadata, array &$context)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is $context passed by reference?

private function isIriOnlyAttribute($propertyMetadata, array &$context)
{
return
isset($context[static::ENABLE_IRI_ONLY]) &&
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This class is final, use self instead of static.

@adelplace adelplace changed the title ApiIriOnly annotation implementation SerializationSkipping annotation option implementation Dec 27, 2017
@adelplace
Copy link
Author

@soyuka @meyerbaptiste
The changes have been done, tell me if it's better. I also added tests for json and hal formats.

$annotation->attributes
$annotation->attributes,
null,
$annotation->skipSerialization
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think that the word "serializable" would be better:

isSerializable
withSerializable
serializable

*
* @return bool
*/
private function isSkippedSerializationAttribute($propertyMetadata, array $context)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

isPropertySerializable

Also missing typehints and you can remove the block comments (@param/@return):

function isPropertySerializable(PropertyMetadata $propertyMetadata, array $context): bool 
{}

Then negate: !$this->isPropertySerializable(...)

*
* @return bool
*/
protected function isItemSerializationShouldBeSkipped(array $context)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

shouldSkipSerialization same you can add a return type :bool and remove @param/@return.

@dunglas
Copy link
Member

dunglas commented Dec 28, 2017

What about always_id instead? I don't like the "skip serialization" term because the serialization is actually not skipped. To me it would mean "just skip this property", here it is serialized in a special type: an IRI (btw, IRI is a generic term; not specific to JSON-LD: https://en.wikipedia.org/wiki/Internationalized_Resource_Identifier)

@soyuka
Copy link
Member

soyuka commented Dec 28, 2017

👍 @dunglas , I'd propose in the metadata:

isAlwaysIdentifier
withAlwaysIdentifier
alwaysIdentifier

@adelplace adelplace changed the title SerializationSkipping annotation option implementation alwaysIdentifier annotation option implementation Dec 29, 2017
@adelplace
Copy link
Author

adelplace commented Dec 29, 2017

@soyuka @dunglas
Done ;)

@@ -0,0 +1,118 @@
@skip
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why skip?

/**
* Returns a new instance with the given alwaysIdentifier flag.
*
* @param bool $alwaysIdentifier
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can remove both @param and @return, they are useless because of the typehints.

@@ -97,9 +100,21 @@ public function normalize($object, $format = null, array $context = [])
$context['resources'][$resource] = $resource;
}

if ($this->isAlwaysIdentifierItem($context)) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you inline this one? We try to reduce the number of function calls in the serialization process (which is recursive) because a function call is costly:

if (($context[self::ALWAYS_IDENTIFIER_KEY] ?? false) && ($context[self::ALWAYS_IDENTIFIER_KEY] ?? false))

Same for isAlwaysIdentifierProperty, I would drop these methods.

@@ -39,6 +39,9 @@
{
use ContextTrait;

const ENABLE_ALWAYS_IDENTIFIER = 'enable_always_identifier';
const ALWAYS_IDENTIFIER_KEY = 'always_identifier_key';
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We use the _key suffix nowhere. Can you drop it?

* @author Alexandre Delplace <[email protected]>
*
* @ApiResource(attributes={
* "normalization_context"={"groups"={"alwaysIdentifierGroup"}, "enable_always_identifier"=true}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do we need this enable_always_identifier flag? IMO we can remove it, if the alwaysIdentifier is set on a property, we use it, that's all, it doesn't make sense to allow to disable this feature. If you don't want to use it, just don't set the flag.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I took example from the max_depth implementation. I'll remove it

@@ -0,0 +1,117 @@
Feature: AlwaysIdentifier support
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

May I suggest: Feature: allow resources in properties to always be serialized as identifiers

}
"""

Scenario: Check the json formatted response
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

JSON

"""
{
"children": [
"\/always_identifier_dummies\/1"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you drop the \ please (for readability), same for all others.

}
"""

Scenario: Check the hal formatted response
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

HAL

"""

@dropSchema
Scenario: Delete a resource
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is not necessary (this is not related to this feature and already tested). @dropSchema will already destroy the database.

@@ -0,0 +1,117 @@
Feature: AlwaysIdentifier support
In order to use a hypermedia API
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can create a new context method in FeatureContext like https://github.com/api-platform/core/blob/master/features/bootstrap/FeatureContext.php#L125 to create new AlwaysIdentifiersDummies, remove the create and delete scenarios, and move the scenarios for each format (JSON-LD, HAL, JSON) in the corresponding directories (we prefer to group tests per format instead of per feature, it will help when we will create a subtree split).

@adelplace
Copy link
Author

@dunglas done. I also added a json folder in the features because I didn't find a specific one for this format.

@dunglas dunglas merged commit 98955bc into api-platform:master Jan 15, 2018
@dunglas
Copy link
Member

dunglas commented Jan 15, 2018

Thanks @adelplace

symfony-splitter pushed a commit to symfony/framework-bundle that referenced this pull request Feb 19, 2018
This PR was squashed before being merged into the 4.1-dev branch (closes #26108).

Discussion
----------

[Serializer] Add a MaxDepth handler

| Q             | A
| ------------- | ---
| Branch?       | master
| Bug fix?      | no
| New feature?  | yes <!-- don't forget to update src/**/CHANGELOG.md files -->
| BC breaks?    | no
| Deprecations? | no <!-- don't forget to update UPGRADE-*.md files -->
| Tests pass?   | yes
| Fixed tickets | api-platform/core#1130, api-platform/core#1528, api-platform/core#1528 <!-- #-prefixed issue number(s), if any -->
| License       | MIT
| Doc PR        | todo <!--highly recommended for new features-->

Sometimes, instead of just stopping the serialization process when the configured max depth is reached, it can be interesting to let the user return something (like returning the identifier of the entity to stop manually the serialization process).

This PR also makes the max depth handling more similar to circular references handling (that already has the possibility to set a handler).

Commits
-------

ed975c764b [Serializer] Add a MaxDepth handler
symfony-splitter pushed a commit to symfony/serializer that referenced this pull request Feb 19, 2018
This PR was squashed before being merged into the 4.1-dev branch (closes #26108).

Discussion
----------

[Serializer] Add a MaxDepth handler

| Q             | A
| ------------- | ---
| Branch?       | master
| Bug fix?      | no
| New feature?  | yes <!-- don't forget to update src/**/CHANGELOG.md files -->
| BC breaks?    | no
| Deprecations? | no <!-- don't forget to update UPGRADE-*.md files -->
| Tests pass?   | yes
| Fixed tickets | api-platform/core#1130, api-platform/core#1528, api-platform/core#1528 <!-- #-prefixed issue number(s), if any -->
| License       | MIT
| Doc PR        | todo <!--highly recommended for new features-->

Sometimes, instead of just stopping the serialization process when the configured max depth is reached, it can be interesting to let the user return something (like returning the identifier of the entity to stop manually the serialization process).

This PR also makes the max depth handling more similar to circular references handling (that already has the possibility to set a handler).

Commits
-------

ed975c764b [Serializer] Add a MaxDepth handler
fabpot added a commit to symfony/symfony that referenced this pull request Feb 19, 2018
This PR was squashed before being merged into the 4.1-dev branch (closes #26108).

Discussion
----------

[Serializer] Add a MaxDepth handler

| Q             | A
| ------------- | ---
| Branch?       | master
| Bug fix?      | no
| New feature?  | yes <!-- don't forget to update src/**/CHANGELOG.md files -->
| BC breaks?    | no
| Deprecations? | no <!-- don't forget to update UPGRADE-*.md files -->
| Tests pass?   | yes
| Fixed tickets | api-platform/core#1130, api-platform/core#1528, api-platform/core#1528 <!-- #-prefixed issue number(s), if any -->
| License       | MIT
| Doc PR        | todo <!--highly recommended for new features-->

Sometimes, instead of just stopping the serialization process when the configured max depth is reached, it can be interesting to let the user return something (like returning the identifier of the entity to stop manually the serialization process).

This PR also makes the max depth handling more similar to circular references handling (that already has the possibility to set a handler).

Commits
-------

ed975c7 [Serializer] Add a MaxDepth handler
hoangnd25 pushed a commit to hoangnd25/core that referenced this pull request Feb 23, 2018
…tation

alwaysIdentifier annotation option implementation
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants