-
-
Notifications
You must be signed in to change notification settings - Fork 1.3k
Resolved a bug where a soft-deleted object isn't remove from the ObjectManager #2930
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
Resolved a bug where a soft-deleted object isn't remove from the ObjectManager #2930
Conversation
Codecov ReportAll modified and coverable lines are covered by tests ✅
Additional details and impacted files@@ Coverage Diff @@
## main #2930 +/- ##
==========================================
+ Coverage 78.51% 78.53% +0.01%
==========================================
Files 168 168
Lines 8782 8790 +8
==========================================
+ Hits 6895 6903 +8
Misses 1887 1887 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
@phansys it'd be nice if the tests could be run on new commits. Also, I believe the CHANGELOG will need to be something you commit, as I don't have the target version. |
Co-authored-by: Javier Spagnoletti <[email protected]>
Co-authored-by: Javier Spagnoletti <[email protected]>
Co-authored-by: Javier Spagnoletti <[email protected]>
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.
@mbabker, could you please provide your feedback here?
Thanks.
I don't use soft deletes in my Doctrine based projects so at face value this seems fine to me. What's the current behavior if you do a |
@mbabker You're correct in your assumption. If it's not already cached in the |
@oojacoboo, could you please rebase this PR and fix the conflicts? |
The PR says there aren't any conflicts with the base branch. |
Thank you @oojacoboo! |
Good point. Squash was working with no conflicts. |
One question: what about the soft-deleteable filter? Should the object be removed from the ObjectManager if the soft-deleteable filter is disabled? Shouldn't it stay in the cache in that case? |
@rotdrop if that filter is disabled... that'd be a real database delete, no? Why would it remain in the |
No, I think you misunderstood my point. The "soft-deleteable" filter is the filter which actually enables filtering out soft-deleted entities. If that filter is disabled (and it is disabled by default) then select statements will just retrieve entities as usual. Only if the soft-deleteable entity filter is enabled then soft-deleted entities are omitted from the result set. So by "the filter" I do not mean the SoftDeleteable extension, but the soft-deleteable entity filter, please compare with the documentation here: DoctrineExtensions/doc/softdeleteable.md Line 32 in ea1d375
Hence: without the filter being enabled the entities show IMHO stay in the cache. |
…erved. This refers to the PR doctrine-extensions#2930 which removes entites from the object manager regardless whether the soft-deleteable filter is active or not.
@oojacoboo Perhaps this PR #2939 clarifies what I am talking about. |
@rotdrop I see what you mean now - regarding the filter and being enabled/disabled. Honestly, I don't see the difference. I get where you're coming from and I see your logic, but I think it's more of a personal use case, or a flawed way of looking at it. Deleting an entity, regardless of whether soft-delete is enabled/disabled or even setup in the first place, should remove the object from the ObjectManager. You're deleting it... that's an explicit intention. Leaving it in the That said, if you have the |
@oojacoboo I do not think that the scenario is that clear. Also, if we talk about state, explicit intent and that calling remove should remove the entity from the object manager: this still does not happen until you call flush(). However, flush() is meant to sync the state of the object manager with the database, flush() is not a cache garbage collector. Also, this entire SoftDeleteable extension already breaks "explicit intent", actually, the whole purpose of this plugin is to alter the meaning of remove(). So, I am not convinced that the way this PR #2930 handles things is desirable. |
…the ObjectManager" This reverts commit 211b6fe. I find it unmotivated to clear the cache of the object manager at flush. See the discussion at doctrine-extensions#2930.
I won't argue that |
I'm torn by this change. From one point of view I agree with the reasoning behind this change, but from another point I do not. Simply detaching the soft-deleted entity during a request/message context seems to introduce more issues than what it solves. As it is required to call In our projects we have acted on knowing that a softdeleted object is still available within the same request/message context, as you know it won't be fully deleted in the end. Next to that, issues #2942, #2947 & #2955 seem to be directly caused by this change. Especially #2955 will be almost impossible to fully solve. So, I believe this needs to be either reverted to solves the issues that have risen, or to make this behaviour configurable. If anyone is interested, here is a compiler pass to remove the `postFlush` handler when using the stof bundle.use Exception;
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\ContainerBuilder;
class DisablePostFlushDetachCompilerPass implements CompilerPassInterface
{
const TAG_NAME = 'doctrine.event_listener';
public function process(ContainerBuilder $container): void
{
$definition = $container->getDefinition('stof_doctrine_extensions.listener.softdeleteable');
if (!$definition->hasTag(self::TAG_NAME)) {
throw new Exception('Doctrine event listener not configured?');
}
// Remove the postFlush tag
$tags = $definition->getTags();
$tags[self::TAG_NAME] = array_filter(
$tags[self::TAG_NAME],
static fn (array $tag): bool => ($tag['event'] ?? null) !== 'postFlush'
);
// Update the listener tags
$definition->clearTags();
$definition->setTags($tags);
}
}
// Register in your bundle with the following:
// Needs to be run before RegisterEventListenersAndSubscribersPass is run
// $container->addCompilerPass(new DisablePostFlushDetachCompilerPass(), priority: 10); |
Also I am still not convinced, although @oojacoboo had the last word so far. But though I did not answer him yet I really do not agree with his last comment in this affair. So here is a feature request: please revert #2930 Please let us start a discussion and let us come to a better documented agreement about how "soft-deleteable" should behave. |
Hi, I have a follow-up question about this change. Since updating to version 3.20, we have seen errors regarding cascade operations. The flow in our application is as follows (maybe sub optimal but right now it is what it is):
We now believe that this happens because the cascade delete is not executed during the first flush due to the detachment from the object manager. The second flush fails because of the cascade SET NULL on an object that is no longer part of the object manager. Could this be a regression, or are we on the wrong path? Thanks and best wishes, |
@kopfsalat Yeah, sounds related to this change. You can confirm it by using the CompilerPass I posted in my previous comment here: if using that solves your issue you know for sure. |
@bobvandevijver Thanks for the quick response! Using your CompilerPass indeed resolved the issue. I will post a bug report and link it to this PR. |
Currently, after you remove an entity, it's still queryable by the pk, as it's cached in the
ObjectManager
. This PR fixes this bug by removing itpostFlush
. See test for more details.