Problem/Motivation
Deleting an image style which is in use by a field formatter or widget, without selecting a replacement style, leads to fatal errors:
Steps to reproduce:
Image formatters (from comment #56):
- add an Article, uploading an image
- remove all the predefined image styles, leaving 'No replacement, just delete'
- go to the main page
you get the error
Fatal error: Call to a member function getCacheTags() on a non-object in /home/dfvjn/www/core/modules/image/src/Plugin/Field/FieldFormatter/ImageFormatter.php on line 200
which makes the entire home page not accessible. Recovering via UI is non-trivial because you have to re-add the deleted image styles with the exact machine names ('large', 'medium', 'thumbnail'), provided you know how to access admin UI typing the url in the browser. Not easy unless you are really know what to do.
Image widgets (from #2631140: After Deleting Thumbnail Image Style, Saving to an Image Field Throws Fatal Error):
- Navigate to image styles and delete thumbnail styles
- Try to upload image to image field on Article
- Should see white screen or Fatal error: Call to a member function transformDimensions() on null in /vagrant/d8/core/modules/image/image.module on line 281
Proposed resolution
Now that, #2562107: EntityDisplayBase should react on removal of its components dependencies is in, when deleting an ImageStyle the formatters and widgets using that style will be disabled. Prior to #2562107: EntityDisplayBase should react on removal of its components dependencies, the whole entity display where this style was involved in formatters/widgets settings, was deleted.
This is the first use-case of #2562107: EntityDisplayBase should react on removal of its components dependencies.
- Implement calculateDependencies() and onDependencyRemoval() in ImageFormatter.
- Implement calculateDependencies() and onDependencyRemoval() in ImageWidget.
- Improve the ImageStyle deletion confirmation form to show the replacement only when there are affected formatters/widgets and when at least another style exists.
- Improve the description text on ImageStyle deletion confirmation form to show the correct help depending on the context.
- Tests.
Remaining tasks
None.
User interface changes
Improved confirmation form on ImageStyle deletion.
Screenshot before patch:
Screenshot after patch:
With replacement styles available:
Without replacement styles available:
API changes
None.
Data model changes
None.
Beta phase evaluation
Issue category | Bug, because it results in a fatal error. |
---|---|
Issue priority | Major because fatal error when viewing content. |
Prioritized changes | Prioritized because bugfix. |
Disruption | No disruption, because only a config dependency bugfix. |
Comment | File | Size | Author |
---|---|---|---|
#122 | b.png | 16.6 KB | mondrake |
#122 | a.png | 24.91 KB | mondrake |
#116 | 2479487-116.patch | 33.65 KB | claudiu.cristea |
Comments
Comment #1
Dmitry_N CreditAttribution: Dmitry_N commentedHi,
I got the same issue with Drupal 8.0.0-beta10. If you've found any solution, please help.
Best regards,
Dmitry Nikitchenko.
Comment #2
legolasboI'm unable to reproduce this issue on HEAD with the steps supplied in the issue summary.
Fortunately I am able to reproduce this issue with the following steps:
The error is caused by attempting to load a non-existing image style and using the result without checking if an image style was loaded. The attached patch fixes this.
Comment #3
legolasboSince the OP is on a windows system this is probably related to #2276705: Cannot create image styles on Wamp server (Apache/windows), which also causes a fatal error before this bug is triggered.
Comment #4
legolasboAttached patch adds tests.
Comment #6
mondrakeI could reproduce the issue manually following the steps in the IS. The patch fixes the issue and adds tests. Also tested manually. RTBC
Comment #8
alexpottThis is a config dependencies issue. When you delete the image style it should warn you that the image style is in use and then "fix" the entity display.
Comment #9
legolasboUnassigning since I'm not able to address this further in the coming week. I might be able to pick up work on this later.
Comment #10
legolasboWorking on this.
Comment #11
legolasboAttached patch takes a new approach and adds config dependencies and adds dependency handling for when the image style is deleted.
Comment #12
legolasboComment #16
legolasboTest is failing because it doesn't account for the newly added dependency. Adjusted the test accordingly.
Comment #18
legolasboIgnore previous patch, which was incorrectly formatted.
Comment #19
legolasboComment #20
dawehnerIt would be nie to update the issue summary a bit here to explain what happens and what the solution is.
Maybe we could have a better method name, this doesn't say much IMHO
nitpick: upper case
Let's add {@inheritdoc}
We could do if ($image_style = $this->getSetting('image_style')) { and get rid of the second getSetting method
Comment #21
legolasboWill update the summary aswel.
Comment #22
legolasboComment #23
tim.plunkettThis doesn't look cheap. Is it? If not, is it worth storing in a property?
Also, why is this config entity the only one that needs to do this?
Comment #24
mondrake#2562107: EntityDisplayBase should react on removal of its components dependencies and #2565513: Replace ImageStyle removal workaround with the entity display native behavior are related.
Comment #25
BerdirIndeed. The problem is that dependencies on image styles are not declared, from e.g. the image formatter. Once we do that, the dependencies will be deleted, like everything else too.
Of course, the problem is that then we'll actually delete and that won't really fly with the replacement stuff. So we'll need find a solution for that. #2565513: Replace ImageStyle removal workaround with the entity display native behavior does't make sense, because the config dependency system has no way to do that kind of replacement.
Comment #26
alexpottSo I think we should save the replacement ID to the image style as part of the confirm form. And then we need to delegate to formatter during on dependency removal to so the style replacement... fun. And then we shouldn't need a multi-step form.
Comment #28
mondrakeIMHO, we should go back to the original scope in this issue, and leave the config dependency fix to the two issues that were filed in the meantime, see related issues.
Patch in #4 still applies, and does something sane that could be a stop gap solution while config dependency gets fixed. Besides, contrib/custom code can very well add render arrays for
image_formatter
orimage_style
themes outside of the entity display formatters with a wrong image style name... and the patch would prevent a fatal in that case.Not RTBCing yet, opinions?
Comment #29
claudiu.cristeaThis needs to be handled via config dependencies. Will provide a patch, later today.
Comment #30
claudiu.cristeaThis have to benefit of #2562107: EntityDisplayBase should react on removal of its components dependencies and is an effect of that. IMO that is critical while now blocks 2 major issues (this & #2412569: Allow setting the auto-create bundle on entity reference fields with multiple target bundles).
Provided 2 patches. One to be committed but not tested and one just for testing, built on top of #2562107-33: EntityDisplayBase should react on removal of its components dependencies. No interdiff while it takes a total different approach.
I added 2 tests: one for UI and one for API (my first KernelBaseTestNG, yay!)
Comment #33
claudiu.cristeaNot sure.
Comment #36
claudiu.cristeaFixed the kernel test.
Comment #37
claudiu.cristeaThis is the first use-case of #2562107: EntityDisplayBase should react on removal of its components dependencies.
Patch for review,
Comment #38
claudiu.cristeaImproved issue summary.
Comment #39
jhedstromJust a few nits/questions:
Instead of 'he', how about 'the user'?
This can be removed?
Missing space here.
Do our coding standards allow for compacting this into:
Comment #40
claudiu.cristeaThank you for review @jhedstrom.
IMO this is almost Critical because it makes the UI crash, so I don't see us going in RC with this bug. I tentatively tag this with 'rc deadline'.
Also looking to this ugly string that we're concatenating in this implementation, I would love to see #2575375: Allow ConfirmFormInterface::getDescription() to alternatively return a renderable array in so that I can return there a nice renderable array.
Comment #41
claudiu.cristeaOps, the interdiff
Comment #42
jhedstromFWIW, I don't know that it's critical (doesn't impact the entire system), nor that it need block RC--we can still fix bugs after RC.
Sorry about this, but I didn't really think through in my previous suggestion. How about "No possible replacements, announce that the formatters and widgets need updating."
Comment #45
claudiu.cristea@jhedstrom, Yes, that sounds perfect. Thank you!.
Comment #46
jhedstromPatch is looking good. Since the last test-only patch was uploaded, the tests here have changed quite a bit--could somebody upload just the tests again to illustrate the fix?
Comment #47
claudiu.cristeaThere are 2 tests that we provide here: one is a KernelTestBaseTNG that tests this from the API perspective and the other one tests the UI because the image style replacement is something that happens in the UI.
Comment #48
claudiu.cristeaMore nits, fixes, doc improvements.
Comment #51
mondrakeManual review, running the patch in #48 on simplytest.me
Steps:
My considerations:
Will review code later.
Comment #52
claudiu.cristea@mondrake,
In this case we pretend that *we know* what the site builder wants. If the image is huge the site will be broken and maybe he'll not notice this. That's bad. By getting this message he is forced to make an informed choice: replace or disable the widgets/formatters. He can still go back and add a replacement image style.
Agree with the duplication of widgets/formatters but I like more what I've implemented in the scope of this issue. How to disable the standard output?
EDIT: Also, I want to show only widgets/formatters in the list but the standard info box shows all dependencies.
Comment #53
claudiu.cristeaAlternatively, I can remove the custom list and let there a generic message. But that would be a UX lost compared to the patch.
Comment #54
jhedstromI tend to agree with this. Simply defaulting back to the original image might have very unintended consequences.
I think this is pretty close to RTBC now.
Comment #55
yched CreditAttribution: yched commentedThnaks @claudiu.cristea.
The patch adds the new dependencies in default config, but don't we also need an update function ?
That feels inconsistent with the usual casing of properties in our config yamls.
replacement_id ?
replacement_style ?
But well, more importantly see below :
Ooh. That seems a bit wicked...
If I get things right, this "replacementID" info is only placed here and saved back to the config, so that it's be available in the various implementations of onDependencyRemoval(), just before we delete that config anyway.
I'd tend to think that information belongs somewhere else than in the image_style entity itself, in something like State, or maybe in a readable static registry somewhere (since the information is emitted and consumed within the same request anymay). At any rate, it feels a bit wrong to clutter the config shchema and all the config records with a property that is only ever non-null and useful during a couple milliseconds within one request in case the entity gets deleted ?
It feels a bit weird that ImageStyleDeleteForm hardcodes behavior on a specific formatter and widget, with knowledge of the specific setting name involved each time.
Any contrib/custom formatter that also uses image styles will be left out here.
If this is about "knowing which displays have widgets/formatters that depend on a given image style", don't we have all the info by calling the widget's calculateDependencies() ?
(to avoid instanciating every widget and formatter plugin in every display for every bundle of every entity type, we could first check the dependencies of the EntityDisplays ?)
All in all, I have a feeling we're inventing a system specific to image styles, to address a case that is more generic than that (allowing replacements in dependant config when a dependency is deleted). The "image style" use case is a bit prominent, but not really singular conceptually ?
Comment #56
mondrakeIMHO, this is critical. Tentatively setting like that, please revert if does not qualify.
Testing RC1 on simplytest.me without this patch:
you get the error
which makes the entire home page not accessible. Recovering via UI is non-trivial because you have to re-add the deleted image styles with the exact machine names ('large', 'medium', 'thumbnail'), provided you know how to access admin UI typing the url in the browser. Not easy unless you are really know what to do.
---------------
@claudiu.cristea re #52:
Fine, but with your reasoning then we are pretending that the site builder is OK to disable the formatter :)
I think it's a matter of opinions - do we prefer to see an unformatted image, or no image at all? Couple of more considerations:
original image
is shown.Comment #57
dawehnerIn case you want, you can assign a variable and use that in the foreach.
Doens't concat strings like that lead to escaping?
Do we need an update path for them, which could be to simply resave all the affected configuration?
Comment #58
claudiu.cristeaTrying to comment some of concerns before jumping to coding:
@yched, #55:
Yes, I felt this from the very first moment but then I tried to stick as much as I could to the current implementation of ImageStyle config. But now, looking in the code more I think that we can drop the
replacementID
. Even that is part of ImageStyle interface that, right now in HEAD, stores nothing -- it's not used on existing sites. It's not even part of schema. So removing it from the config entity it would be almost trivial.Now the question is: do we need to persist the replacement ID somewhere, for example in a state? I think storing in memory should be enough. But what about the API? What will happen with an hypothetical existing module doing this, based on HEAD code?
This will fail even with the current patch. To keep such a BC we have to override the
::delete()
in ImageStyle and force a save if 'replacementID' is not NULL:The question is: Do we need to support BC for such an super edge-case? I would say NO. That's why, I think, we can change the replacementID to a static storage that we can read during the onDependencyRemoval() phase. We are not implementing a new feature here, we are fixing a critical bug. We need a decision here.
Yes. But I still think that the site builder needs to know explicitly who are the formatters/widgets affected by this operation. This is part of the delete confirm process and I think that's why it should be there. An idea would be to rewrite the
addDependencyListsToForm()
to subtract the widgets/formatters from there, leaving in CMI dependencies only the rest.This is so true, but wouldn't we introduce a UX regression by dropping the replacement feature? IMO this would work as a simple delete confirmation form where the site builder is warned about disabling those widgets/formatters. But the UX regression?
@mondrake, #56:
I think disabling is an action that makes the site builder more aware about what he's doing. In fact disabling is the native action if no specific action is implemented.
@dawehner, #57:
I'm not sure I understood. (/me admits that is not up-to-date with the latest changes to t(), TranslatableMarkup, SafeString & Co.)
Other aspects:
I wonder if the remaining $style->flush() should not go ImageStyleStorage::resetCache()? (the class doesn't exist right now).
Comment #59
alexpottI think it is acceptable to move the image replacement style to state. Note I do not think we should remove ImageStyle::getReplacementId() - this should just call state.
Re the getDescription and concatenation of markup... this works because the result is XSS admin filtered...
$form['description'] = array('#markup' => $this->getDescription());
I don't think think we should be listing individual components on the form because (a) we already have the config dependency list (b) this adds unnecessary complexity and it not necessary for fixing the bug. In the RC phase we should be looking to do the smallest possible fix and try ensure that every eventuality is tested.
I've discussed this with @WimLeers, @dawehner, @jibran and @gabor and we agreed that this does not meet the definition of critical since the steps to create the error are not typical. However, that does not mean that this issue should not land during RC. Given that it creates a difficult to remove from error and we have missing configuration dependencies (which makes the system less robust and deployable) I'm tagging this with "rc target" which means once it is rtbc it is eligible for commit during RC.
Comment #60
yched CreditAttribution: yched commentedTracked things back a little, ImageStyle::getReplacementId() is a one-off construct specific to image styles, introduced in #1782244: Convert image styles $style array into ImageStyle (extends ConfigEntity) (early 2013) to preserve the one-off construct in D7 image styles that allowed code to "replace" an image style being replaced.
D7 :
So getReplacementID() is the remnant of a completely separate and parallel API next to the more general "config dependency" system that D8 gained since then. Sad, but yeah, now is probably not the time to remove it :-/
Using state for this means :
- ImageStyle::getReplacementID() reads from state,
- since we don't have a corresponding setReplacementId() setter, ImageStyle needs to override ::set() to catch writes to 'replacementID' and store it to state.
- in order to clean up, since we use a persistent storage, ::postDelete() probably needs to remove the corresponding state data too.
That means quite a few unnecessary writes to a persistent storage, but it's not triggered too often...
Wondering if we could use an in-memory property in an ImageStyleStorage handler for that, with associated read/write methods there ?
(ImageStyle config entities currently don't have a dedicated storage handler of their own, but they could ?)
Comment #61
claudiu.cristeaI used state and memory for replacement. Curious.
Interdiff is not too relevant.
Comment #63
yched CreditAttribution: yched commentedThanks @claudiu.cristea. More detailed review soon, for now just :
If this uses APIs, this should be a post_update ?
Not sure I see the interest of the property, is this really called several times in a request ?
Comment #64
yched CreditAttribution: yched commentedAbout how we track replacements :
Yeah, this ends up being a slightly convoluted way to just to store a string between those two points in the callstack...
If we're adding a new service, we might at well define a class with a simple getter and setter without going through the state API - or simply put those methods in the 'image_style' storage handler ?
Curious to hear what others think :-)
Comment #65
claudiu.cristea@yched, thank you for review.
#63.1: You're right. Moved but still keeping at config level.
#63.2: Good catch. Initially that was used twice. I didn't check.
#64. First I jumped to
drupal_static()
but that is in a retire process even it's not marked yet as deprecated. I went with a storage class. I wanted also to remove ImageStyle::postDelete() and move the flush operation in ImageStyleStorage::resetCache(). Unfortunately resetCache() is taking only IDs as arguments, not the entire object and in that stage the image style is already deleted, so I cannot load() it. I don't understand the reason why resetCache() is taking only the IDs as arguments while in the moment when it is called the complete list of objects is available.Comment #66
claudiu.cristeaComment #67
claudiu.cristeaSmall fixes.
Comment #68
claudiu.cristeaGrrrr. Forgot to add an empty line at the end of ImageStyleStorage.
Comment #69
yched CreditAttribution: yched commentedThanks @claudiu.cristea, looks way nicer IMO !
As an additional step, I'm wondering whether it would make sense to consolidate the "delete style and specify a replacement" capability direclty in ImageStyle::delete() :
Thoughts ?
Comment #70
claudiu.cristeaI don't see a use-case in core for this. The UI deletion goes to the standard entity delete form, so we don't call ->delete() directly. Other cases should know about this modified interface. BTW, we don't follow the interface, but it works while the parameter is optional.
Comment #71
yched CreditAttribution: yched commentedRight, good point. Never mind then.
Comment #72
yched CreditAttribution: yched commentedLast code nitpicks :
I think we should still cleanup the replacement mapping in the storage once the style has actually been deleted. Not that it matters much since the mapping is not preserved past the request, but still cleaner :-)
That might mean adding a removeReplacementId() (maybe overkill), or supporting NULL in get/setReplacementId()
Detail : The array_key_exists() here is not really needed, could be a cheaper isset($this->replacement[$name]), since if it's set to NULL we will return NULL anyway...
Well, this is almost as BC-breaking as removing the method from ImageStyleInterface, right ? :-)
I'm frankly skeptical that anything would actually break if we did remove it, but if we want to be extra conservative and keep it, then this should call storage::getReplacementId() ? (additionally we could at least mark it @deprecated)
The type hint is one line too high :-p
Minor : var name mismatch, it's called $style_id in the previous method :-)
Also, those two methods could use a small comment summarizing what is being done, the code is not super obvious to read.
(and same remarks for the duplicated code in ImageWidget)
Grammar is a bit off.
"Remove the image field from the display, to avoid a dependency error during import" ?
(just a proposal, not sure if that's what the test is actually doing here)
80 chars :-)
Comment #73
yched CreditAttribution: yched commentedWas about to get back to the "UI information duplication" part, but looks like it's been removed in #61. Honestly, that might be shortest path right now :-)
Also : the "preview image style" feature in the Widget is actually optional. So if no replacement it provided, the widget could be kept without a preview, which would be a frendlier fallback than hiding the widget and forbidding file upload altogether.
(of course, it's different for formatters, a formatter without an output style is just useless)
Comment #74
yched CreditAttribution: yched commentedPlus :
s/an/and ;-)
Comment #75
claudiu.cristeaThank you @yched for your detailed review.
#72.1: I did that already in a temporary patch (never posted) but it seamed to me kinda over-engeneering. Added back.
#72.2: OK.
#72.3. OK. The deprecated statement was already added in the interface. Just changed a bit.
#72.4, 5: OK. Cleaned a little. Also the formatter has the image style storage already injected, so I used that. Unfortunately the widget misses that.
#72.6, 7: OK.
#73: Excellent catch. In fact disabling that preview is non-invasive but setting the formatter to "original image" seems to me invasive. So the widget remain with no preview, the formatter gets disabled.
#74: OK.
Also working on formatter I discovered #2588553: Image widget summary is lying when the image preview is disabled :)
Comment #76
yched CreditAttribution: yched commentedThanks @claudiu.cristea. I thought I'd push RTBC, unfortunately I missed that earlier :
That first sentence is not english ;-)
Also, I think we tend to avoid contractions like "we'll, you'll, don't..." in our code comments, so I guess that applies all the more to UI text as well ?
Comment #77
claudiu.cristeaWell, I cannot help more here, my English is poor.
Comment #78
yched CreditAttribution: yched commentedYeah, not that easy :-/
Suggestions :
- when there are possible replacement styles :
"The %style image style you are about to delete is used in existing components. You may select another image style to replace it. If no replacement style is selected, the corresponding components will be disabled, and might need manual reconfiguration."
- when there are no possible replacement styles :
"The %style image style you are about to delete is used in existing components. Those components will be disabled, and might need manual reconfiguration."
?
Suggestions / adjustments welcome :-)
Comment #79
claudiu.cristeaRight, sounds better. This is English :)
How about replacing the word "components", which (I think) is a little bit too abstract and used more internally, with "formatters and widgets"? I mean, it seems that "component" is more an API terminology while formatter/widget is more descriptive to a site builder.
Comment #80
claudiu.cristea...that meaning:
"The %style image style you are about to delete is used in existing formatters and widgets. You may select another image style to replace it. If no replacement style is selected, the corresponding formatters and widgets will be disabled, and might need manual reconfiguration."
and
"The %style image style you are about to delete is used in existing formatters and widgets. Those formatters and widgets will be disabled, and might need manual reconfiguration."
The problem is now, that staring with #75 we are disabling only the widgets :(
Comment #81
yched CreditAttribution: yched commentedYeah, I was not sure we really expose "formatters / widgets" in the UI, but we do.
I'd say "existing *field* formatters and widgets", just to be a bit clearer.
Yep, the sentence about disabling should mention only formatters I guess.
Comment #82
claudiu.cristeaOK.
Comment #83
yched CreditAttribution: yched commentedOk, let's bring it to the right eyes :-)
Comment #84
mondrakeGreat work, @claudiu.cristea!
Just a couple of things:
1. I wonder whether it would still make sense to have this change to
template_preprocess_image_style()
from the patch in #4:and the test too. Contrib/custom may pass '#theme' => 'image_style' arrays outside of formatters/widgets, and if the style id is non existing, we will still get a fatal. Workaround is for contrib/custom to try and load the image style to check its existence before building the render array, but that seems a duplication.
2. Testing manually, I noticed that if you first disable and then renable the image formatter, the visual result differ, with the comments section getting rendered inline with the image. It's not related to this patch though.
Before disabling:
After disabling and re-enabling:
Comment #85
claudiu.cristea@mondrake,
I don't like how this is now in HEAD, neither in patch. I don't think the theme layer should *load* objects. That should have been done before. IMO this is a bad design. I don't know what is the solution here. I feel that the whole image style object should be passed to the theme layer, not only the name. But probably it's to late for that in D8?
EDIT: And yes, the backend (in this case the modules) should be in business of loading, validating the objects.
Comment #86
mondrake#85:
Yes that would make a lot of sense.
Maybe in 8.1 we can introduce a
$variable['image_style']
in parallel to$variable['style_name']
(that should be deprecated). Then$variable['style_name']
could become (in 8.1) a fallback if no image style object is passed. But that's for later...Comment #87
claudiu.cristea@mondrake, I opened an issue for the image style loading stuff. I would be very glad to get some feedback there #2589847: Stop loading image_style in the theme layer.
Comment #88
alexpottThis is not testing this code. It is testing that
system_post_update_recalculate_configuration_entity_dependencies()
has run. You need to load and resave the configuration entity for dependency recalculation. I think we need to create a dump for each RC to make testing simpler., and might need<code> no need for the comma. Could this be the <code>#description on <code>$form['replacement']
. Also given the way config entities and plugins work together a contrib config entity could depend on image styles and implement the replacement logic. I think limiting this toexisting field formatters and widgets
is wrong but, if we do that we need to be consistent andthe corresponding field formatters will be disabled
should bethe corresponding field formatters and widgets will be disabled
Again this might well be more than just widgets and formatters.
Same comma issue as above and also same issue that this might delete or fix other configuration entities.
Oh I see - why only displays? This replacement logic could be used by any configuration entity that depends on image styles to fix itself.
I don't think "memory storage" is very meaningful. I think it is worth expanding the comment to save this is not saved to the individual entity but used during deleting to do a replacement. Maybe just an @see to the methods is all the documentation required.
Atm it is only widgets and formatters that do this - but it would be possible for any other configuration entity that uses image styles to do this.
It's good to see that this is tested - nice work.
Let's combine these tests. Since message testing and doing the deletes are essentially the same activity - why install Drupal twice?
Comment #89
yched CreditAttribution: yched commented@alexpott :
- #88 2. 3. 4. The issue is that what will happen if no replacement is specified, depends on each config domain logic and what it does with the image style.
E.g image formatters get disabled, but image upload widgets are kept working, just without a preview thumbnail (since that is an optional widget setting anyway - see #73). Other config that use the image style might react in other ways.
- #88 5. "why only entity displays" : I guess expanding that would mean loading *all* config and find which ones currently depend on the image style ? Is that reasonable ?
[edit : hm, I guess that's ConfigManager::findConfigEntityDependentsAsEntities() ? We would then call it twice on this form ?]
Comment #90
Bojhan CreditAttribution: Bojhan as a volunteer commentedNot really clear what to review here, the message?
Comment #91
alexpott@Bojhan we need to review how the user selects a replacement image style when deleting an image style.
Comment #92
alexpottAlso #2592665: Create RC1 database dumps has landed so now we can write a proper upgrade path test without previous upgrades getting in the way.
Comment #93
Bojhan CreditAttribution: Bojhan as a volunteer commentedComment #94
claudiu.cristea#88.1: Fixed.
#882, 3, 4, 5: @yched replied in #89.
#88.6, &: Added/fixed docs.
#88.9: OK, there's only one test now.
Comment #95
claudiu.cristeaOuch! Forgot the patch.
Comment #96
mondrakeTested manually, adding some image styles and then deleting the Thumbnail style and replacing it with the newly created styles. Formatters get disabled when style is deleted with no replacement, and widget gets set to not display preview.
I would just say
'- No replacement -'
, there's enough information in the rest of the form description already.Other than that RTBC from my point of view - I think only @alexpott can give feedback to replies to #88.2-5
EDIT: if we implement
onDependencyRemoval
in ImageFormatter and ImageWidget, do we still need ImageStyle::replaceImageStyle? Maybe I haven't understood.Comment #97
claudiu.cristea@mondrake thank you.
That is still needed when renaming a style name, see ImageStyle::postSave().
Comment #98
mondrakeThank you. This also solves #2631140: After Deleting Thumbnail Image Style, Saving to an Image Field Throws Fatal Error.
Added before/after screenshots.
Ahh right. Pity that we do not have a method to react to dependencies updates, then. You have gone a long way to decouple ImageStyle code from formatters and widgets dependencies on delete, but it's still having dedicated code for these entities on update...
Comment #99
mondrakeComment #100
Wim LeersNit: s/Post update/Post-update/
"stores into" sounds very strange.
"merge together" -> "merge"
Why change from single to double quotes? Let's keep it the same as before.
"and if case"?
s/pickup/pick up/
This sentence sounds kind of strange.
This does not make sense.
Returning
NULL
means no@return
is necessary.But also, it's just deprecated, so actually it should still return this string.
Is this
string[]
?Comment #101
claudiu.cristea@Wim Leers, thank you for review.
Comment #102
mondrake#100 seems addressed to me. Back to RTBC.
Comment #103
mondrakeSorry, I did not mean to remove the 'rc target' tag. Added back.
Comment #104
catch@effulgentsia pointed out the issue summary mentions a fatal error, but I don't see that mentioned anywhere else, is that still the case?
Comment #105
mondrake#104: updated IS with steps from comment #56 and from #2631140: After Deleting Thumbnail Image Style, Saving to an Image Field Throws Fatal Error.
Comment #106
mondrakeComment #108
claudiu.cristeaComment #109
mondrakebot error
Comment #110
alexpottMaking this check here means that only if there is an affected component (ie an entity display) will you get a replacement image style. This is a change of behaviour that I don't think is correct. I think we should always get a replacement style and then other contrib config entities can use the same system.
Comment #111
claudiu.cristea@alexpott, OK. Should ::hasAffectedComponents() return TRUE by scanning all dependencies or should it be dropped? If we'll drop it, that might be confusing for some site builders. Because, if there's no config depending on that style on the system, they might think that they are replacing something. But their action would be senseless because the replacement is volatile.
Comment #112
alexpott@claudiu.cristea I guess it could check all dependencies... ConfigManager::findConfigEntityDependents() can do that. However the replacement question has always been volatile. So I think the description can be improved to encompass this.
Comment #113
claudiu.cristea@alexpott, @yched, I need your feedback based on #110 and #112.
Note: I didn't use ConfigManager::findConfigEntityDependents() for 2 reasons:
I admit that I don't like the way I'm calling $this->addDependencyListsToForm() earlier nor the way I'm testing for dependencies by checking the #access key. I think we should split ConfigDependencyDeleteFormTrait::addDependencyListsToForm() in 2 parts the existing method that only adds the form elements and a new protected method that computes and statically caches the list of dependencies. Then we call the new protected method from addDependencyListsToForm(). Also we call that directly in ImageStyleDeleteForm::form(). When is called 2nd time in the request to add the form elements, will retrieve the list from the static cache.
Comment #114
alexpottI'm not a huge fan of adding this... let's just override
buildForm()
inImageStyleDeleteForm
instead ofform()
- then we don't have to do this. BUT actually that's not going to work either. This is because in order to work out that it can fix something it needs the replacement ID so we need the replacement ID before showing the user the list of what can and can not be fixed. To me it looks as though we must be missing some test coverage because I can't see how the latest patch is actually working.Comment #115
claudiu.cristea@alexpott,
I think this works as expected because, if there's no replacement, the removal gets resolved at display level, in EntityDisplayBase::onDependencyRemoval(). I did that but now, I'm confused.
Comment #116
claudiu.cristeaDiscussed with @alexpott on IRC about providing the image style replacement select only when there are configurations depending on that image style. The conclusion was to not limit the display of the replacement select based on that. In this way we let any contrib module to benefit on the replacement and implement its own logic to update other configurations. So, the behaviour doesn't change. Compared to HEAD, I'm only suppressing the select element when there's no replacement at all on the system. But this makes a lot of sense in terms of UI & UX.
Comment #117
mondrake@claudiu.cristea so I understand in #116 we are removing a restriction that was looking only at dependent image widget/formatters during the deletion phase, and with this any config entity that has a dependency on an image style will be able to react to its deletion via its own implementation of
::onDependencyRemoval
?Couple of points below:
Is it possible to understand, at this stage, if there are configurations that depend on the image style being deleted?
If so, we might fine tune the message:
a) There are dependent configs, and there are possible replacements =>
$this->t('There are configuration elements that depend on this image style, and you can select another image style to replace it. If no replacement style is selected, the dependent configurations might need manual reconfiguration. All images that have been generated for this style will be permanently deleted.');
b) There are dependent configs, but there are NO possible replacements (i.e. we are deleting the last image style in the system) =>
$this->t('There are configuration elements that depend on this image style, and they might need manual reconfiguration. All images that have been generated for this style will be permanently deleted.');
c) There are no dependent configs =>
$this->t('All images that have been generated for this style will be permanently deleted.');
will be removed before Drupal 9.0.x
Comment #118
cilefen CreditAttribution: cilefen commentedComment #119
claudiu.cristea@mondrake, we are not checking anymore for dependencies. There are no more a), b) and c). Regardless if this style has dependencies or not, we are just a) provide the replacement, if there are or b) provide only an explanation and allow the deletion. Also we've discussed to keep as much as we can the UI strings. So the a) string is the same as in HEAD. The other one is a new string.
Comment #120
mondrake#119 ah all right then. Tested manually on simplytest.me, everything looks right. Updated the screenshots in the IS to reflect latest changes. RTBCing so to bring to the right eyes :)
I believe the minor change to the deprecation notice suggested in #117 can also be done on commit.
Thanks
Comment #122
mondrakeBot problem. Also the screenshots got lost :(, re-adding.
Comment #124
claudiu.cristeaThis was a bot failure.
Comment #125
alexpott@claudiu.cristea thanks for sticking with this - really nice work. Committed f986c6a and pushed to 8.0.x and 8.1.x. Thanks!
Some code style cleanup on commit and fixing #117 deprecation message.
Comment #129
Sebastien M. CreditAttribution: Sebastien M. commentedThe issue has been automatically closed.
However, does the 8.1.6 contains this fix ?
Currently I'm still having this issue with the 8.1.3
---- edited ----
My fault, it was about image style, but not matching this issue.
Sorry
Comment #130
mondrakeStrange, this was committed well before 8.1.0 - have you run update.php?
Comment #131
mondrake