-
-
Notifications
You must be signed in to change notification settings - Fork 189
Allow Event Listeners the ability to modify context information in the event #233
Allow Event Listeners the ability to modify context information in the event #233
Conversation
Personally I'm 👍 |
Any chance we can prioritize this? I've been on a private fork for a while now and this has been an extremely valuable technique for us. I'd like to get back on the main line. |
Sorry, I was looking at this the other day but didn't get around with it. While I'm not sure what (besides "we're too slow to implement new MongoDB features" ;)) it could be used for, I don't see a problem adding this. My only question is, why only for update? Why not add it for all other query events as well? |
It may be useful for the other query types. In my use case, it seemed this technique was useful for setting a $comment on my write queries. |
Shall I take a stab at completing this feature? We'd like to see this make it into the next tag that Doctrine ships. |
don't want to spoil all the fun, but this requires tests :-) |
After a first look, I think this definitely needs tests to ensure the changed values are used for queries, not the originals. |
@alcaeus My strategy in the PR was to find any place where there's a "do" command such as doGroup, doFindOne() etc were the listener received variables that are subsequently passed into the "do" function. For tests, each event class that I changed now has tests (such as in FindEventArgsTest.php) to ensure that if a change is made (via my new set functions) that it is correctly returned when the getter is called. The only thing I'm not specifically testing for (and I don't think the current codebase is testing for either) is if the final integration works between the Collection.php class and the Event Listener calls I modified. I suppose I could setup a test where I register a listener on every one of the functions I modified where my listener changes each of the variables and then I mock out the "do" function in order to ensure that the change is detected. If you think that is necessary, please say so and I'll do it. |
I'm not sure you'd need a mock; I think functional tests should do:
Since this is the center of your logic, there should be tests for it as @beberlei mentioned :) |
Sorry if this sounds pedantic but I think the proper test here would not need to fire a real database query. I think the test should be able to prove that "If an event handler tries to change the $query, $newObj, $options, or whatever that was changed via my new event setters, that by the time the do() function fires, we receive the changed value." |
Just pushed the rest of the tests to this PR: 3ea9c65 |
@@ -63,4 +63,14 @@ public function getOptions() | |||
{ | |||
return $this->options; | |||
} | |||
|
|||
public function setPipeline(array $pipeline) |
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.
Even though the rest of the methods don't have docblocks, I think we can improve that one and add docblocks to the event args classes. Would you mind doing that?
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.
Done.
*/ | ||
public function getOptions() | ||
{ | ||
return $this->options; | ||
} | ||
|
||
/** | ||
* @param array $pipeline |
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.
Not to be pedantic, but you're missing a @since
tag here :)
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.
Should I add @SInCE on all of the functions that I added?
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.
Yes, please. That helps people identify when stuff was added.
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.
ok all set
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.
Since we add new public methods in a backwards compatible way, Semantic Versioning requires this change to be in a minor version increment. That makes it @since 1.3
.
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.
Done
I just confirmed that this change set works with my app when I try to use it to set a mongodb $comment. |
👍 FWIW, once this is released you might as well use the |
Seeking confirming from the maintainers that there are no additional changes requested. |
I was waiting for @jmikola to take a look at this before merging it. Due to conference travels this might take another few days. |
Kindly seeking review by @jmikola when he's got some time. Thank you! ;) |
Kindly seeking review by @jmikola .. thank you |
$this->eventManager->dispatchEvent(Events::preBatchInsert, new EventArgs($this, $a, $options)); | ||
$eventArgs = new EventArgs($this, $a, $options); | ||
$this->eventManager->dispatchEvent(Events::preBatchInsert, $eventArgs); | ||
$a = $eventArgs->getData(); |
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.
Since EventArgs doesn't take its arguments by reference, I wanted to confirm that this would work with batchInsert()
's by-reference parameter. According to https://3v4l.org/4O6VL, re-assigning $a
seems to have the desired effect of passing the changes back on to the calling context (I'm admittedly a bit rusty on the ins and outs of PHP references :)
I'll assume this is fine for insert()
and save()
as well.
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.
I also believe this will work as desired.
Left some notes above for small fixes, but nothing major. One separate concern (not tied to a particular line of code) is that we already have MutableEventArgs to allow listeners for change results from the Collection methods. Additionally, that class has logic to check if some event data has actually changed (calculated in I wasn't able to find any events in DBAL and ORM for modifying database operations (i.e. queries), so there's probably not a similar API to compare this to -- I'm also not sure if/how they allow services to hook in and modify queries. In any event, I wonder if we should leave EventArgs as-is and just start using MutableEventArgs, since the class already exists. Then the immutable EventArgs would remain in place for its other use cases, such as connection events. Beyond that, is there value in having |
@jmikola As for the MutableEventArgs vs. EventArgs, that's your call. In my case, I have already done the full regression test with this branch against my project and I can see everything works as expected so I'm just excited to see this ship so we can get back on the main line and off of our fork. |
@jmikola Just wanted to triple check there's no other actions you are requesting of me on this ticket. We are very excited to see this hit the main line asap. |
I'm alright with adding setters to the named event classes (e.g. AggregateEventArgs), but I'd like to bring up one last point about EventArgs and MutableEventArgs. For the record, MutableEventArgs dates back to 161be2d and #94. On a side note, while it'd be nice if we had an interface to denote whether an event class was mutable or immutable, nothing of the sort exists at the moment and extending MutableEventArgs doesn't make sense since it only concerns itself with tracking changes to the Let's start by reviewing places where EventArgs is used:
I'd prefer to leave EventArgs immutable and change some of these events to use MutableEventArgs (with the addition of a
There is a potential caveat with preBatchInsert, preInsert, and preSave, since For that reason, I'd prefer to see preBatchInsert, preInsert, and preSave left as-is and continue to use immutable EventArgs and change only the following to use MutableEventArgs:
This would still allow you flexibility to modify the queries used in deletes and updates, which may be all that your original use case required (of the methods dispatching EventArgs). |
This reverts earlier changes that added mutability to EventArgs (among other named event classes). In the interest of keeping EventArgs immutable, we'll now use MutableEventArgs for those methods that would benefit from it. Note: preBatchInsert, preInsert, and preSave will continue to use immutable EventArgs for their inputs, due to the fact that the driver is prone to modifying the input arguments in memory (this is different than by-reference modification). If we allowed an event listener to mutate that argument, users would no longer be able to rely on "_id" injection on the value passed into the Collection method.
This may have been an oversight when MutableEventArgs were originally added in 161be2d; however, there's no reason these events cannot be mutable in the interest of consistency with other method events.
As I stated on lyft#1, this change is fine so long as I can modify the query object within the collectionPreUpdate event. |
Keep EventArgs immutable and selectively use MutableEventArgs
@blockjon: I don't expect any conflict with your needs. We're only using MutableEventArgs for preFindAndRemove, preRemove, postRemove, and postUpdate. The preBatchInsert, preInsert, and preSave events stick with immutable events (for reasons I cited in my previous post). All of the other events objects (including preUpdate) are using their respective event objects, which are now mutable per your own patch. 👍 |
Merged manually. Thank you @blockjon for your contribution! |
I am trying to automatically add a useful MongoDB $comment (http://docs.mongodb.org/manual/reference/operator/meta/comment/) to my project whenever a Mongo update takes place. In order to do this, it appears that I will need to slightly modify the query before it is executed against the mongo driver.
It appears that the most elegant way for me to do this would be to register a listener on the collectionPreUpdate event within my project with code that looks roughly like this:
Doctrine/mongodb was not designed to allow the event hooks to modify the query as part of the events system. However, I submit to you all that this is a situation in where allowing me to customize the query before it's executed is extremely useful. I'm submitting this PR as an example of something I'm trying to accomplish and asking for your advise on if there is a better way to do this currently, or, if perhaps we should have something like this built into the repo.