-
Notifications
You must be signed in to change notification settings - Fork 2.5k
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
Ensure onFlush and postFlush events are always called #398
Conversation
$this->collectionUpdates || | ||
$this->collectionDeletions || | ||
$this->orphanRemovals)) { | ||
return; // Nothing to do. |
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.
What about raising postFlush
here instead? (and moving the triggering logic to its own protected method?)
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.
Whatever you prefer. Notice something similar should be done with onFlush
.
I don't think calling onFlush is a good idea when nothing is flushed. |
@stof I must agree it would be kind of expected by the user though... |
@Ocramius I don't think so: PreUpdate and PostUpdate are only triggered if there is an actual update. |
@stof then we should eventually change the docs at http://docs.doctrine-project.org/projects/doctrine-orm/en/latest/reference/events.html#lifecycle-events |
I still like the idea of the patch though :) |
@stof preUpdate and postUpdate are lifecycle callbacks (so being attached to the affected entities) while *Flush events are not. To my understanding *Flush events are tied to the fact a flush operation is being executed, not whether the flush ended persisting any changes. Also, if onFlush/postFlush events end up not being raised if there are no changes, preFlush should also not be raised (to keep the consistency). The same goes for other events like onClear, which now is raised even when nothing is cleared. |
@frosas there is also PreUpdate and PostUpdate events, not only lifecycle callbacks |
@stof oh I didn't noticed this, anyway I still think it is coherent: *Flush events are raised when a flush is executed and *Update events when updates are, event names talk by themselves :) If there is an interest to not change the current implementation I would at least change the event names to something like onFlushWithChanges and postFlushWithChanges. |
The chnage would be consinstent, you might have an event listener that makes changes and want a flush operation to trigger these changes. However the coding style of the PR is not aligned with Doctrine standards at all. Please rewrite the PR to using guard clauses and early exists instead of the huge realignment through the additional if clause. |
Yes, this big if clause is quite ugly and your (and @Ocramius) proposed changes looks fine to me. On the other hand commit() is 100 lines now, another option is to extract the code inside the if clause into its own method: <?php
public function commit($entity = null)
{
// Raise preFlush
if ($this->evm->hasListeners(Events::preFlush)) {
$this->evm->dispatchEvent(Events::preFlush, new Event\PreFlushEventArgs($this->em));
}
// Compute changes done since last commit.
if ($entity === null) {
$this->computeChangeSets();
} else {
$this->computeSingleEntityChangeSet($entity);
}
$anythingToDo =
$this->entityInsertions ||
$this->entityDeletions ||
$this->entityUpdates ||
$this->collectionUpdates ||
$this->collectionDeletions ||
$this->orphanRemovals;
if ($anythingToDo && $this->orphanRemovals) {
foreach ($this->orphanRemovals as $orphan) {
$this->remove($orphan);
}
}
// Raise onFlush
if ($this->evm->hasListeners(Events::onFlush)) {
$this->evm->dispatchEvent(Events::onFlush, new Event\OnFlushEventArgs($this->em));
}
if ($anythingToDo) {
$this->commitComputedChangesets();
}
// Raise postFlush
if ($this->evm->hasListeners(Events::postFlush)) {
$this->evm->dispatchEvent(Events::postFlush, new Event\PostFlushEventArgs($this->em));
}
// Clear up
$this->entityInsertions =
$this->entityUpdates =
$this->entityDeletions =
$this->extraUpdates =
$this->entityChangeSets =
$this->collectionUpdates =
$this->collectionDeletions =
$this->visitedCollections =
$this->scheduledForDirtyCheck =
$this->orphanRemovals = array();
} I would even extract some more code: <?php
public function commit($entity = null)
{
// Raise preFlush
if ($this->evm->hasListeners(Events::preFlush)) {
$this->evm->dispatchEvent(Events::preFlush, new Event\PreFlushEventArgs($this->em));
}
// Compute changes done since last commit.
if ($entity === null) {
$this->computeChangeSets();
} else {
$this->computeSingleEntityChangeSet($entity);
}
$this->removeOrphans();
// Raise onFlush
if ($this->evm->hasListeners(Events::onFlush)) {
$this->evm->dispatchEvent(Events::onFlush, new Event\OnFlushEventArgs($this->em));
}
$this->commitComputedChangesets();
// Raise postFlush
if ($this->evm->hasListeners(Events::postFlush)) {
$this->evm->dispatchEvent(Events::postFlush, new Event\PostFlushEventArgs($this->em));
}
$this->cleanUp();
}
private function removeOrphans()
{
if ($this->orphanRemovals) {
foreach ($this->orphanRemovals as $orphan) {
$this->remove($orphan);
}
}
}
private commitComputedChangesets()
{
if (! $this->hasComputedChangesets()) {
return;
}
// ...
}
private function hasComputedChangesets()
{
return
$this->entityInsertions ||
$this->entityDeletions ||
$this->entityUpdates ||
$this->collectionUpdates ||
$this->collectionDeletions ||
$this->orphanRemovals;
} |
Since the usage of the listeners is done only twice, I'd wrap that piece in a private method instead... |
Looks good to me :) |
There is one thing that bugs me about this PR. I wrote it against version 2.2 but, if it is accepted, it should be also applied to 2.3 and master. Can it be done in a single PR? |
@frosas it can be merged to different branches (can be done in git :) ) |
-2 from me. 1- Since you are not flushing anything (no entities), it should not trigger an operation that is not being executed. |
If you want a single attempt of this being accepted, please enable the performance tests and execute the code before and after your patch. If there's no huge performance impact, we may consider the second point as +1 from me. Please post both results here when you try it. |
Also this PR is because I wanted to detect flush overlappings but I managed to do it without these changes so I have no inconvenience in closing it. |
@guilhermeblanco also, the |
@guilhermeblanco the performance is neglectable here - plus performance tests don't test this. If you have an on flush event you normally check for "give me all inserted etntities", "give me all changed entities" etc, but these are empty anyways, so nothing happens in listeners. @frosas can you close this PR and open a new one against master? we dont merge against versions. |
Closing now, this should be opened on master. |
Any idea on how to easily apply these changes to master? Otherwise I'll create a new branch against master and PR it. |
No description provided.