Support for Drupal 7 is ending on 5 January 2025—it’s time to migrate to Drupal 10! Learn about the many benefits of Drupal 10 and find migration tools in our resource center.
Problem/Motivation
When you create content with an image without crop and edit to add a crop. We do not have the image must be emptied directly croper covers (ctrl + r) to see the image correctly croper.
Proposed resolution
When you have an manipulation of visual of image you need to invalidate the correspondant cache lie to this image generated by image.style. The pattern is config:image.style.* (eg: config:image.style.image_style_machine_name).
Comments
Comment #2
woprrr CreditAttribution: woprrr as a volunteer commentedThat patch fix this problem and invalidate only the cache tag corresponding to an image_style.
Edit :
The patch fix another problem.
When the user decides to change the picture style directly without touching the crop, then the change was not visible without emptying the browser cache with the cache invalidation after the application of the effect this will see the changes directly.
Comment #3
woprrr CreditAttribution: woprrr as a volunteer commentedAnother think,
I notice something that could be quite problematic with D8, the itok lie to images never changes even after a crop (or without crop after a effect modification to image). This can be very annoying in the case of using CDN akamai kind or other. The itok should change when an image is the derivative
What do you think about it ?
Comment #4
woprrr CreditAttribution: woprrr as a volunteer commentedan example to illustrate this think.
Comment #5
woprrr CreditAttribution: woprrr as a volunteer commentedThe previous comportement are fixed by ( https://github.com/drupal-media/crop/blob/8.x-1.x/src/Entity/Crop.php#L188 ) in last version of crop API. But i stay septic for interaction with akamai / varnish ... If path or query string not change the browser not send a query to cdn for inform the changes ?
@slashrsm you can inform me on that ?
Comment #6
woprrr CreditAttribution: woprrr as a volunteer commentedI ve investigate in this subject and found a solutions / explications thanks @scald team @jcisio @defr.
itok must not change it as long as the file is not physically move (the path).
The browser, makes him still the HTTP query asking if the image had been altered not by chance. What we will usually reply "304 Not modified" level of response HEADER in this case no problem nav uses the cache. In case the image correctly have suffered a flush (image_path_flush) and not necessarily the flush ($uri) that it does not go far enough. The fix is present in The latest version of crop_api (https://github.com/drupal-media/crop/blob/8.x-1.x/src/Entity/Crop.php#L188) with image_path_flush ( $ this-> uri-> value); the file that has an action applied imageStyle. Action that will lead to change the header of this resource and return a response '200' so the image must be recharged by the nav / CDN.
Most commercial CDN does not have an API to tell them "Attention this file to change, re-recovers before serving" (less). And it is the case of our only solution is to change the file name to work around these limitations, telling them to keep the "infinite".
Comment #7
woprrr CreditAttribution: woprrr as a volunteer commentedI think we need to add an other action like https://www.drupal.org/node/2658268#comment-10796022 because
flush() with arg not empty the caches when we pass an uri to this function we return juste $this if the image exist @see \Drupal\image\Entity\ImageStyle::flush() we not need an violent drupal_theme_rebuild(), but we need to invalidate the cache for applicative (drupal).
For me the #2 patch works well.
Comment #8
miro_dietikerNote that with NP8, we integrated with fastly and it can perfectly flush, even cache tag based.
Also you need to be careful when applying a min cache time since browsers can locally cache it without reasking for a change and your explicit flushes will never reach the browser.
IMHO the itok should change or some other thing in the URL should change if a crop changes (which doesn't).
ImageStyleDownloadController::deliver() finally uses getPathToken() and it seems that getPathToken() is not supporting anything to vary itok.
So we end up on the same problem as #2617818: Support multiple crop variants per URI and crop type
Comment #9
woprrr CreditAttribution: woprrr as a volunteer commented@miro Yes but for my project we have an akamai & varnish and with that when you change the crop, it's very problematic. The degraded solution found to get arround this limitation is add a query string with crop values saved when ImageStyle generate / re generate an image.
Comment #10
woprrr CreditAttribution: woprrr as a volunteer commentedATM the D8 core file system not permit to change something in the URL CDN to inform of a change in an image. This issue is related to all imageStyle that will be bring a change without changing the destination. The previous hook fix the problem by adding a query in the URL to inform of the change in the effect on the image.
ATM we need more informations about Drupal Core to continue i go create an issue to talk about it.
Comment #11
vurt CreditAttribution: vurt as a volunteer and at Computer Manufaktur GmbH commentedLike you said, it is a general problem: All crop modules are affected. Drupal providers with Varnish (like Pantheon) take extra meassures to purge the image from Varnish, see: https://www.drupal.org/node/2148619
To make the proposed solution from #9 works fine. For responsive images I had to use similar code in template_preprocess_responsive_image().
Comment #12
BerdirLets just try to convert #9 into a patch then, not sure what this is postponed. I don't think this is something that core can solve for us.
There are some interesting cases where not even having working cache invalidation (file name based, not cache tags, as files have no cache tags) helps. For example when using file entity and entity browser, and editing/croping a file when clicking on the edit button and expecting it to refresh when saving. Even when updating the HTML, which we do know, the browser dosn't reload the picture without a full page refresh.
Comment #13
mbovan CreditAttribution: mbovan at MD Systems GmbH commentedHere is the patch based on #9 placed in crop module.
Comment #14
Berdirwe should not hardcode public but parse it from the string, just like we do with the image style.
lets also add a comment to explain what we are doing.
Comment #15
mbovan CreditAttribution: mbovan at MD Systems GmbH commented.
Comment #16
mbovan CreditAttribution: mbovan at MD Systems GmbH commentedComment #17
woprrr CreditAttribution: woprrr as a volunteer commentedFully agree about @Berdir,
We not should use public hardcoded (in $file_uri and in pregmatch). we need to get schema with \Drupal\Core\File\FileSystem::uriScheme() ?
Comment #18
mbovan CreditAttribution: mbovan at MD Systems GmbH commentedI agree too. :) #13 was actually #9 as a patch file.
Tried to improve things with a new patch.
I'm a bit confused with this line. In the case of editing entity with entity browser (explained in #12), this means we are looking for (the last) "manual crop" effect added in the image style that's used to preview the image on the edit form?
Let's say global image widget configuration (admin/config/media/crop-widget) uses an image style (with no manual crop) for crop preview and all crop types are selected.
In case the cropping happens using the same cropping type used in mentioned preview-image-style, the image will be updated. In any other case, it won't.
If this is not the expected behaviour, it looks to me that missing information in this function is (chosen) crop type. Then, we could use that value to load the proper crop entity.
Comment #19
BerdirFinding the crop type has nothing to do with entity browser. It's based on the image style, and it will render the entity and based on the image style that is displayed, pick the right crop type. So please don't mention browser in the comments :)
Comment #20
miro_dietikerI think i would prefer to see a (shortened?) hash here than raw values. It's not about the numbers. It's just about uniqueness.
We are now depending on the crop record to determine changed values.
Alternatively we could say updating a crop should touch / update the file change timestamp. That's what we need to guarantee.
Thus, the only thing we would need to lookup and hash is the file change timestamp.
And then we automatically cover replacing a file and other kinds of potential alters, too.
But then also not sure if Crop API should provide the URL alter. We could easily apply this to all managed files.
Comment #21
BerdirDiscussed with miro. Relying on changed of the file entity (not the physical file) sounds like an interesting idea. using image styles on something else is possible but rare I'd say.
This will simplify this (although loading a file entity based on uri needs a query and will actually be slower) and it has the advantage that we could even suggest that core ads that.
For that to work, we'll also need to resave the file entity when saving a crop.
Comment #22
mbovan CreditAttribution: mbovan at MD Systems GmbH commentedIs this the idea of #22?
Comment #23
mbovan CreditAttribution: mbovan at MD Systems GmbH commentedIn discussion with @Berdir and @miro_dietiker, it seems that #18 is acceptable patch at this point.
Created a Core followup: #2800731: Add file change timestamp to the file URI related to #20 and #21.
Edit:
Created a Crop followup: #2800739: Improve findCrop() performance
Comment #24
BerdirYes, lets go with #18, but please update the comment.
Comment #25
mbovan CreditAttribution: mbovan at MD Systems GmbH commentedComment improvement by @Berdir.
The interdiff is against #18.
Comment #26
BerdirI think this is ready now.
Comment #27
slashrsm CreditAttribution: slashrsm at MD Systems GmbH commented#18 looks ok to me. Noticed two things:
If this is going to live in Crop API we can't depend on Image widget crop.
I like the idea of using a shortened hash here.
EDIT: Commented on wrong hunk.
Comment #28
miro_dietikerComment #29
mbovan CreditAttribution: mbovan at MD Systems GmbH commentedRemoved image widget crop manager and copied almost the same code to
crop_file_url_alter()
.Comment #30
BerdirThis looks good now I think. Since the hash is predictable, I think it actually shouldn't be too hard to extend e.g. \Drupal\Tests\crop\Kernel\CropCRUDTest::testCropSave() to generate an image style url for the test image and check that it has crop hash appended?
Comment #31
mbovan CreditAttribution: mbovan at MD Systems GmbH commentedHere are the tests. Didn't find any other way to test this except the one that's added here.
Also, seems there was a bug with regular expressions...
Comment #32
BerdirI honestly don't know what the http/https check is for. Lets remove that, the test shows that it doesn't really work (manually calling the alter hook is cheating :))
Comment #33
mbovan CreditAttribution: mbovan at MD Systems GmbH commentedThis is the test code that I would except to return the attached hash (based on crop that's created for the original file).
As
file_create_url()
triggerscrop_file_url_alter()
:- The processed URI (in crop_file_alter()) is:
public://styles/test/public/sarajevo.png
- While the public stream is something like this:
vfs://root/sites/simpletest/78359729/files
Does this mismatch mean we need to call
file_create_url()
twice: the first time to get absolute URL and the second time to assert the hash?Or it means
PublicStream::basePath()
incrop_file_url_alter()
is not necessary?Comment #36
mbovan CreditAttribution: mbovan at MD Systems GmbH commentedSwitched to the web test with some support for rare cases.
Still not sure about
PublicStream::basePath()
in the first condition...Uploaded a "test" patch that has changed URI in the crop entity.
Comment #39
Berdirhash.
I think the actual hash isn't even that important. What would be nice is to change the crop now and make sure we get a different hash than the first one.
what's this for?
Comment #40
mbovan CreditAttribution: mbovan at MD Systems GmbH commentedAdded a new test to assert the hash has changed.
#39.3: The UI tests executed after tries to delete the crop type via UI and fails because there are some entities using it.
Comment #41
woprrr CreditAttribution: woprrr as a volunteer commented@mbovan I promise i can test your patch Fast too.
Comment #42
woprrr CreditAttribution: woprrr as a volunteer commentedI think we need to cover all cases purposed by Drupal file, private file storage particulary with PrivateStream::basePath()i think we have few problems with this. I need your opinion @slashrsm / berdir / mbovan / miro. Can we support this in this issue or move it on other issue to cover this case ? I am sure in IWC we have users using private file storage or external file storage. That can be an complexity to support this but necessary (not sure in this issue).
That is not required because crop api already have an mecanic when file are deleted @see crop_file_delete()
Comment #43
woprrr CreditAttribution: woprrr as a volunteer commentedInfact i think ATM that case need to be traited in another issue, is very specific to private Stream. I prefer to validate that generic and more case step by step and stop the polemic in 4X reply :P
For the second point, i ve deleted wrong crop->delete() in test because that is already deleted by file whenever you have use $file->deleted(). And add an check to unsure crop are correctly deleted for our case. It's NOT an duplicate of CRUD test testOrphanRemoval() but complementary into this functional test.
All other cases ALL WORK A CHARM for me :)
I think we have a final patch here *_* (i hope) mbovan can you test it too and i think can we pass to RTBC (My dream for that issue :D)
Comment #44
moshe weitzman CreditAttribution: moshe weitzman commentedI was excited to try out this patch, but it seems to not work for my site. We are using the 'FocalPointScaleAndCropImageEffect' effect from Focal Point module. This effect has a CropStorage object, so definitely builds uno crop module. Yet the patch checks for
if (isset($data_effect['crop_type'])) {
and that check fails for this effect. It would be good if it did not. Any advice? Should this be fixed in Focal Point module?Comment #45
woprrr CreditAttribution: woprrr as a volunteer commented@slashrsm, I think that can be merged now patch sound good and we need to have that important support with stable version !
@moshe weitzman I think that is due to an focal problem during implement of these effect ? That doesn't block that issue IMHO we can work on it on another and permit to other users to work with this patch.
Comment #46
woprrr CreditAttribution: woprrr at NeoLynk commentedGreat LGTM :)
Comment #48
woprrr CreditAttribution: woprrr at NeoLynk commentedGOD !!! This issue is merged *_* Now I can drink lots of beer to forget :D Just one thing not blocker for merged this issue. In picture (Classic) context the patch work well but I guess we have an specific case with responsive images and srcset to correctly refresh the picture because all images listed in srcset aren’t flagged with shorten_hash... Not sure if this works but it’s isolated problems that do be fixed in another issue if we have a bug with that.
This BIG BIG Part merged !!!
Comment #50
Berdir@moshe: This module currently only works with the manual crop effect added by this, if focal point has its own effect then it either has to at least match the configuration structure, then it might work or duplicate the logic here.
Anyway, this is not working very well and definitely broken for responsive images, where it doesn't even get that far: #2868339: Public folder check in crop_file_url_alter() is incorrect, does not work for responsive images