Problem/Motivation
In #2856363: Path alias changes for draft revisions immediately leak into live site we're looking to add path aliases to non-default revisions. For example when creating a draft (forward) revision with Content Moderation. This works well with Node because we can alias the revision link (/node/1/revision/2). The only other supported entity types is Taxonomy Term and Media. Taxonomy Term is not revisionable yet so we won't need to worry about that, but Media is revisionable, and doesn't have a revision link template, so will not get this feature, and will regress to forward revision aliases breaking the "live" default revision alias.
Proposed resolution
Add a revision link template (and controller etc) for media entity.
Remaining tasks
User interface changes
API changes
Data model changes
| Comment | File | Size | Author |
|---|---|---|---|
| #28 | interdiff-21-28.txt | 6.25 KB | seanb |
| #28 | 2885486-28.patch | 12.41 KB | seanb |
| #21 | interdiff-18-21.patch | 7.01 KB | seanb |
| #21 | 2885486-21.patch | 15.77 KB | seanb |
| #18 | interdiff-12-18.txt | 964 bytes | seanb |
Comments
Comment #2
seanbHere is a first patch. I basically copied a lot of stuff from node. If this solves the issue we can also add the tests for it.
This makes me think we definitely need some base classes to not have to copy this for every revisionable entity type. I think it's best to do this in a followup.
#2862422: Add per-media type creation permissions for media is a related issue since we want revision permissions per type as well.
Comment #3
timmillwoodI'm wondering if we add version history, reverting and deleting of revisions in a follow up? Keep this issue to just adding the revision link template and revision page. However not too precious about that.
I do agree that we should add many base classes and interfaces for this stuff. Currently only node does this stuff, the other revisionable entity type in core, block content, doesn't have any of this yet either.
A couple of nit picks:
Too much spaces.
No new line
Comment #4
seanbHere is a new patch containing just the revision page. Basically started over so skipped the interdiff. Also added followups:
#2887106: Add generic base classes for content entity revisions
#2887108: Use generic base classes for entity revisions in Node, Media and Block content
Comment #6
seanbThis should fix the tests.
Comment #7
timmillwoodI think it looks really good. Leaving the "Needs tests" tag as I expect there is a little more test coverage to add. Also Not sure we should add a storage handler.
I don't really like that we're overriding the storage handler just to add this in. It'd be nice if we could add it to SqlContentEntityStorage. I know Node does this, but maybe it shouldn't either.
We could do it in a follow up, but as this it would prevent us adding a whole new file, doing it now seems wise.
Comment #8
seanbRemoved
MediaStorage/MediaStorageInterfaceand added the methods toSqlContentEntityStorage/ContentEntityStorageInterface. The param ofNodeStorage::countDefaultLanguageRevisions()is changed now, since it also extendsContentEntityStorageInterface. I didn't remove the method inNodeStorageyet, we should probably do that in #2887108: Use generic base classes for entity revisions in Node, Media and Block content.Also added a bunch of tests. As discussed on IRC we should probably add base classes for the revision related tests as well in #2887106: Add generic base classes for content entity revisions. For now I think this is sufficient.
Comment #9
seanbRemoved some extra spaces in the patch.That didn't go as planned. Let me wait for a review until I post another one.
Comment #12
seanbMoved
countDefaultLanguageRevisionstoSqlEntityStorageInterface.Comment #13
timmillwoodI think it might be best to add this to \Drupal\Core\Entity\Sql\SqlEntityStorageInterface rather than ContentEntityStorageInterface.
+1 changing this to a select!
This seems an unrelated change?
And again.
Too many spaces (as you spotted).
Comment #14
timmillwood#13.1 and #13.5 are fixed in #12. Just #13.3 and #13.4 to clarify.
Comment #15
seanb13.4 and 13.4 were needed to make sure the tests passed. For some reason I get a ajax JS error. I guess my machien takes a little longer than the testbot. In
Drupal\Tests\media\FunctionalJavascript\MediaSourceImageTestwe have$assert_session->assertWaitOnAjaxRequest()which serves the same purpose.I could remove it and add another issue for it? But since it is in
MediaRevisionTestwe might as well fix it now.Comment #16
timmillwood@seanB - My concern is, what have we added in this issue that adds the need to wait on the ajax request? If the answer is nothing then it should go in another issue, for clarity more than anything.
Comment #18
seanbThe tests actually fail on those lines. Another good reason to remove it. This should be it then :)
I'll figure out what's going wrong on my local machine later...
Comment #19
timmillwoodAwesome!
Comment #20
tstoecklerThis looks nice to me, but I do have some comments. Most prominently,
MediaControllershould not be needed, as far as I can tell.Should we throw an exception or something like that in case the entity is either not translatable or not revisionable (or both) in which case
$this->revisionDataTablewill not be set?Seems like unnecessary complexity?
Let's use "revision ID" instead of "vid".
Also this comment could do a better job of explaining what is happening. Why is the default language relevant, and not the current language, for example?
Since this already injects all of its dependencies, there is no need to extend
ControllerBase, as far as I can tell.We have
EntityViewController::viewRevision()for this.This we don't have as a generic function yet, but we might as well add it to
EntityViewControllerhere, I would say.Comment #21
seanb#20.1 Added exceptions.
#20.2 This allows for other operations as well, but since we don't implement them yet I removed this.
#20.3 Changed vid to revision ID. This for now is a copy of what the node module does. I'm not 100% sure why the default language is used and not the current language. Don't know who we can ask for that? I guess if we need to refactor/improve this it would be nice to handle this in #2887106: Add generic base classes for content entity revisions and #2887108: Use generic base classes for entity revisions in Node, Media and Block content. Or maybe a separate followup?
#20.4 Switched to
EntityViewController#20.5 Switched to
EntityViewController#20.6 Decided to remove the custom title callback.
EntityViewController::buildTitle()overrides it anyway.Comment #23
seanbYes, that was supposed to be a txt file.
Comment #24
timmillwoodLooks to cover everything in #20, so back to RTBC
Comment #25
tstoecklerTotally missed that that
buildTitle()is not used as a_title_callbackbut actually is called at runtime. Nice catch! I remember that at some point we were still supposed to add_titleand_title_callbackto all routes, so that theTitleResolverwill have something to resolve, I'm not sure if that's still how we do it. I think that\Drupal\Core\Entity\Controller\EntityController::title(), though, should suffice as a sort of "fallback"_title_callback, so maybe we can just add that.I looked into it a bit and I'm still not 100% sure it's correct to query on the default language (although it certainly could be, not sure). But I did realize that
NodeRevisionAccessCheckis used for two different routes:/node/1/revisionsand/node/1/revisions/2/view. The first one is a bit more complicated as it needs to check whether revisions exist in the first place, etc. and that is why we have that sort of logic. The second one should be pretty straightforward, as the routing system should throw a 404, if it can't load the revision, so we should just be able to check access on the loaded revision using the entity access control handler. And we actually already have a route access checker to do just that. So I think we can simply remove the custom access check and specify:Then when we provide a revision overview of some sort, then we can try to figure out what kind of access check we need. In any case I think splitting up the two different use-cases makes the code more understandable.
Edit: Now thinking about this, what my suggestion would allow is that you access
/media/1/revisions/1even if you only have a single revision whereas currently that is not the case. So I guess that suggests we should discuss that in a follow-up. So leaving RTBC, although, if you want to fix the_title_callbackmentioned above, feel free ;-)Comment #26
tstoecklerActually looking around a bit more, I see that contrib
entity.modulehas aprotected function countDefaultLanguageRevisions()in the access checker, which performs the entity query instead of doing anything in the storage. I actually like that better than adding more stuff to our already over-powerful storage class, especially if we're not 100% sure about the use-case, so marking needs work for that.Comment #27
tstoecklerOpened #2887529: Improve revision routing for the above.
Comment #28
seanbFixed #25 and #26.
countDefaultLanguageRevisions()toMediaRevisionAccessCheckcountDefaultLanguageRevisions()inNodeStorageandNodeStorageInterfaceComment #29
seanbNeeds review :)
Comment #30
timmillwoodAll looks good to me, but I think @tstoeckler should be the one RTBC'ing.
Comment #31
tstoecklerThank you, looks very nice!
Comment #32
gábor hojtsyThere are a lot of similarities of this code to node of course :)
So that made me wondering are we consciously not supporting update and delete operations for revisions? (We don't necessarily need to have a UI to do that?)
I think it would be nice overall to document why not.
Comment #33
gábor hojtsyAlso the patch/approach in #2856363: Path alias changes for draft revisions immediately leak into live site does not require to have this link template anymore. It is nonetheless a good addition IMHO since media does support revisions, so looking at those revisions would ideally be possible on the UI somehow :) Just noting there is no blocking relationship anymore and no regressions caused. :)
Comment #34
tstoecklerWell, this is about routing access, so unless there's a UI - i.e. routes - for that it seems pointless to support that?
Comment #35
gábor hojtsyThat's a good point :)
Comment #36
wim leers+1 for reusing this existing controller.
lgtm
I doubt static caching is necessary, but
\Drupal\node\Access\NodeRevisionAccessCheck::checkAccess()doe sthe same, so this is fine.RTBC +1
Comment #38
gábor hojtsySuperb, thanks for the additional review @Wim Leers :) Committed!