Uh oh!
There was an error while loading. Please reload this page.
WIP: Add events - #2329
Conversation
alanpoulain
commented
Nov 15, 2018
Thanks for working on this 🙂 |
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
f2c5977 to
3d505ebCompare| $this->validate($item, $info, $resourceMetadata, $operationName); | ||
| if (null !== $this->dispatcher) { | ||
| $this->dispatcher->dispatch(PreWriteEvent::NAME, new PreWriteEvent($operationName, $item)); |
There was a problem hiding this comment.
Guess there will be an issue here, since the $operationName from GraphQL (create, update, delete) is not the same as the HTTP methods used in REST
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
antograssiot
left a comment
There was a problem hiding this comment.
Would it be useful too to have PreValidate and PostValidate events to keep the same logic than in REST ?
core/src/GraphQl/Resolver/Factory/ItemMutationResolverFactory.php
Lines 130 to 134 in d678481
| $this->dispatcher->dispatch(PostReadEvent::NAME, new PostReadEvent($item)); | ||
| } | ||
| } catch (ItemNotFoundException $e) { | ||
| return null; |
There was a problem hiding this comment.
wouldn't it be better to change this block to
try {
if (null !== $this->dispatcher) {
$this->dispatcher->dispatch(PreReadEvent::NAME, newPreReadEvent(null));
}
$item = $this->iriConverter->getItemFromIri($args['id'], $baseNormalizationContext);
} catch (ItemNotFoundException$e) {
$item = null;
}
if (null !== $this->dispatcher) {
$this->dispatcher->dispatch(PostReadEvent::NAME, newPostReadEvent($item));
}
if (null === $item) {
returnnull;
}to ensure that the PostReadEvent is always sent like in the ReadListener ?
There was a problem hiding this comment.
I don't think it should be dispatched when Read has failed.
dunglas
left a comment
There was a problem hiding this comment.
I think we can restrict the events to:
- read
- deserialize
- write
- validate
- serialize
Other ones are Symfony specific and should be handled using Symfony kernel events. WDYT?
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
@dunglas Sound good, but I think we should keep the pre- and post- events. |
b7cb661 to
ac09958CompareUh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
| const PRE_RESPOND = 'api_platform.pre_respond'; | ||
| const POST_RESPOND = 'api_platform.post_respond'; | ||
| const PRE_ADD_FORMAT = 'api_platform.pre_add_format'; |
There was a problem hiding this comment.
These events should be removed as they're not related to the resource.
There was a problem hiding this comment.
Please remove the "Add Format" events.
Uh oh!
There was an error while loading. Please reload this page.
| final class PreWriteEvent extends Event | ||
| { | ||
| const NAME = Events::PRE_WRITE; |
There was a problem hiding this comment.
This is a really weird thing to do. Did I miss the discussion on why this is done this way?
There was a problem hiding this comment.
You mean, defining a NAME constant in the classes?
I did it mainly for comfort purpose, actually: it makes more sense to me to use a constant attached to the concerned class, so I kept it after @dunglas asked me to create the separate Events class.
Do you want me to remove the NAME constants?
There was a problem hiding this comment.
I don't see the value of these constants. Just use e.g. Events::PRE_WRITE directly.
| <argument type="service" id="api_platform.security.resource_access_checker" on-invalid="null" /> | ||
| <argument type="service" id="request_stack" /> | ||
| <argument>%api_platform.collection.pagination.enabled%</argument> | ||
| <argument type="service" id="event_dispatcher" /> |
There was a problem hiding this comment.
You need to add the same on-invalid="null" in this file too.
| $identifiers = $this->extractIdentifiers($request->attributes->all(), $attributes); | ||
| if (null !== $this->dispatcher) { | ||
| $this->dispatcher->dispatch(PreReadEvent::NAME, new PreReadEvent($data)); |
There was a problem hiding this comment.
It's really weird to have data in Pre Read. I don't think it makes sense...
There was a problem hiding this comment.
Perhaps what we could do is to keep a reference to the event object, then check if the data is already set on the event. If it is set, we should not override it.
jamesisaac
commented
Dec 11, 2018
Very glad this is being worked on. Is the idea with not attaching the Also, with the current events system they're executed in a very predictable linear order. Am I understanding that due to the way GraphQL resolvers work (one entity at a time), these events can be executed more like |
Deuchnord
commented
Dec 19, 2018
Hi, sorry for the late, I forgot to answer when I saw your comment ^^
Actually, these events are supposed to be higher levelled than Symfony's ones, so they're meant to contain only the details about the data themselves. If you want to get details about the request itself, you'll probably want to intercept Symfony's events instead.
That GraphQL part is actually quite cryptic to me, I need to study that more… if you have any tips to make my integration of the events better, feel free to share them 🙂 |
jamesisaac
commented
Dec 19, 2018
No worries!
I thought one of the motivations here was that Symfony events aren't getting fired during the lifecycle of GraphQL requests (see #2167 )? So do you mean intercepting a combination of the 2? I.e. in a single listener, listen to Symfony's request event to store the route/method, then combine that with the data retrieved from this event, to execute the side effect? I just think that individually, these events with "only the details about the data", and Symfony's events which don't have the controller result, don't contain enough information to add granular side effects in a lot of real world cases. Both are needed together most of the time. |
Deuchnord
commented
Dec 21, 2018
Yes, that's what's planned ideally: an event that's risen, whenever the action comes from REST or GraphQL :)
I think I see what you mean, problem is, I'm not sure I can get that Symfony event, for the same reason we can't do it currently like described in #2167… We'll need to think more about it, maybe it would be a good thing to have an object that contain the information that may be useful and are available for both REST and GraphQL? |
jamesisaac
commented
Dec 21, 2018
When I wrote my own quick workaround for #2167 (master...jamesisaac:graphql-events), I just injected the To me that solution added a lot of convenience, as the data alone doesn't tell you the context of how that data is being reached in the API (not even whether it's a query or a mutation). But I know you mentioned these events are meant to be higher level, so maybe there's a separation of concerns I'm missing out on. |
What about adding to all the events an object that would be common to both REST and GraphQL, and would contain the context of the events? This way, you would get as many information as possible, without having to take care about Symfony's events being actually risen or not. Currently, I can see at least two things this event could store:
WDYT? Do you see any other thing that could be interesting to add in such an object? @dunglas and @teohhanhui, I'd be interested by your opinion about that too :) |
Uh oh!
There was an error while loading. Please reload this page.
jamesisaac
commented
Jan 29, 2019
That would be very helpful to me. In addition to your list, the things I make use of are:
|
9481ef2 to
03edea2CompareDeuchnord
commented
Apr 1, 2019
Closing this PR since a better implementation is proposed on #2506. |
Adding events to make API Platform’s actions tweaking easier.
Todos:
\ApiPlatform\Core\EventListener\*listeners)