-
Notifications
You must be signed in to change notification settings - Fork 62
Feature/embedded entities #1682
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
Conversation
dd23495 to
c6a9e55
Compare
c6a9e55 to
97f7408
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ich finde den Vorschlag grundsätzlich gut. Statt Properties:read / Properties:write könnte ich mir auch Any:read / Any:write vorstellen, da man es dann immer als eine Einschränkung nach Root Entity Klasse lesen kann. Aber zugegebenermassen wird das wohl fast immer nur für primitive Properties verwendet, daher wäre auch dein Vorschlag okay für mich.
Eine Limitierung dieses Systems mit den Groups tritt auf, wenn man rekursive Datenstrukturen hat. Z.B. wenn wir die children eines ContentNodes mit writableLink: true markieren würden, also nested POST / nested PATCH erlauben würden, dann könnte man nicht separate Regeln für Payload-Root und nested Children festlegen.
Ein anderes Beispiel wo das vielleicht schlimmer sein könnte, wäre wenn wir z.B. MaterialItem und MaterialList gegenseitig nested schreibbar machen. Wenn ich dann ein MaterialItem patche ist die Group MaterialItem:write aktiv. Im Payload könnte ich also nested die MaterialList und darin nested ein beliebiges anderes MaterialItem mitsenden und so mitbearbeiten.
Aber ich glaube solange wir writableLink: true nur sparsam und bedacht einsetzen, sollte das in der Praxis kein grosses Problem sein.
|
Allgemeine Notiz: Diese versucht anhand einer API-Resource einen Beispiel-Payload automatisch zu erzeugen. Die Schema-Namen der Api-Resourcen ändern jedoch zusammen mit den Groups. Das führt dazu, dass diese Schema-Namen je nach refactoring immer wieder ändern können / nicht stabil sind. -> Bitte diskutieren. |
| return $this->days; | ||
| } | ||
|
|
||
| #[ApiProperty(readableLink: true)] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Bei getEmbeddedDays hast du ein Example drin, hier nicht. Müsste man das ergänzen oder fällt er zurück auf das Example der Property?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Bei den getEmbedded* Methoden brauchts kein Example, das wird sowieso nicht in Swagger angezeigt. Stattdessen werden, wenn man den Return Type korrekt annotiert, die eingebetteten Felder perfekt automatisch angezeigt, inklusive den korrekten Normalisierungs-Gruppen 🥳
/**
* @return Day[]
*/
#[ApiProperty(readableLink: true)]
#[SerializedName('days')]
#[Groups('Period:Days')]
public function getEmbeddedDays(): array {
return $this->days->getValues();
}
#[ApiProperty(readableLink: true)]
#[SerializedName('camp')]
#[Groups(['Period:Camp'])]
public function getEmbeddedCamp(): ?Camp {
return $this->camp;
}…ferent operations
Also, deactivate the automatic embedding feature of API platform, because with our serialization groups system, everything would always get embedded everywhere. We want to only activate embedding selectively.
This is until api-platform/core#4377 is merged, see that PR and api-platform/core#2444 for details.
carlobeltrame
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ich habe die Tests gefixt und die vorgeschlagenen Gruppen bei allen Entities eingefügt.
Danach hat API Platform automatisch mal sämtliche Relationen embedded, auch alle die wir nicht so markiert haben. Bei der Fehlersuche bin ich auf ein verstecktes Stück Dokumentation gestossen, und mir ist einiges in Bezug auf Embedding in API Platform klarer geworden.
Automatisch embedded (d.h. automatisch readableLink=true) wird eine Relation dann, wenn 1. die Relation selber durch die aktiven Gruppen lesbar ist und 2. zumindest ein Feld in der related Entity durch die aktiven Gruppen lesbar ist. Normalerweise schlägt API Platform vor (implizit in den Docs und explizit in den SymfonyCasts), Serialisierungsgruppen ala camp:update, period:read zu verwenden. Bei uns ist aber der Vorschlag, update, read etc. zu verwenden. Dadurch sind beide obigen Konditionen gegeben, und alles wird überall automatisch embedded.
Ich finde unseren Ansatz trotzdem noch spannend wegen der Eleganz mit der Camp:Periods Config die er für unseren Fall bietet. Um das so zum fliegen zu bringen, musste ich daher ein paar Anpassungen an API Platform vornehmen. Eine davon ist in api-platform/core#4377 bei API Platform angebracht (aber bei uns vorgeholt), die anderen (CircularReferenceDetectingHalItemNormalizer, PreventAutomaticEmbeddingPropertyMetadataFactory) sind spezifisch für unseren Fall, die habe ich nur bei uns implementiert.
To discuss: Halten wir an unserem Vorschlag für Serializer Groups fest und unterhalten diese Abweichungen selber, oder gehen wir zurück zum inoffiziellen Standard?
a3ecaac to
b0cb899
Compare
carlobeltrame
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Wäre jetzt nie darauf gekommen, aber b0cb899 hat tatsächlich die Tests gefixt. Merci @pmattmann
Jooo... war auch nicht einfach, den zu finden... musste ich ordentlich tief debuggen gehen... |
|
Die Coverage geht leider um 1.1 Prozent runter für api. |
|
Die eagerloadingextension ist wohl dafür verantwortlich. Die ist eigentlich nur temporär bei uns drin, bis api-platform/core#4377 gemerged und released ist. Wir könnten höchstens tests dafür noch bei uns reinmachen. |
The EagerLoadingExtension is only temporarily in our codebase, until api-platform/core#4377 is merged and released. There are tests for this extension in API Platform core, so we shouldn't need to write our own test suite for it. However, because of our limited use cases so far, this class lowers the coverage too much. Therefore, I commented out some code of which I am certain we won't need it in the near future. Less untested code = higher coverage.
|
|
||
| $result = $this->contextBuilder->createFromRequest($request, false); | ||
|
|
||
| $this->assertNotEquals(['skip_null_values' => false], $result); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
minor:
Hätte ich jetzt eher positiv formuliert.
Falls möglich möchte ich wissen, was zurückgegeben wird. Nicht dass das $result nicht diesem Array entspricht.
|
|
||
| $result = $this->contextBuilder->createFromRequest($request, true); | ||
|
|
||
| $this->assertNotEquals(['allow_extra_attributes' => false], $result); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
minor:
Hätte ich jetzt eher positiv formuliert.
Falls möglich möchte ich wissen, was zurückgegeben wird. Nicht dass das $result nicht diesem Array entspricht.

#1579 Embedded Entities Beispiel aufbauen
Idee:
Es werden pro Entität jeweils folgende Serialization-Groups angelegt:
Ist bei allen Lese-Operationen aktiv.
Properties markiert mit read werden immer ausgegeben
Ist bei allen Schreib-Operationen aktiv.
Properties markiert mit write sind immer schreibbar (post & patch)
ist bei Post-Operation aktiv
Properties markeirt mit create sind nur beim erstellen schreibbar (post)
Ist bei Patch-Operation aktiv
Properties markiert mit update sind änderbar (patch)
Zusätzlich werden Serialization-Groups pro Relation Quelle:Ziel erstellt.
Diese erlauben selektives embedden von solchen Relationen.
Damit die Relation selektiv embedded werden kann, wird jeweils das Property der Relation mit #[ApiProperty(readableLink:false)] markiert.
Zusätzlich wird eine Getter-Methode getEmbeddedXYZ() erstellt. Diese wird mit #[ApiProperty(readableLink:true)] und #[Groups(Quelle:Ziel)] markiert.
Siehe Beispiele:
Durch angeben von Relationen Quelle:Ziel im normalizationContext kann bestimmt werden, ob eine Relation embedded werden soll, oder nicht.