The original entity is currently passed as piggy-backed property $entity->original
. It's useful to have it, but it's not very visible there.
What about moving from
hook_entity_update($entity, $type)
hook_{entity_type}_update($node)
to
hook_entity_update($entity, $entity_original)
hook_{entity_type}_update($entity, $entity_original)
Analogously for the presave hooks, e.g.
hook_entity_presave($entity, $entity_original = NULL)
If we do so we could scratch $entity->original
. However, currently the existence of $entity->original
allows for more efficient mass-updates as original can be multiple-loaded. So what about providing entity_save_multiple($entities)
which already handles that efficiently?
Comments
Comment #1
fagoLet's leave entity_save_multiple() beside for now, but convert $entity->original to the separate parameter. Temporarly piggy-backing data is bad-practice and we should not encourage this. It was necessary in that case as $entity->original was introduced late in the d7 cycle, but now it's time to fix that.
Comment #2
Dave ReidWould this be getting rid of the entity-generic hooks (e.g. hook_entity_update())? That has a bigger impact than removing $entity->original to a lot of modules.
Comment #3
fagoNo, sry if I've been unclear - of course all the hooks should stay. This is just about moving $entity->original to a $original parameter for all the update hooks.
Comment #4
Dave ReidAh ok, was just confused since there was no "after" version of it.
Comment #5
catchI can't stand the structure of $entity->original, so this seems like a good idea.
At some point I'd wanted something like hook_entity_presave($type, Entity $entity, array $changes); so you can just easily see what stuff had changed, but I'm not sure how feasible that is at all. That'd be a much bigger change though so let's go for the extra parameter for now.
Comment #6
fgmHere is a patch to do this.
I also added the original parameter entity to the preSave/postSave methods, which might need it too.
Comment #8
fagoYep, we should add it to those methods as well. I've opened for http://drupal.org/node/1634442 for the unrelated exception issue.
Comment #9
fgmRerolled. Should have far less errors (node and user tests pass locally).
Comment #10
Dave ReidI might add something that this makes impossible is being able to do token replacement using $entity->original. Moving this to a separate parameter removes the ability to fetch the original. I guess tokens could fetch it with entity_load_unchanged().
Comment #12
fago@#10: Does it make sense to have token replacements for that? It's not something that will be available everytime anyway, even more I guess it usually won't be available?
Still, if those tokens are desired the implementing module could support them by running token replacing with the original entity as well.
Comment #13
fgmLooks like it should pass this time, comment, entity, node, taxonomy, and user pass locally.
Comment #14
fgmRerolled after yesternight's commits, just in case they broke something.
Comment #15
fagoThat's unrelated and already handled by another issue. So let's leave it out here.
I think it's unusual to have that spanning multiple lines. Either use one line, or an if/else?
Then, let's only take $entity->original into account when it is an object implementing the EntityInterface, so entity types having an unrelated original property get not screwed on that.
I don't think that's worth commenting, you can read that from the code if you are interested in that as well.
The docs miss the interface. Also I think the non-NULL docs would read better if they are not negated, i.e. NULL if the entity is inserted. Also, we mix $original and $original_entity - we should make use of the same variable name everywhere.
Comment #16
fgmRerolled.
FTR, I regret our not using that ternary pattern, though: in cases like this (uncomplicated but long expression members), it is both clearer than a single line and than an if/else. But that's not an issue.
Comment #17
fagoThanks.
Should be documented as (optional). Also it doesn't document what it is.
I like how this makes this code shorter.
Shouldn't that be an isset($original) ?
Unrelated changes.
Also, there is one \Exception change left in the patch.
Comment #18
fgmRerolled accordingly.
Comment #19
fagoPatch looks good now! Checked back with Dave Reid via IRC that #10 isn't a deal breaker for moving on with this, so let's do so.
Comment #20
fgmActually, this needs some more changes in the api files.
Comment #21
fgmTurned out to be much more significant. Patch rerolled on top of #1618136: Remove $type from entity hooks.
Comment #22
fgmForgot to set status.
Comment #23
fgmRerolled now that #1618136: Remove $type from entity hooks has been committed.
Comment #24
jcisio CreditAttribution: jcisio commented(and other places in hook_entity_presave())
$original should be default to NULL.
(a few times)
Inconsistant argument name.
Unrelated change.
Otherwise looks good ;)
Comment #25
fgmThanks for the review. I think it is best to include the "use" change too since we are modifying this file anyway.
Comment #27
fgmHmm, looks like this was not the final patch.
Comment #29
fgmRerolled with all these changes. All tests I checked seem to pass locally.
Comment #30
fgm#29: 0001-Issue-1480696-move-entity-original-to-a-separate-hoo.patch queued for re-testing: make sure that yesterday's commits didn't break it.
Comment #31
fagoThis has to note that original can be NULL, as we dor for hook_entity_presave(). Same for others.
Comment #32
fgmI checked for more occurrences and found a few, but then something else emerged: Node::save() overrides Entity::save(), and needs to be converted to that format too for the issue to be completely addressed for the _update() hooks.
Comment #33
fgmActually, this also required changes in taxonomy.module and node tests, which implements these hooks.
All tests I've checked locally pass (book, comment, node, path, taxonomy).
Comment #34
fagoDocumentation guidelines say we have to go with absolute class names in hook docs for now.
Comment #35
fgmRemoved, along with the stray reference to the Monolog logger patch subcommit which found its way in the previous version too.
Comment #36
fagoReviewed it (again). Also, I was not able to find other references to $*->original anymore, so it should be complete now as well and all hook changes are properly documented.
This will need a change notification.
Comment #37
Dries CreditAttribution: Dries commentedI'm in favor of this API change. I want to give more people the time to comment on it so I'll wait a couple of days before committing it.
Comment #38
fgmThe prospective change notice is at http://drupal.org/node/1643406
Comment #39
fago#35: 0001-Issue-1480696-move-entity-original-to-a-separate-hoo.patch queued for re-testing.
Comment #40
fagoIt has been a week now, so let's move on? :)
Comment #42
fgmAfter one week, it was bound to be broken.... will fix it tonight.
Comment #43
fgmAll failing tests pass with this version.
Note that this required starting to use EntityInterface in field hooks.
Comment #44
fgmTypo in the API file, no code change. Rerolled a better interdiff.
Comment #46
fgmHmmm, now that the original exceptions have been addressed, more appear. Looks like a lot more type hinting is required. Will be rerolling tomorrow.
Comment #47
fgmRerolled on current HEAD.
Comment #49
fgmGrrr 8.x moved in the meantime. Rerolled.
Comment #51
fgmOf course there had to be a merge error..
Comment #53
fgmRerolled on today's HEAD. Removed previously appeared exceptions and fail on local tests. Will they pass on q.d.o. ?
Comment #54
fgmRerolled on today's HEAD. Removed previously appeared exceptions and fail on local tests. Will they pass on q.d.o. ?
Comment #55
fgm#54: 0001-Issue-1480696-Move-entity-original-to-separate-53.patch queued for re-testing: some recent change supposedly broke it w.r.t field updates.
Comment #56
BerdirNote that this patch and #1723892: Support for revisions for entity save and delete operations are currently on a conflicting path. The patch over there requires $entity->original in hook_field_update().
We'll need to figure out a solution, see the other issue for details.
Comment #57
Dave ReidI really don't like the DX of moving this to a separate argument. :/ I'd much rather remove $original all together, and if you need the original entity, you can fetch it yourself.
Comment #58
Berdir@DaveReid: The problem is that that is impossible. By the time hook_insert()/update are called we've already updated the database and it is impossible to load the original entity anymore. So you'd have to do it in hook_entity_presave() and then modules might end up doing this multiple times which is the reason this was added in the beginning.
Comment #59
jibran#54: 0001-Issue-1480696-Move-entity-original-to-separate-53.patch queued for re-testing.
Comment #60.0
(not verified) CreditAttribution: commentedmade it more clear that no hook is supposed to go away
Comment #61
fagoThis would fix #2140179: $entity->original gets stale between updates - so should we reboot this?
Comment #62
BerdirI don't think that's possible, seems like a large API change, we would now also have to update all pre/post methods. And there are unsolved problems when trying to access it in some function calls later on, as pointed out by dave reid.
However, what we still could do is provide a method for it, that would at least make it a bit less weird? And define it as an explicit property, possibly public for now?
Because right now ->original isn't even defined anywhere, which means it's stored in $this->values, for the current language and weird stuff like that.
Comment #63
fagoYes, it's a rather large API change, but having it available everywhere it's needed shouldn't be a big deal now - we just need to pass it on the related entity and field item methods also.
Comment #64
drunken monkeyI'm much in favor of this proposal, I was always annoyed by that magic property. A separate method/hook argument seems way cleaner. However, I guess this now won't happen anymore? Or is there still a chance? Really a bummer that it was already almost committed two years ago …
Anyways, if this API change won't happen anymore in D8 then, as Sascha says, we should at least properly define that property. With #2256679: Use config schema to determine which config entity properties to export regardless of whether they are public or protected landed, there shouldn't be any problem with config entities there anymore.
Comment #65
BerdirI'm pretty sure we can still do it as an explicit method, we can keep support for $this->original if we want to.
Comment #66
drunken monkeyYou mean adding
getOriginalEntity()
/setOriginalEntity()
(or whatever) and making$original
an explicit protected property? That's what I meant we should do in any case, yes, I do hope that's still possible.What I fear won't be possible anymore (though I'd love to hear I'm mistaken) is adding
$original
as a separate argument to all update/presave hooks and methods, and completely getting rid of the property.Comment #71
joachim CreditAttribution: joachim commented> I'm pretty sure we can still do it as an explicit method, we can keep support for $this->original if we want to.
That's now covered by #2839195: Add a method to access the original property , which I think would make this issue obsolete.