Problem/Motivation

This is a sister issue of #2517030: Add a URL formatter for the image field and #2825487: Fix normalization of File entities: file entities should expose the file URL as a computed property on the 'uri' base field. The former issue solved it for image entities exposed via Views REST export displays. This issue must solve it at the serialization/normalization level, so that all REST resources (as well as JSON API) benefit.

The latter issue already is doing it for FileItem (and hence ImageItem because it extends FileItem), but only for the "canonical" file URL. In the case of ImageItem, we also want image style URLs.

Proposed resolution

Add ImageItemNormalizer.

Remaining tasks

None.

User interface changes

None.

API changes

Adds an API to allow explicit bubbling of cacheability metadata: pass in a 'cacheability' => instanceof CacheableMetadata key-value pair in the serialization context.

(The ImageItem normalizer that we add here uses this to its advantage: this new capability allows that normalizer to be properly unit-testable. No more global state manipulation! See #67's interdiff.)

Data model changes

None.

CommentFileSizeAuthor
#248 interdiff-247-248.txt503 bytesRassoni
#248 2825812-248.patch13.87 KBRassoni
#247 interdiff-245-247.txt961 bytesRassoni
#247 2825812-247.patch13.84 KBRassoni
#245 interdiff_240-245.txt2.52 KBravi.shankar
#245 2825812-245.patch13.54 KBravi.shankar
#240 interdiff_239-240.txt1.34 KBvsujeetkumar
#240 2825812-240.patch13.48 KBvsujeetkumar
#239 interdiff_237-239.txt4.66 KBvsujeetkumar
#239 2825812-239.patch13.51 KBvsujeetkumar
#237 2825812-237.patch13.32 KBvsujeetkumar
#233 reroll_diff_229-233.txt4.85 KBVinay15
#233 2825812-233.patch13.32 KBVinay15
#232 2825812-232.patch13.5 KBiivanov
#229 2825812_229.patch13.5 KBvsujeetkumar
#227 interdiff-2825812-214-227.txt698 bytesndobromirov
#227 2825812-227.patch14.2 KBndobromirov
#224 interdiff-212-224.txt698 bytesndobromirov
#224 2825812-224.patch14.18 KBndobromirov
#214 2825812-214.patch14.16 KBvtcore
#212 2825812-212.patch14.21 KBmiiimooo
#205 2825812-205.patch14.28 KBjofitz
#205 interdiff-2825812-201-205.txt6.81 KBjofitz
#201 2825812-201.patch6.93 KBe0ipso
#201 2825812--interdiff--199-201.txt1.45 KBe0ipso
#199 2825812-199.patch13.99 KBWim Leers
#199 interdiff.txt1.01 KBWim Leers
#197 2825812-197.patch13.11 KBWim Leers
#197 interdiff.txt4.1 KBWim Leers
#195 2825812-195.patch11.84 KBWim Leers
#195 interdiff.txt3 KBWim Leers
#194 interdiff-187-194.txt1.19 KBWim Leers
#194 2825812-194.patch10.41 KBWim Leers
#191 interdiff-2825812-180-191.txt622 bytesBR0kEN
#191 2825812-191.patch14.41 KBBR0kEN
#187 2825812-187.patch10.35 KBWim Leers
#187 interdiff.txt1.51 KBWim Leers
#186 2825812-186.patch10.22 KBWim Leers
#186 interdiff.txt1.38 KBWim Leers
#182 2825812-182.patch8.96 KBWim Leers
#182 interdiff.txt2.52 KBWim Leers
#181 2825812-181.patch8.97 KBWim Leers
#181 interdiff-156-181.txt5.82 KBWim Leers
#180 interdiff-2825812-177-180.txt1.51 KBBR0kEN
#180 interdiff-2825812-156-180.txt15.87 KBBR0kEN
#180 2825812-180.patch14.36 KBBR0kEN
#177 interdiff-2825812-176-177.txt1017 bytesBR0kEN
#177 interdiff-2825812-156-177.txt14.35 KBBR0kEN
#177 2825812-177.patch14.45 KBBR0kEN
#176 interdiff-2825812-173-176.txt306 bytesBR0kEN
#176 interdiff-2825812-156-176.txt14.35 KBBR0kEN
#176 2825812-176.patch14.45 KBBR0kEN
#173 interdiff-2825812-172-173.txt1.68 KBBR0kEN
#173 interdiff-2825812-156-173.txt14.33 KBBR0kEN
#173 2825812-173.patch14.45 KBBR0kEN
#172 interdiff-2825812-170-172.txt6.03 KBBR0kEN
#172 interdiff-2825812-156-172.txt13.71 KBBR0kEN
#172 2825812-172.patch14.5 KBBR0kEN
#170 interdiff-2825812-156-170.txt11.36 KBBR0kEN
#170 2825812-170.patch13.59 KBBR0kEN
#156 2825812-156.patch12.16 KBalexpott
#156 146-156-interdiff.txt13.52 KBalexpott
#146 2825812-146.patch13.21 KBalexpott
#146 144-146-interdiff.txt2.36 KBalexpott
#144 2825812-144.patch12.87 KBalexpott
#144 141-144-interdiff.txt13.19 KBalexpott
#141 2825812-141.patch20.88 KBalexpott
#141 140-141-interdiff.txt9.52 KBalexpott
#140 2825812-140.patch14.58 KBalexpott
#140 139-140-interdiff.txt5.48 KBalexpott
#139 2825812-139.patch13.72 KBjustafish
#137 2825812-137.patch14.96 KBjustafish
#136 interdiff.txt3.28 KBjustafish
#136 2825812-135.patch13.59 KBjustafish
#127 2825812-properly_use_typed_data_but_i_cant_figure_it_out-do-not-test.patch3.67 KBWim Leers
#124 2825812-124.patch11.89 KBWim Leers
#124 interdiff.txt2.16 KBWim Leers
#120 interdiff.txt862 bytesWim Leers
#119 2825812-119.patch11.79 KBWim Leers
#119 interdiff.txt1.12 KBWim Leers
#116 2825812-115.patch11.79 KBWim Leers
#116 interdiff.txt2.65 KBWim Leers
#114 2825812-114.patch11.79 KBWim Leers
#114 interdiff.txt5.51 KBWim Leers
#110 2825812-110.patch8.63 KBWim Leers
#110 interdiff.txt2.55 KBWim Leers
#107 2825812-107.patch6.15 KBWim Leers
#107 Screen Shot 2017-11-09 at 12.01.17.png97.55 KBWim Leers
#107 Screen Shot 2017-11-09 at 11.57.30.png80.94 KBWim Leers
#101 2825812-101.patch20.16 KBtedbow
#101 interdiff-98-101.txt5.75 KBtedbow
#98 2825812-98.patch19.15 KBtedbow
#98 interdiff-91-98.txt1.71 KBtedbow
#91 2825812-91.patch19.08 KBWim Leers
#91 interdiff.txt5.1 KBWim Leers
#90 2825812-90.patch18.1 KBtedbow
#90 interdiff-87-90.txt581 bytestedbow
#87 2825812-87.patch17.53 KBtedbow
#87 interdiff-83-87.txt669 bytestedbow
#83 interdiff-72-82.txt526 bytesjofitz
#83 2825812-82.patch16.88 KBjofitz
#72 interdiff-70-72.txt4.3 KBtedbow
#72 2825812-72.patch16.92 KBtedbow
#70 interdiff-2825812-67-70.txt1.91 KBhimanshu-dixit
#70 2825812-70.patch16.97 KBhimanshu-dixit
#67 2825812-67.patch17.01 KBtedbow
#67 interdiff.txt9.68 KBtedbow
#62 2825812-62.patch17.14 KBtedbow
#62 interdiff-60-62.txt5.01 KBtedbow
#60 2825812-60.patch16.42 KBtedbow
#60 interdiff-57-60.txt1.91 KBtedbow
#57 2825812-57.patch16.36 KBmartin107
#57 interdiff-2825812-52-57.txt7.05 KBmartin107
#52 interdiff-2825812-49-52.txt1.35 KBmartin107
#52 2825812-52.patch16.71 KBmartin107
#49 interdiff-2825812-45-49.txt11.04 KBmartin107
#49 2825812-49.patch16.68 KBmartin107
#45 interdiff-2825812-41-45.txt11.31 KBmartin107
#45 2825812-45.patch16.13 KBmartin107
#41 2825812-41.patch16.99 KBtedbow
#41 interdiff-38-41.txt6.93 KBtedbow
#38 interdiff-34-38.txt3.43 KBtedbow
#38 2825812-38.patch16.88 KBtedbow
#34 interdiff-30-34.txt11.49 KBtedbow
#34 2825812-34.patch16.72 KBtedbow
#30 interdiff-27-30.txt7.83 KBtedbow
#30 2825812-30.patch14.29 KBtedbow
#27 2825812-27.patch10.21 KBtedbow
#27 2825812-27-plus-2827218-47.patch41.74 KBtedbow
#27 interdiff-26-27.txt734 bytestedbow
#26 2825812-26.patch10.21 KBtedbow
#26 interdiff-19-26.txt1.24 KBtedbow
#26 2825812-19-plus-2827218-47.patch41.66 KBtedbow
#19 interdiff-11-19.txt3.13 KBtedbow
#19 2825812-19.patch10.14 KBtedbow
#11 interdiff-9-11.txt4.3 KBtedbow
#11 2825812-11.patch8.89 KBtedbow
#9 interdiff-6-9.txt7.42 KBtedbow
#9 2825812-9.patch8.79 KBtedbow
#6 interdiff-4-6.txt1.84 KBtedbow
#6 2825812-6.patch8.33 KBtedbow
#4 2825812-3-image_styles_normalization.patch8.23 KBtedbow
Support from Acquia helps fund testing for Drupal Acquia logo

Comments

Wim Leers created an issue. See original summary.

tedbow’s picture

Assigned: Unassigned » tedbow

Working on this.

tedbow’s picture

Status: Active » Needs review
FileSize
8.23 KB

ok here is patch.
It has a test.

This was similar to #2626924: Include processed text in normalizations: "text" field type's "processed" computed property should be non-internal and carry cacheability metadata
\Drupal\Core\Cache\CacheDependencyBubbleTrait was copied directly from there

Couple questions I had:
#2517030: Add a URL formatter for the image field provides the image styles URLs using relative urls. I used relative urls here. But EntityReferenceFieldItemNormalizer which this extends provides the absolute URL. so for images field items you get both like this:

 (
                    [target_id] => 1
                    [alt] => jkk
                    [title] => 
                    [width] => 970
                    [height] => 1339
                    [target_type] => file
                    [target_uuid] => 96572986-4381-4037-ae87-534353c72d9f
                    [url] => http://www.octo2.dev/d8_3_rest/sites/default/files/2016-11/sadtear.jpg
                    [image_styles] => Array
                        (
                            [large] => /d8_3_rest/sites/default/files/styles/large/public/2016-11/sadtear.jpg?itok=GEE2-4vL
                            [medium] => /d8_3_rest/sites/default/files/styles/medium/public/2016-11/sadtear.jpg?itok=GPXdb1lB
                            [thumbnail] => /d8_3_rest/sites/default/files/styles/thumbnail/public/2016-11/sadtear.jpg?itok=O2emam6p
                        )

                )

Should we change this to use absolute URLs or provide and extra 'image_url' or should EntityReferenceFieldItemNormalizer provide relative?

I added the cache dependencies for each image styles because if you change the machine name or deleted an image style the urls would update. but also if you added another image style the array would need to be updated. Not sure how to handle that.

dawehner’s picture

This looks pretty good!

  1. +++ b/core/modules/image/src/Normalizer/ImageFieldItemNormalizer.php
    @@ -0,0 +1,62 @@
    +    $styles = $this->entityTypeManager->getStorage('image_style')->loadMultiple();
    +    if ($styles) {
    +      $data['image_styles'] = [];
    

    I'm wondering whether we should always provide the 'image_styles' key, so client code does not have to explicitly check it.

  2. +++ b/core/modules/image/src/Normalizer/ImageFieldItemNormalizer.php
    @@ -0,0 +1,62 @@
    +        $data['image_styles'][$id] = file_url_transform_relative($style->buildUrl($uri));
    

    I think using an absolute URL is the right thing to do, because it makes it easier to use in a custom client. In case it would be a relative URL, the client code would need to know the base URL, do the appending of strings etc.

tedbow’s picture

@dawehner thanks for the review!

1,2 makes sense and fixed

I also change the priority of the new service because it has to be lower than serializer.normalizer.entity_reference_item.hal or it will break Image fields for HAL.
Which brings up should we be doing the same thing in the HAL module? If so should that be a follow up?

If we don't do it in for HAL should still in follow up create a test in HAL for any field type that extends EntityReference that current normalizer works. Because this normalizer with the higher priority broke Image references in HAL but there were no tests. The same could happen with \Drupal\file\Plugin\Field\FieldType\FileItem

tedbow’s picture

Assigned: tedbow » Unassigned

Unassigning

Wim Leers’s picture

Status: Needs review » Needs work

#4:

This was similar to #2626924: Include processed text in normalizations: "text" field type's "processed" computed property should be non-internal and carry cacheability metadata \Drupal\Core\Cache\CacheDependencyBubbleTrait was copied directly from there

Yay!

But EntityReferenceFieldItemNormalizer which this extends provides the absolute URL.

That's not a file URL. All file URLs must be root-relative since #1494670: References to CSS, JS, and similar files should be root-relative URLs: avoids mixed content warnings & fewer bytes to send.

#5.2:

I think using an absolute URL is the right thing to do, because it makes it easier to use in a custom client. In case it would be a relative URL, the client code would need to know the base URL, do the appending of strings etc.

I humbly disagree. Absolute URLs are fine for fully decoupled apps where the end user-facing app is a web app that lives on a different domain or is a native app. But in all other cases, the root-relative URL is much more useful. It's much easier to do domain + string_the_rest_api_sent_me than it is to parse a URL into the separate components and then reassemble correctly again. And for progressively decoupled use cases, you'll want relative URLs anyway.


#6:

Which brings up should we be doing the same thing in the HAL module?

IMO it should be done here. Fix the normalization across all supported formats in one go. It's very closely related anyway. And probably you can even share some of the test coverage code. Which also benefits from updating the default normalization and HAL's at the same time.


  1. +++ b/core/lib/Drupal/Core/Cache/CacheDependencyBubbleTrait.php
    @@ -0,0 +1,34 @@
    +trait CacheDependencyBubbleTrait {
    

    The equivalent in #2626924: Include processed text in normalizations: "text" field type's "processed" computed property should be non-internal and carry cacheability metadata was updated significantly. Let's pull in the latest iteration from there.

  2. +++ b/core/modules/image/src/Normalizer/ImageFieldItemNormalizer.php
    @@ -0,0 +1,60 @@
    +class ImageFieldItemNormalizer extends EntityReferenceFieldItemNormalizer {
    

    s/ImageFieldItem/ImageItem/

  3. +++ b/core/modules/image/src/Normalizer/ImageFieldItemNormalizer.php
    @@ -0,0 +1,60 @@
    +    /** @var \Drupal\file\Entity\File $image */
    

    Must use interface.

  4. +++ b/core/modules/image/src/Normalizer/ImageFieldItemNormalizer.php
    @@ -0,0 +1,60 @@
    +    $image = $this->entityTypeManager->getStorage('file')->load($data['target_id']);
    

    Why not use File::loadMultiple()?

  5. +++ b/core/modules/image/src/Normalizer/ImageFieldItemNormalizer.php
    @@ -0,0 +1,60 @@
    +    /** @var \Drupal\image\Entity\ImageStyle[] $styles */
    

    Must use interface.

  6. +++ b/core/modules/image/src/Normalizer/ImageFieldItemNormalizer.php
    @@ -0,0 +1,60 @@
    +    $styles = $this->entityTypeManager->getStorage('image_style')->loadMultiple();
    

    Why not use ImageStyle::loadMultiple()?

  7. +++ b/core/modules/image/tests/src/Kernel/Normalizer/ImageFieldItemNormalizerTest.php
    @@ -0,0 +1,107 @@
    +    /** @var \Drupal\image\Entity\ImageStyle $image_style */
    

    Interface.

  8. +++ b/core/modules/image/tests/src/Kernel/Normalizer/ImageFieldItemNormalizerTest.php
    @@ -0,0 +1,107 @@
    +      $cache_tags = array_merge($cache_tags, $image_style->getCacheTags());
    

    Use Cache::mergeTags().

  9. +++ b/core/modules/image/tests/src/Kernel/Normalizer/ImageFieldItemNormalizerTest.php
    @@ -0,0 +1,107 @@
    +    $image_style_keys = array_keys($data['image_test'][0]['image_styles']);
    

    $image_style_ids

tedbow’s picture

Status: Needs work » Needs review
FileSize
8.79 KB
7.42 KB

#5.2 added back file_url_transform_relative

#6 ok. will do hal in this issue(not in this patch)

1. pulled in other version with new name though had to add back \Drupal\Core\Cache\ConditionalCacheabilityMetadataBubblingTrait::renderer

2. fixed - also changed test name to match
3. fixed
4. you mean File::load() not File::loadMultiple() right? if so fixed
5-9 fixed

Wim Leers’s picture

+++ b/core/lib/Drupal/Core/Cache/ConditionalCacheabilityMetadataBubblingTrait.php
@@ -0,0 +1,42 @@
+  /**
+   * Gets the render service.
+   *
+   * @return \Drupal\Core\Render\RendererInterface
+   *   The renderer.
+   */
+  protected function renderer() {
+    return isset($this->renderer) ? $this->renderer : \Drupal::service('renderer');
+  }

This method was removed in the other issue.

Other than that, this looks great. All the remains, is HAL support.

tedbow’s picture

#9.2 I didn't actually update the test name. Fixed.

re #10

This method was removed in the other issue.

Fixed

Also fix couple small nits in Test.

tedbow’s picture

Here are the nits I was referring to in #11

  1. +++ b/core/modules/image/src/Normalizer/ImageItemNormalizer.php
    @@ -29,13 +30,23 @@ class ImageItemNormalizer extends EntityReferenceFieldItemNormalizer {
    +   * The renderer.
    +   *
    +   * @var \Drupal\Core\Render\RendererInterface
    +   */
    +  protected $renderer;
    +
    +  /**
    

    Didn't declare field

  2. +++ b/core/modules/image/tests/src/Kernel/Normalizer/ImageItemNormalizerTest.php
    @@ -66,7 +73,6 @@ protected function setUp() {
    -    $this->imageFactory = $this->container->get('image.factory');
    

    This was never used. c/p error

Wim Leers’s picture

Status: Needs review » Needs work

Cool. :) So, now zero nits remain, we just need to update the HAL normalization to do the same!

garphy’s picture

Just a thought, we used to implement this in D7 (as an extension of the Service Entity module.

We started exactly like this patch, outputting an associative array of URL indexed by style name but we quickly concluded that it is in most case not enough as there is other useful pieces of information alongside the style URL itself, such as the resulting derivative dimensions.

So instead of just a string literal, we output an associative array with the "URL", "width" and "height" keys.

I would suggest switching to that kind of output.

Wim Leers’s picture

Great feedback, thanks @garphy!

tedbow’s picture

re #14 I think this could open up can of worms.

So instead of just a string literal, we output an associative array with the "URL", "width" and "height" keys.

We can't determine the width or height by just looking at the image style. For instance if you scale an image but only specify height width will be different for each image.
Also if you don't "Allow Upscaling" then you can't tell either because the image could be smaller and then not scaled. Also what about all the contrib image effects where we don't know how to determine the dimensions?

If we had to look at each individual processed image to see what the dimensions are what about images where a particular(or all) image style derivatives have not been made yet? are they still made when first requested? Do we force them to be created so we can provide dimensions?

garphy’s picture

I've not checked if it's still the case with D8 API (Sorry!) but with D7's Style API, each style operation provide a callback used to compute the final dimension of the image without actually execute the operations, thus allowing to compute the resulting dimensions without creating all possible derivatives.

Of course there will still be edge cases were this precalculation cannot be made, but we still can provide it for the ~90% use cases.

When an (integrated) drupal theme outputs a Only local images are allowed. tag, it use this API to know the dimensions of the image (populating the width/height attributes) without actually generate the image. It'll be generated when the browser will actually request it.

tedbow’s picture

I've not checked if it's still the case with D8 API (Sorry!)

No problem at all.

but with D7's Style API, each style operation provide a callback used to compute the final dimension of the image without actually execute the operations, thus allowing to compute the resulting dimensions without creating all possible derivatives.

Interesting I will look to see if I can find this in D8.

If it exists still I would be interested if anyone knows what kind of overhead that might involve. Thinking of entities with lots image fields or multiple value image fields with lots of images on 1 entity.

UPDATE:
Ok this is probably it \Drupal\image\ImageStyleInterface::transformDimensions
The docs don't explicitly say the derivative is not created but that would make sense.

So I guess if the overhead is not a concern this seems doable.

tedbow’s picture

Status: Needs work » Needs review
FileSize
10.14 KB
3.13 KB

Ok here is patch does @garphy suggestion in #14 and adds the height and width as well as url.

It also updates the tests. In the test I had to set all the effect to "upscale" or the dimensions would be the same for all styles.

As per @Wim Leers' comment on #13 this still needs the hal work done.

tedbow’s picture

Re my worry

So I guess if the overhead is not a concern this seems doable.

I was imagining some image processing going on which is not done. At least for scaling this is done in \Drupal\Component\Utility\Image::scaleDimensions which is just calculations.

dawehner’s picture

garphy’s picture

@dawhener: Why would it revert this ? In my understanding, Media brings in a new entity type alongside File entities, not replacing it.

Wim Leers’s picture

I think having width + height makes sense also from a decoupled POV: if you want to use those image URLs to generate <img src="URL" width="WIDTH" height="HEIGHT">, then you need width and height. <img src="URL"> (without width+height) is a bad practice. It causes poor performance, because it requires the browser to reflow layout, since it cannot know the image dimensions.

So +1 from that POV.

damiankloip’s picture

Also totally +1 on having the height and width.

  1. +++ b/core/modules/image/src/ImageServiceProvider.php
    @@ -0,0 +1,35 @@
    +      $service_definition->addTag('normalizer', ['priority' => 7]);
    

    I think this is still ok after https://www.drupal.org/node/2827218 ?

  2. +++ b/core/modules/image/src/Normalizer/ImageItemNormalizer.php
    @@ -0,0 +1,79 @@
    +  public function normalize($object, $format = NULL, array $context = array()) {
    

    nit: new array syntax [] ?

  3. +++ b/core/modules/image/src/Normalizer/ImageItemNormalizer.php
    @@ -0,0 +1,79 @@
    +    $image = File::load($data['target_id']);
    ...
    +    $styles = ImageStyle::loadMultiple();
    

    Not sure if it matters too much in the grand scheme of things, but we could get the entity storage from the entity type manager and use load() from that. Same goes for both here.

  4. +++ b/core/modules/image/src/Normalizer/ImageItemNormalizer.php
    @@ -0,0 +1,79 @@
    +        'url' => file_url_transform_relative($style->buildUrl($uri)),
    

    Do you think there is any value to having both absolute and relative? definitely relative is the more useful/flexible one.

tedbow’s picture

1. in #2827218: Denormalization on field items is never called: add FieldNormalizer + FieldItemNormalizer with denormalize() methods serialization.normalizer.field_item priority is set to 6 so 7 for image.normalizer.image_item would work(needs to be higher).
but just to be sure including a patch that combines 2825812-19.patch and 2827218-47.patch
2. fixed
3. With on going expansion of the universe what really matters in grand scheme of things?? but Fixed.
4. I would be in favor of just providing relative. clients should be able to easily create absolute if needed.

tedbow’s picture

The combination patch 2825812-19-plus-2827218-47.patch actually failed. Not sure why it is green.

I forgot that image.normalizer.image_item needs be higher than serializer.normalizer.entity_reference_field_item because an image reference is a special kind of entity reference.

The last submitted patch, 27: 2825812-27-plus-2827218-47.patch, failed testing.

Status: Needs review » Needs work

The last submitted patch, 27: 2825812-27.patch, failed testing.

tedbow’s picture

Status: Needs work » Needs review
FileSize
14.29 KB
7.83 KB

Ok this patch provides a new \Drupal\image\Normalizer\ImageItemHalNormalizer
and \Drupal\image\Normalizer\ImageItemNormalizerTrait
The trait is used because the adding the Image style information is mostly the same between hal and default.

I haven't had time to create the new test yet but just thought I should post it before I finish for the day. Also will prove it doesn't break any of the existing tests(hopefully, worked locally).

Status: Needs review » Needs work

The last submitted patch, 30: 2825812-30.patch, failed testing.

tedbow’s picture

Status: Needs work » Needs review

retesting.

Status: Needs review » Needs work

The last submitted patch, 30: 2825812-30.patch, failed testing.

tedbow’s picture

Status: Needs work » Needs review
FileSize
16.72 KB
11.49 KB

Ok I am not sure what the CI error was in #30

This patch adds the testing for the Hal normalizer.

Status: Needs review » Needs work

The last submitted patch, 34: 2825812-34.patch, failed testing.

tedbow’s picture

Status: Needs work » Needs review

Test passed again

dawehner’s picture

  1. +++ b/core/modules/image/src/ImageServiceProvider.php
    @@ -0,0 +1,51 @@
    +      // Priority should be higher than
    +      // serializer.normalizer.entity_reference_field_item but lower than
    +      // serializer.normalizer.entity_reference_item.hal.
    +      $service_definition->addTag('normalizer', ['priority' => 9]);
    ...
    +      // Priority should be higher than
    +      // serializer.normalizer.entity_reference_item.hal which 10.
    +      // Priority of 20 gives the ability to have other normalizers between this
    +      // one and serializer.normalizer.entity_reference_item.hal.
    +      $service_definition->addTag('normalizer', ['priority' => 20]);
    

    Just an idea for the future and maybe for new normalizes, ... what about watching both service definitions get the priority and then choose a priority of (A+B)/2

  2. +++ b/core/modules/image/src/Normalizer/ImageItemNormalizerTrait.php
    @@ -0,0 +1,41 @@
    +    $image = $this->entityTypeManager->getStorage('file')
    +      ->load($item->target_id);
    +    $uri = $image->getFileUri();
    

    I'm wondering whether we should check whether this image actually exists.

  3. +++ b/core/modules/image/src/Normalizer/ImageItemNormalizerTrait.php
    @@ -0,0 +1,41 @@
    +      $dimensions = ['width' => $item->width, 'height' => $item->height];
    

    Note: This could be moved outside of the loop

  4. +++ b/core/modules/image/tests/src/Kernel/Normalizer/ItemItemNormalizerBase.php
    @@ -0,0 +1,168 @@
    +    foreach ($normalized_image_styles as $id => $img_info) {
    

    IMHO we should not provide short variable names

tedbow’s picture

@dawehner thanks for the review.
1. It seems like having hard-coded numbers while not perfect at least allows custom and contrib normalizers to know where they are in relation to core normalizers. Though custom and contrib could also follow the dynamic method you suggested there are probably normalizers using hard-coded values and developers who are use to this.
2. Fixed
3. This actually has to be inside the loop because $dimensions is passed by reference to \Drupal\image\ImageStyleInterface::transformDimensions. Then the "Implementations have to store the resulting width and height, in pixels." So it is changed in with each iteration of the loop and needs to be reset the original image dimensions.
4. Good suggestion! changed $id to $image_style_id and $img_info to $image_style_dimensions

dawehner’s picture

Status: Needs review » Reviewed & tested by the community
  1. +++ b/core/modules/image/src/Normalizer/ImageItemNormalizerTrait.php
    @@ -19,22 +19,22 @@
    +        $dimensions = ['width' => $item->width, 'height' => $item->height];
    +        $style->transformDimensions($dimensions, $uri);
    

    The world is a sad place ... like I would have expected this method to return the transformed dimensions. Of course this is not caused by this particular patch.

  2. +++ b/core/modules/image/tests/src/Kernel/Normalizer/ItemItemNormalizerBase.php
    @@ -130,10 +130,10 @@ public function testNormalize() {
    +      $this->assertNotEmpty(strstr($image_style_dimensions['url'], "files/styles/$image_style_id/public/example.jpg"));
    

    Nitpick, when there is time between now and the commit: We could use assertContains here.

Wim Leers’s picture

Status: Reviewed & tested by the community » Needs work

I think this looks great. I have a bunch of nitpicks, and some naming concerns that are easily fixed.

There is one bigger concern: BC. Can we really just enable this? This would change the responses, just like #2751325: All serialized values are strings, should be integers/booleans when appropriate, only much more so! That one has a BC layer, this one does not. Yet that one is getting BC concerns raised. So I'm pretty sure they'll be raised here too.

  1. +++ b/core/modules/image/src/ImageServiceProvider.php
    @@ -0,0 +1,51 @@
    +      // serializer.normalizer.entity_reference_item.hal which 10.
    

    Nit s/which 10/which is 10/

  2. +++ b/core/modules/image/src/Normalizer/ImageItemHalNormalizer.php
    @@ -0,0 +1,71 @@
    + * ImageItem normalizer to provide URLs to image styles.
    

    s/ImageItem normalizer/ImageItem HAL normalizer/

  3. +++ b/core/modules/image/src/Normalizer/ImageItemHalNormalizer.php
    @@ -0,0 +1,71 @@
    +   * Constructs an ImageItemNormalizer object.
    

    ImageItemHalNormalizer

  4. +++ b/core/modules/image/src/Normalizer/ImageItemNormalizerTrait.php
    @@ -0,0 +1,41 @@
    +   * Adds images style information to normalized ItemItem field data.
    

    s/images/image/
    s/ItemItem/ImageItem/

  5. +++ b/core/modules/image/src/Normalizer/ImageItemNormalizerTrait.php
    @@ -0,0 +1,41 @@
    +   *   The field image item.
    

    I think: The image field.? It currently is pretty strange.

  6. +++ b/core/modules/image/src/Normalizer/ImageItemNormalizerTrait.php
    @@ -0,0 +1,41 @@
    +   * @param array $data
    +   *   The normalized field data.
    

    $data is super generic.

    I think this would be clearer:

    * @param array $normalization.
    *   The image field normalization to add image style information to.
    
  7. +++ b/core/modules/image/tests/src/Kernel/Normalizer/ImageItemHalNormalizerTest.php
    @@ -0,0 +1,36 @@
    +class ImageItemHalNormalizerTest extends ItemItemNormalizerBase {
    
    +++ b/core/modules/image/tests/src/Kernel/Normalizer/ImageItemNormalizerTest.php
    @@ -0,0 +1,23 @@
    +class ImageItemNormalizerTest extends ItemItemNormalizerBase {
    
    +++ b/core/modules/image/tests/src/Kernel/Normalizer/ItemItemNormalizerBase.php
    @@ -0,0 +1,168 @@
    + * Base class for ItemItemNormalizer testing.
    ...
    +abstract class ItemItemNormalizerBase extends KernelTestBase {
    

    ItemItemNormalizerBase?

    ImageItemNormalizerBase!

  8. +++ b/core/modules/image/tests/src/Kernel/Normalizer/ItemItemNormalizerBase.php
    @@ -0,0 +1,168 @@
    +    // Change all images style scale effect to upscale.
    

    Needs a touch of language improvement :)

  9. +++ b/core/modules/image/tests/src/Kernel/Normalizer/ItemItemNormalizerBase.php
    @@ -0,0 +1,168 @@
    +   * @param array $data
    

    s/$data/$normalization/

tedbow’s picture

Status: Needs work » Needs review
FileSize
6.93 KB
16.99 KB

#39.2 fixed

#40
1-4 fixed
5. Changed from "The field image item." to "The image field item."
IMHO "The image field." doesn't specify it is an individual item in a field list.
6,7 fixed
8. changed to "Set upscale to TRUE in all image style scale effects."
9. fixed

RE

There is one bigger concern: BC. Can we really just enable this? This would change the responses, just like #2751325: All serialized values are strings, should be integers/booleans when appropriate, only much more so!

I think #2751325: All serialized values are strings, should be integers/booleans when appropriate is more disruptive because it changes the data types of existing parts of the response. This just adds new elements on the field item level which is more like #2060677: Add target_type, target_uuid to serialized output of entity reference fields in non-HAL formats. There was no BC layer for that. The client would have to be validating that no unknown keys on the field item level in both case to break.

Version: 8.3.x-dev » 8.4.x-dev

Drupal 8.3.0-alpha1 will be released the week of January 30, 2017, which means new developments and disruptive changes should now be targeted against the 8.4.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

Wim Leers’s picture

Status: Needs review » Needs work
  1. +++ b/core/lib/Drupal/Core/Cache/ConditionalCacheabilityMetadataBubblingTrait.php
    @@ -0,0 +1,32 @@
    +   * Bubbles cacheability metadata to the current render context.
    

    "to the current render context, if any"

  2. +++ b/core/modules/image/src/ImageServiceProvider.php
    @@ -0,0 +1,51 @@
    +class ImageServiceProvider implements ServiceProviderInterface {
    

    Why can't we put this in image.services.yml?

    Let's document the reason.

  3. +++ b/core/modules/image/src/Normalizer/ImageItemNormalizer.php
    @@ -0,0 +1,64 @@
    +  public function normalize($object, $format = NULL, array $context = []) {
    +    $data = parent::normalize($object, $format, $context);
    +    if (empty($data['target_id'])) {
    +      return $data;
    +    }
    +    $this->addImageStyles($object, $data);
    +    return $data;
    +  }
    

    This is probably THE most essential part of the patch. What this means is that image items are normalized just like before… but we just also add image style information to the normalization, if the field is not empty.

    But I think the logic can be much simpler:

    if (!$object->isEmpty()) {
      $this->addImageStyles($object, $data);
    }
    

    Bonus points for renaming $object to $field_item and adding a type hint comment.

  4. +++ b/core/modules/image/src/Normalizer/ImageItemNormalizerTrait.php
    @@ -0,0 +1,41 @@
    +    if ($image = $this->entityTypeManager->getStorage('file')->load($item->target_id)) {
    ...
    +      $styles = $this->entityTypeManager->getStorage('image_style')
    +        ->loadMultiple();
    

    Why not File::load() and ImageStyle::loadMultiple()?

    Easier to read, and we would no longer need to have the entity type manager injected.

  5. +++ b/core/modules/image/tests/src/Kernel/Normalizer/ImageItemNormalizerBase.php
    @@ -0,0 +1,168 @@
    +abstract class ImageItemNormalizerBase extends KernelTestBase {
    

    The name currently doesn't make it clear that this is a test class.

    This should be renamed to ImageItemNormalizerTestBase.

  6. +++ b/core/modules/image/tests/src/Kernel/Normalizer/ImageItemNormalizerBase.php
    @@ -0,0 +1,168 @@
    +  protected $image;
    +
    +
    +  /**
    

    Extraneous blank line.

  7. +++ b/core/modules/image/tests/src/Kernel/Normalizer/ImageItemNormalizerBase.php
    @@ -0,0 +1,168 @@
    +    $this->serializer = \Drupal::service('serializer');
    

    $this->serializer = $this->container->get('serializer');

  8. +++ b/core/modules/image/tests/src/Kernel/Normalizer/ImageItemNormalizerBase.php
    @@ -0,0 +1,168 @@
    +    FieldStorageConfig::create(array(
    

    s/array()/[]/

  9. +++ b/core/modules/image/tests/src/Kernel/Normalizer/ImageItemNormalizerBase.php
    @@ -0,0 +1,168 @@
    +    $data = $this->container->get('renderer')
    

    Let's rename $data to either $normalization or $normalized_entity.

  10. +++ b/core/modules/image/tests/src/Kernel/Normalizer/ImageItemNormalizerBase.php
    @@ -0,0 +1,168 @@
    +   * Gets the expected cacheability metadata.
    

    s/expected/expected bubbled/

  11. +++ b/core/modules/image/tests/src/Kernel/Normalizer/ImageItemNormalizerBase.php
    @@ -0,0 +1,168 @@
    +   *   The cacheability metadata.
    

    s/The/The expected bubbled/

martin107’s picture

Assigned: Unassigned » martin107

I've been following along for a while ...all of #43 looks reasonable

it is high time I contributed a little

martin107’s picture

Assigned: martin107 » Unassigned
Status: Needs work » Needs review
FileSize
16.13 KB
11.31 KB

1) Fixed.

2) Fixed by adding a dependencies comment to ImageServiceProvider

3-11) Fixed

In addition I fixed :-

ImageItemHalNormalizer was injected with a deprecated \Drupal\rest\LinkManager\LinkManagerInterface type object.
which feed it onto the parent EntityReferenceItemNormalizer which was actually expecting a \Drupal\serialization\LinkManager\LinkManagerInterface type object.

Status: Needs review » Needs work

The last submitted patch, 45: 2825812-45.patch, failed testing.

Wim Leers’s picture

Thanks!

2) I don't see that comment?

RE: the additional thing: great find! :) That's very recent, but it's great to have it done correctly here! Well-spotted!


Interdiff review:

  1. +++ b/core/modules/image/src/Normalizer/ImageItemHalNormalizer.php
    @@ -41,18 +33,15 @@ class ImageItemHalNormalizer extends EntityReferenceItemNormalizer {
    +   * @param Drupal\serialization\LinkManager\LinkManager $link_manager
    

    Must be typehinted to the interface, not the implementation.

  2. +++ b/core/modules/image/src/Normalizer/ImageItemHalNormalizer.php
    @@ -41,18 +33,15 @@ class ImageItemHalNormalizer extends EntityReferenceItemNormalizer {
    -  public function __construct(LinkManagerInterface $link_manager, EntityResolverInterface $entity_Resolver, EntityTypeManagerInterface $entity_type_manager, RendererInterface $renderer) {
    +  public function __construct(LinkManagerInterface $link_manager, EntityResolverInterface $entity_Resolver, RendererInterface $renderer) {
    

    It's done correctly here :)


Patch review:

  1. +++ b/core/modules/image/src/Normalizer/ImageItemHalNormalizer.php
    @@ -0,0 +1,60 @@
    +/**
    + * ImageItem HAL normalizer to provide URLs to image styles.
    + */
    +class ImageItemHalNormalizer extends EntityReferenceItemNormalizer {
    
    +++ b/core/modules/image/src/Normalizer/ImageItemNormalizer.php
    @@ -0,0 +1,51 @@
    +/**
    + * ImageItem normalizer to provide URLs to image styles.
    + */
    +class ImageItemNormalizer extends EntityReferenceFieldItemNormalizer {
    
    +++ b/core/modules/image/src/Normalizer/ImageItemNormalizerTrait.php
    @@ -0,0 +1,42 @@
    +trait ImageItemNormalizerTrait {
    

    After I posted #43 yesterday, I was thinking a bit more about this.

    These are two new normalizers. But ImageItems were already normalized jsut fine without this patch.

    What this patch is doing, and what these normalizers are doing is not normalizing ImageItems but decorating ImageItem normalizations!

    Think about it: image styles are NOT part of ImageItems in any way: image items are 100% unaware of image styles.

    It's just that we are deciding that it makes sense to provide image style information for every image in an image field.

    So… I'm now thinking that it'd be better to name this ImageItemWithImageStyle(Hal)Normalizer (and ImageItemWithImageStyleNormalizerTrait), which would fully explain what this is doing.

    Or something like that. What do you think? tedbow, what do you think?

  2. +++ b/core/modules/image/src/Normalizer/ImageItemHalNormalizer.php
    @@ -0,0 +1,60 @@
    +      $this->addImageStyles($object, $data['_embedded'][$field_key][0]);
    
    +++ b/core/modules/image/src/Normalizer/ImageItemNormalizer.php
    @@ -0,0 +1,51 @@
    +      $this->addImageStyles($field_item, $data);
    
    +++ b/core/modules/image/src/Normalizer/ImageItemNormalizerTrait.php
    @@ -0,0 +1,42 @@
    +  protected function addImageStyles(ImageItem $item, array &$data) {
    

    The addImageStyles() method would then also need to be renamed to decorateWithImageStyles().

  3. +++ b/core/modules/image/tests/src/Kernel/Normalizer/ImageItemHalNormalizerTest.php
    @@ -0,0 +1,36 @@
    +  public static $modules = ['system', 'entity_test', 'serialization', 'image', 'field', 'user', 'file', 'hal', 'rest'];
    

    The rest module no longer needs to be enabled as of #2758897: Move rest module's "link manager" services to serialization module + #45's insight to not use the deprecated REST link manager, but the Serialization link manager :)

    Also, this does not need to list the system, image etc modules, it inherits that from the base class automatically! This can be reduced to just ['hal'] now :)

  4. +++ b/core/modules/image/tests/src/Kernel/Normalizer/ImageItemNormalizerTestBase.php
    @@ -0,0 +1,167 @@
    +   * The format to use in normalization.
    

    The format whose normalization to test.

Wim Leers’s picture

Issue tags: +blocker

This is now also blocking #2748617: EntityResource only sets entity cache tags on response; cache tags for entity reference fields missing because this adds ConditionalCacheabilityMetadataBubblingTrait, which that issue also needs.

martin107’s picture

Status: Needs work » Needs review
FileSize
16.68 KB
11.04 KB

Interdiff Review:

2) I don't see that comment?

Fixed. [Me stares at the ground mumbling] I hear that happens SOMETIMES when you create a patch before you press save in your editor. #ThatIsMyLineAndIAmStickingToIt.

I have appended the word Interface t the annonation.

Thanks for keeping me honest!

Patch Review

1) 2) Fixed

In the last iteration the critical method was named addImageStyles() [Plural] so I pluralized the name changes

An example of the pattern I went with was

ImageItemWithStylesHalNormalizerTest

3) Fixed.

A Small nit I noticed while work on this

ImageItemNormalizerTrait::addImageStyles()

There was a disconnect between the annotated @parm name "normalization" and the method param name ... I went with $normalization.

On Sunday I will try and workout whatever screw up I introduced that broken testing..

Status: Needs review » Needs work

The last submitted patch, 49: 2825812-49.patch, failed testing.

tedbow’s picture

+++ b/core/modules/image/src/Normalizer/ImageItemWithStylesHalNormalizer.php
@@ -0,0 +1,60 @@
+   * @param Drupal\serialization\LinkManager\LinkManagerInterface $link_manager

Needs a "\"

Re @Wim Leers' comment #47

So… I'm now thinking that it'd be better to name this ImageItemWithImageStyle(Hal)Normalizer (and ImageItemWithImageStyleNormalizerTrait), which would fully explain what this is doing.

The problem with ImageItemWithImageStyle(Hal)Normalizer is that this what we are doing with the normalizer now. But since we can only have 1 normalizer for ImageItem I think we should keep it generic. Because what happens when we find there is something else we need to do in ImageItem normalization(or denormalization) that does have to do with 1 of ImageItem properties? We have to add it to this class and we can't rename it. Probably makes sense to re-name the trait but I think it makes sense for normalizers to be name after the thing that they are normalizing.

martin107’s picture

Status: Needs work » Needs review
FileSize
16.71 KB
1.35 KB

#49

On Sunday I will try and workout whatever screw up I introduced that broken testing..

Fixed.

#51

Needs a "\"

Thanks fixed.

Hmm still thinking up a better name....for ImageItemWithImageStyle(Hal)Normalizer

Status: Needs review » Needs work

The last submitted patch, 52: 2825812-52.patch, failed testing.

Wim Leers’s picture

#51: great point! So perhaps best to stick with ImageItemNormalizer, but make it very explicit in the documentation that this is decorating the default normalization with image style metadata.

Wim Leers’s picture

Just discussed this with @tedbow and the Serialization module maintainer, @damiankloip. He agrees with Ted. The name of the class should always match the $supportedInterfaceOrClass property. So, it should be ImageItemNormalizer, and we can make it clear in the documentation that it's just decorating the default normalization.

garphy’s picture

Quick feedback:
I was hoping that advances made with this patch would also be useful when using json:api.
But unfortunately, as style URLs are added at the field item level, it is merely "invisible" on json:api output which treat entity reference generically.
I think that image styles information (URL, size, ...) would be valuable at the file-entity level when the said entity is an image. As a result we could have this information when querying file entites with rest (entity/file/?_format=json) or when including referenced entities with json:api (api/node//?include=field_image).

martin107’s picture

Status: Needs work » Needs review
FileSize
7.05 KB
16.36 KB

Just limiting the change to a rename.

tedbow’s picture

@garphy re

I think that image styles information (URL, size, ...) would be valuable at the file-entity level when the said entity is an image. As a result we could have this information when querying file entites with rest (entity/file/?_format=json)

The file entity itself doesn't know anything about styles. The only thing that makes image styles available I think is if upload as part of an image field. For a file entity if the file itself is an image file you can't tell if there should be image styles unless you check its usage in a image field. That is you could upload an image in a file field and then the images styles would not be available.

tedbow’s picture

Status: Needs review » Needs work
  1. +++ b/core/modules/image/src/ImageServiceProvider.php
    @@ -0,0 +1,50 @@
    + * Provides additional normalizer services for image field items when the
    + * serialization and hal modules are enabled.
    

    Nit: class description should be 1 line then empty followed longer description if needed.

  2. +++ b/core/modules/image/src/Normalizer/ImageItemNormalizer.php
    @@ -0,0 +1,53 @@
    +   * Constructs an ImageItemWithStylesNormalizer object.
    

    Need to update class name in comment

tedbow’s picture

Status: Needs work » Needs review
FileSize
1.91 KB
16.42 KB

Fixed nits I mentioned in #59 and 1 small other 1. All in comments

Wim Leers’s picture

Status: Needs review » Needs work
  1. +++ b/core/modules/image/src/ImageServiceProvider.php
    @@ -0,0 +1,51 @@
    + * Provides additional normalizer services for image field.
    

    Provides normalizer services for the "image" field type.

  2. +++ b/core/modules/image/src/ImageServiceProvider.php
    @@ -0,0 +1,51 @@
    + * The services are only set if the serialization and hal modules are enabled.
    

    Well this does not explain why we can't put these in image.services.yml.

  3. +++ b/core/modules/image/src/Normalizer/ImageItemHalNormalizer.php
    @@ -0,0 +1,60 @@
    +    $data = parent::normalize($object, $format, $context);
    

    Nit: s/$data/$normalization/

    Also in the other normalizer class.

  4. +++ b/core/modules/image/src/Normalizer/ImageItemHalNormalizer.php
    @@ -0,0 +1,60 @@
    +    if (!empty($data['_embedded'])) {
    

    Why can't we use !$field_item->isEmpty() here, just like we do in ImageItemNormalizer?

  5. +++ b/core/modules/image/src/Normalizer/ImageItemHalNormalizer.php
    @@ -0,0 +1,60 @@
    +      $this->decorateWithImageStyles($object, $data['_embedded'][$field_key][0]);
    

    I started to wonder whether this was actually correct: whether this still worked for multi-valued fields. My manual testing shows it works. And stepping through it with a debugger shows that this indeed makes sense!

  6. +++ b/core/modules/image/src/Normalizer/ImageItemNormalizer.php
    @@ -0,0 +1,53 @@
    +  public function normalize($field_item, $format = NULL, array $context = []) {
    +    $data = parent::normalize($field_item, $format, $context);
    +    if (!$field_item->isEmpty()) {
    

    This is still missing a

    // @var \Drupal\image\Plugin\Field\FieldType\ImageItem $field_item
    

    comment.

Point 2 is my main concern. Once that is fixed, this is RTBC.

tedbow’s picture

Status: Needs work » Needs review
FileSize
5.01 KB
17.14 KB

1. fixed
2. Expanded the comment to list the reasons which are the classes extend class from the hal and serialization modules, they have no use without these modules and the hal one will throw a ServiceNotFoundException because of a missing argument service.

I also nested the check for the hal module under the check for the serialization module. The hal service requires services from the serialization module. So even if serialization wasn't dependent on serialization this service would be.

3. fixed in both classes.
4. It can.fixed.
5. Yep, makes sense the way it is.
6. Added the comment to both classes. and change parameter name in \Drupal\image\Normalizer\ImageItemHalNormalizer::normalize to $field_item to match the other class.

Wim Leers’s picture

Status: Needs review » Reviewed & tested by the community

Hurray :)

Wim Leers’s picture

Status: Reviewed & tested by the community » Needs work
+++ b/core/modules/image/src/Normalizer/ImageItemHalNormalizer.php
@@ -0,0 +1,61 @@
+class ImageItemHalNormalizer extends EntityReferenceItemNormalizer {
...
+   * Constructs an ImageItemHalNormalizer object.

Let's rename this to ImageItemNormalizer. All of the existing normalizers in the HAL module also don't mention Hal in their classnames!

Wim Leers’s picture

Status: Needs work » Reviewed & tested by the community

Ah, damn, #64 does not make sense, because we have ImageItemNormalizer for serialization (i.e. default normalizer) and ImageItemHalNormalizer for hal, and both live in the same directory and namespace. That's why #64 is not feasible.

Wim Leers’s picture

Status: Reviewed & tested by the community » Needs review
  1. +++ b/core/lib/Drupal/Core/Cache/ConditionalCacheabilityMetadataBubblingTrait.php
    @@ -0,0 +1,32 @@
    +trait ConditionalCacheabilityMetadataBubblingTrait {
    
    +++ b/core/modules/image/src/Normalizer/ImageItemNormalizerTrait.php
    @@ -0,0 +1,42 @@
    +        $this->bubble($style);
    

    The way the jsonapi module does this instead:

    $serializer->serialize($data, $format, ['request' => $request, 'cacheable_metadata' => $response->getCacheableMetadata()]);
    

    We could make \Drupal\rest\EventSubscriber\ResourceResponseSubscriber::renderResponseBody() work int he same way.

    Then we wouldn't be bubbling onto "the current global render context" anymore. Which feels a lot less brittle.

  2. +++ b/core/modules/image/tests/src/Kernel/Normalizer/ImageItemNormalizerTestBase.php
    @@ -0,0 +1,171 @@
    +abstract class ImageItemNormalizerTestBase extends KernelTestBase {
    

    And it means this can become a unit test!

Thoughts? @tedbow in particular?

tedbow’s picture

1. that looks a good idea.
I implemented this. I could remove ConditionalCacheabilityMetadataBubblingTrait.

2. I left as a kernel test for now because wanted to see if would still pass. I had remove the url.site cache context from Hal test but think that is because not serializing in render context anymore.

Will update test to unit if this passes without breaking any rest tests.

Wim Leers’s picture

  1. +++ b/core/modules/image/src/Normalizer/ImageItemNormalizerTrait.php
    @@ -34,7 +37,9 @@ protected function decorateWithImageStyles(ImageItem $item, array &$normalizatio
    +          $context['cacheable_metadata']->addCacheableDependency(CacheableMetadata::createFromObject($style));
    

    This can be simply

    $context['cacheable_metadata']->addCacheableDependency($style);
    

    Because ImageStyle implements EntityInterface which implements CacheableDependencyInterface.

  2. +++ b/core/modules/image/tests/src/Kernel/Normalizer/ImageItemNormalizerTestBase.php
    @@ -109,14 +108,11 @@ public function testNormalize() {
    +    $normalization = $this->serializer->normalize($entity, $this->format, ['cacheable_metadata' => $cacheability_metadata]);
    

    s/cacheable_metadata/cacheability/

Wim Leers’s picture

Status: Needs review » Needs work
himanshu-dixit’s picture

Status: Needs work » Needs review
FileSize
16.97 KB
1.91 KB

Fixed #68 in this new patch. I am not sure about the second point, @WimLeers can you see if it is correct ?

Status: Needs review » Needs work

The last submitted patch, 70: 2825812-70.patch, failed testing.

tedbow’s picture

Status: Needs work » Needs review
FileSize
16.92 KB
4.3 KB

@himanshu-dixit thanks for fixing #68.1

I think for #68.2 @Wim Leers was just saying to swap out 'cacheability' for 'cacheable_metadata' in the array we use for the context array.
You should gotten some fails in the test b/c you updated the key but it needs to be the same in ImageItemNormalizerTrait, ImageItemNormalizerTestBase and ResourceResponseSubscriber.

I updated this.

There were a bunch of other fails just because #2854830: Move rest/serialization module's "link manager" services to HAL module landed since #67. So we need use the hal.link_manager service instead of the serialization.link_manager service

I just had to do this for another issue so I updated this too.

Wim Leers’s picture

Status: Needs review » Reviewed & tested by the community

Perfect!

Status: Reviewed & tested by the community » Needs work

The last submitted patch, 72: 2825812-72.patch, failed testing.

denutkarsh’s picture

Status: Needs work » Reviewed & tested by the community

That was a unrelated fail. Returning the RTBC Status

Status: Reviewed & tested by the community » Needs work

The last submitted patch, 72: 2825812-72.patch, failed testing.

Wim Leers’s picture

Status: Needs work » Reviewed & tested by the community

Drupal CI had a bad moment.

Status: Reviewed & tested by the community » Needs work

The last submitted patch, 72: 2825812-72.patch, failed testing.

Wim Leers’s picture

Status: Needs work » Needs review

Retesting. Might be a legitimate fail though. Cache contexts for GET responses have changed, it seems, due to some commit today (EDIT: likely #2853211: EntityResource::post() incorrectly assumes that every entity type has a canonical URL).

Status: Needs review » Needs work

The last submitted patch, 72: 2825812-72.patch, failed testing.

Wim Leers’s picture

Issue tags: +Needs reroll
martin107’s picture

Status: Needs work » Needs review
Issue tags: -Needs reroll

2825812-72.patch applies for me 8.4.x, I am retesting.

BTW I am on commit df2fd66d5999884504ab1d66f921aa6d0bf73711

here is the git log output

Author: Alex Pott
Date: Mon Mar 27 11:39:13 2017 +0100

Issue #2843756

jofitz’s picture

Does not require re-roll - patches applies ok.

Removed unused use statement.

Wim Leers’s picture

Status: Needs review » Needs work

Sorry, by reroll I meant "reroll and need small patch fix", I don't mean "reroll to apply cleanly on latest HEAD".

#83 will fail.

tedbow’s picture

@wim re: #79

I could see that #2853211: EntityResource::post() incorrectly assumes that every entity type has a canonical URL would have changed the cache contexts and \Drupal\entity_test\Entity\EntityTestLabel entity doesn't have a canonical so for that reason the context 'url.site' would not be expected.

But it seems link since \Drupal\hal\LinkManager\LinkManagerBase::getLinkDomain might use $request->getSchemeAndHttpHost() . $request->getBasePath(); then in this case 'url.site' context should be added in that case. Does that sound right?

Wim Leers’s picture

Sigh, you're right, that's simply something that's been forgotten all this time in HAL responses.

EDIT: IMO that's something that's out of scope for this issue though; we need a follow-up for that.

tedbow’s picture

Status: Needs work » Needs review
FileSize
669 bytes
17.53 KB

All right updating \Drupal\Tests\hal\Functional\EntityResource\EntityTestLabel\EntityTestLabelHalJsonAnonTest::getExpectedCacheContexts to not return 'url.site'. Because 'entity_test_label' entity type doesn't provide a canonical link it currently should expect 'url.site' context.

tedbow’s picture

Status: Needs review » Needs work

The last submitted patch, 87: 2825812-87.patch, failed testing.

tedbow’s picture

Status: Needs work » Needs review
FileSize
581 bytes
18.1 KB

... and in the meantime #2843752: EntityResource: Provide comprehensive test coverage for Item entity
got committed.

Same problem except with \Drupal\aggregator\Entity\Item since it doesn't provide a canonical url.

I am assuming both these issues are because we changed \Drupal\rest\EventSubscriber\ResourceResponseSubscriber::renderResponseBody to not use executeInRenderContext().

Wim Leers’s picture

I wanted to RTBC but …

I am assuming both these issues are because we changed \Drupal\rest\EventSubscriber\ResourceResponseSubscriber::renderResponseBody to not use executeInRenderContext().

Well, isn't that a problem then? That's a BC break!

+++ b/core/modules/rest/src/EventSubscriber/ResourceResponseSubscriber.php
@@ -151,14 +151,14 @@ protected function renderResponseBody(Request $request, ResourceResponseInterfac
+      if ($response instanceof CacheableResponseInterface) {
+        if (!$context->isEmpty()) {
+          $response->addCacheableDependency($context->pop());
+        }
+        $serialization_contexts['cacheability'] = $response->getCacheableMetadata();

This is not making any sense. This is popping the render context and adding its cacheability metadata to the response… but we never use the render context anymore in this new code!


I asked for this in #66. It makes normalizers fully unit testable (since you don't need to set up a global render context etc). It makes the code easier to follow, because less magic. @tedbow implemented it in #67.
However, what I didn't notice/realize, is that this suggestion of mine:

Then we wouldn't be bubbling onto "the current global render context" anymore. Which feels a lot less brittle.

… is blatantly false. Doing that implies doing a BC break. Because until now, we explicitly supported this, and for good reason. Let me quote the docs of \Drupal\rest\EventSubscriber\ResourceResponseSubscriber::renderResponseBody():

   * Serialization can invoke rendering (e.g., generating URLs), but the
   * serialization API does not provide a mechanism to collect the
   * bubbleable metadata associated with that (e.g., language and other
   * contexts), so instead, allow those to "leak" and collect them here in
   * a render context.

This change makes that statement untrue! Which means this is a BC break!

So, I think we need to revert that change. I think we can and should still do the explicit cacheability metadata bubbling from normalizers by using $serialization_context['cacheability']. But we should also still continue to support the old mechanism. Not doing that implies a BC break.


So, did that. And turns out @tedbow is right: that allows us to revert the changes in #87 + #90.

Also, this means that the existing documentation is wrong, and needed updating. Changed

   * Serialization can invoke rendering (e.g., generating URLs), but the
   * serialization API does not provide a mechanism to collect the
   * bubbleable metadata associated with that (e.g., language and other
   * contexts), so instead, allow those to "leak" and collect them here in
   * a render context.

to:

   * During serialization, encoders and normalizers are able to explicitly
   * bubble cacheability metadata via the 'cacheability' key-value pair in the
   * received context. This bubbled cacheability metadata will be applied to the
   * the response.
   *
   * In prior versions of Drupal 8, we allowed implicit bubbling of cacheability
   * metadata because there was no explicit cacheability metadata bubbling API.
   * To maintain backwards compatibility, we continue to support this, but
   * support for this will be dropped in Drupal 9.0.0. This is especially useful
   * when interacting with APIs that implicitly invoke rendering (for example:
   * generating URLs): this allows those to "leak", and we collect their bubbled
   * cacheability metadata automatically in a render context.

because now there is an API to explicitly bubble cacheability metadata!

This also means we'll need a change record for this.

Thoughts? Agreed with this direction?

tedbow’s picture

@Wim Leers yes I think you change in #92 is correct to not break BC but also make it easier to add cacheability metadata.

Wim Leers’s picture

I reviewed + RTBC'd @tedbow's ImageItemNormalizer code.

@tedbow can reviewed + RTBC my changes in #91. I first need to add a CR though.

Wim Leers’s picture

tedbow’s picture

Status: Needs review » Reviewed & tested by the community

#91 and the CR look good!

@wim leers thanks for the full explanation in #91.

alexpott’s picture

Status: Reviewed & tested by the community » Needs work
  1. +++ b/core/modules/image/src/Normalizer/ImageItemNormalizerTrait.php
    @@ -0,0 +1,46 @@
    +          'url' => file_url_transform_relative($style->buildUrl($uri)),
    

    I think we need to call \Drupal\image\ImageStyleInterface::supportsUri() to ensure that the style supports the image. And only then add the image style. See #2652138: Image styles do not play nicely with SVGs

  2. +++ b/core/modules/rest/src/EventSubscriber/ResourceResponseSubscriber.php
    @@ -150,14 +158,25 @@ protected function renderResponseBody(Request $request, ResourceResponseInterfac
    +        if (!$context->isEmpty()) {
    +          @trigger_error('Implicit cacheability metadata bubbling (onto the global render context) in normalizers is deprecated since Drupal 8.4.0 and will be removed in Drupal 9.0.0. Use the "cacheability" serialization context instead, for explicit cacheability metadata bubbling.', E_USER_DEPRECATED);
    +          $response->addCacheableDependency($context->pop());
    +        }
    

    Nicely done.

Wim Leers’s picture

#96.1: that's a new API added in #2652138: Image styles do not play nicely with SVGs, so we couldn't have possibly done that until now!

But yay, that seems like an easy reroll :)

tedbow’s picture

Status: Needs work » Needs review
FileSize
1.71 KB
19.15 KB

re #96.1 added call to \Drupal\image\ImageStyleInterface::supportsUri()

Wim Leers’s picture

Status: Needs review » Reviewed & tested by the community
alexpott’s picture

Status: Reviewed & tested by the community » Needs work
Issue tags: +Needs work

... not going to be popular... but I think we need tests for the if ($style->supportsUri($uri)) {

We should have a .svg uri in the test I guess

tedbow’s picture

Status: Needs work » Needs review
FileSize
5.75 KB
20.16 KB

... not going to be popular... but I think we need tests for the if ($style->supportsUri($uri)) {

I guess i won't vote you down on mostpopulardrupalcorecommitter.com today ;)

No problem good thing to test for!!!!

Added a dataprovider that uses existing jpg test case and svg test case.

Wim Leers’s picture

Status: Needs review » Needs work
Issue tags: -Needs work

#100 hahahahah, I was struggling with that — was contemplating asking for it. I wasn't sure. It's definitely better to have it.

  1. +++ b/core/modules/image/tests/src/Kernel/Normalizer/ImageItemNormalizerTestBase.php
    @@ -97,11 +99,18 @@ protected function setUp() {
    +      'uri' => $uri,
    

    Nit: could use setFileUri().

  2. +++ b/core/modules/image/tests/src/Kernel/Normalizer/ImageItemNormalizerTestBase.php
    @@ -150,18 +165,41 @@ public function testNormalize() {
    +   * @param bool $styles_included
    

    I think $styles_included is a bit strange, but ok. Can't think of anything better atm.

  3. +++ b/core/modules/image/tests/src/Kernel/Normalizer/ImageItemNormalizerTestBase.php
    @@ -150,18 +165,41 @@ public function testNormalize() {
    +   * Datatprovider for testNormalize().
    

    Nit: s/Datatprovider/Data provider/

tedbow’s picture

I think this method might be overly complicated
See: #2871591: Allow ComplexData in TypedData to specify computed properties that should be exposed in normalization and other contexts

If that seems like good idea we should probably postpone this.

Wim Leers’s picture

Title: ImageItem normalizer should expose all public image style URLs » [PP-1] ImageItem normalizer should expose all public image style URLs
Status: Needs work » Postponed
Related issues: +#2871591: Allow ComplexData in TypedData to specify computed properties that should be exposed in normalization and other contexts

This has effectively been postponed on that issue for >2 months now.

Version: 8.4.x-dev » 8.5.x-dev

Drupal 8.4.0-alpha1 will be released the week of July 31, 2017, which means new developments and disruptive changes should now be targeted against the 8.5.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

Wim Leers’s picture

#2871591: Allow ComplexData in TypedData to specify computed properties that should be exposed in normalization and other contexts is in, #2910211: Allow computed exposed properties in ComplexData to support cacheability. is the last remaining blocker (was split off from #2871591 to make its scope narrower and help it land sooner), and that too is now RTBC!

Wim Leers’s picture

Title: [PP-1] ImageItem normalizer should expose all public image style URLs » ImageItem normalizer should expose all public image style URLs
Status: Postponed » Needs review
Issue tags: +Needs tests
FileSize
80.94 KB
97.55 KB
6.15 KB

#2910211: Allow computed exposed properties in ComplexData to support cacheability. also landed, this is now fully unblocked!

I've rerolled #101 entirely in the spirit of #2871591: Allow ComplexData in TypedData to specify computed properties that should be exposed in normalization and other contexts. I got some inspiration on how to add a computed property that contains a list of things from \Drupal\entity_test\Plugin\Field\ComputedTestFieldItemList.

Rolling this patch took me more than 6 hours of work, because Typed Data is excruciatingly difficult to figure out. Hopefully once there's a bunch of examples, it'll become much simpler for others to do.


The result in the REST module:

And together with #2921257-6: On Drupal 8.5, JSON API should respect Typed Data's new ::isInternal(), and JSON API Extras should use ::setInternal() (to leverage #2871591: Allow ComplexData in TypedData to specify computed properties that should be exposed in normalization and other contexts), it even works automatically in the contrib JSON API module:

Wim Leers’s picture

Title: ImageItem normalizer should expose all public image style URLs » ImageItem should have an "image_styles" computed property, to expose all image style URLs
Issue tags: +Needs issue summary update

Status: Needs review » Needs work

The last submitted patch, 107: 2825812-107.patch, failed testing. View results

Wim Leers’s picture

Status: Needs work » Needs review
FileSize
2.55 KB
8.63 KB

Hah, the Media entity has this base field:

$fields['thumbnail'] = BaseFieldDefinition::create('image')

Which means this patch is automatically adding image styles for the thumbnail. Proving that it works beautifully everywhere where image fields are used!

Interesting fact: only the ?_format=json tests are failing, the ?_format=hal_json tests are passing, because the "image_styles" computed property simply does not show up for hal_json. This is because ImageItem extends FileItem extends EntityReferenceItem, and the HAL normalizers treat entity reference fields in a special way (and therefore also image fields).
I'd say we have to fix that first, but … the HAL normalization intentionally chose to do this. In fact, for this same reason, the hal_json-formatted response also doesn't allow you to get the alt, width or height properties of image fields. image_styles is merely another in that list.

Wim Leers’s picture

+++ b/core/modules/image/src/Plugin/DataType/ComputedImageStyleList.php
@@ -0,0 +1,92 @@
+class ComputedImageStyleList extends ItemList {

I think this should actually extend Map, not ItemList.

Status: Needs review » Needs work

The last submitted patch, 110: 2825812-110.patch, failed testing. View results

Wim Leers’s picture

I think that @e0ipso is implying at #2921257-15: On Drupal 8.5, JSON API should respect Typed Data's new ::isInternal(), and JSON API Extras should use ::setInternal() that image_styles is a bad name for this computed property, because it's very Drupal-y. derivatives would be a better name. That also happens to be the name that is used in the codebase. "Image Styles" is kind of the human-readable name for the same concept.

So, how do people feel about that? I personally think that probably makes more sense.

Wim Leers’s picture

Status: Needs work » Needs review
FileSize
5.51 KB
11.79 KB

#110 was failing because for some reason, the width and height are strings for the large and medium image styles, but integers for the thumbnail styles.

We can easily fix that: casting them all to integers.

But then the

    // BC: serialization_update_8302().
    // Only run this for fieldable entities. It doesn't make sense for config
    // entities as config values are already casted. They also run through the
    // ConfigEntityNormalizer, which doesn't deal with fields individually.
    if ($this->entity instanceof FieldableEntityInterface) {
      // Test primitive data casting BC (strings).
      $this->config('serialization.settings')->set('bc_primitives_as_strings', TRUE)->save(TRUE);

test coverage fails. Because \Drupal\image\Plugin\DataType\ComputedImageStyleList::computeImageStyleMetadata() returns [string, int, int], not [StringData, IntegerData, IntegerData]. Fixing that is for a next comment. For similar reasons, the XML test coverage is going to fail.


So in this patch, I commented out the "primitives as strings" BC layer test coverage. I also disabled the XML "GET" test coverage. Just to prove the general approach.

This patch should be green, and hopefully this patch will finally start getting the reviews it needs to be able to move forward.

Berdir’s picture

Hm, \Drupal\image\Entity\ImageStyle/image_style config entity is as codebase as it gets and that definitely uses image styles, not derivates. Almost all code references to derivatives in image.module are related to the allow_insecure_derivatives setting, no idea why that doesn't use derivatives.

I'd say using a non-drupal term could in turn be confusing for anyone who actually knows Drupal :)

Also a bit worried about adding more computed properties. They aren't free and unlike non-computed properties are automatically created (not actually computed/accessed, but created) in the constructor of the FieldItemBase. There is an issue to try and optimize that but I couldn't make it work yet.

Wim Leers’s picture

Title: ImageItem should have an "image_styles" computed property, to expose all image style URLs » ImageItem should have an "derivatives" computed property, to expose all image style URLs
FileSize
2.65 KB
11.79 KB

And this then implements #113.

tedbow’s picture

re #115 @Berdir would know but better than what the performance it would be computed fields but as a counterpoint....

The reason we did #2871591: Allow ComplexData in TypedData to specify computed properties that should be exposed in normalization and other contexts was because if we expose extra metadata in through normalizers which this issue originally was going to do then from that issue summary:

You can see how this gets complicated very quickly:

  1. new normalizers, multiplied by all different normalizations in core (and that doesn't include the contrib normalizations yet, such as https://www.drupal.org/project/jsonapi)
  2. API-exposing modules not relying on normalizers, such as https://www.drupal.org/project/graphql, would have to again duplicate all this logic
  3. finally, automatically generating documentation that describes the structure of the generated responses also becomes impossible to automate, because they'd have to hardcode the special cases of every normalizer … which we could do in theory for Drupal core's normalizers, but impossible to know all the contrib/custom normalizers!

I think we determined 3) was big reason that applies here we can't dynamically document our REST API(or JSON API in contrib) if this type of information is added in normalizers.

Status: Needs review » Needs work

The last submitted patch, 116: 2825812-115.patch, failed testing. View results
- codesniffer_fixes.patch Interdiff of automated coding standards fixes only.

Wim Leers’s picture

Status: Needs work » Needs review
FileSize
1.12 KB
11.79 KB

Ugh, the #116 interdiff was correct, but the patch was not. It was missing one hunk of the interdiff.

Wim Leers’s picture

FileSize
862 bytes

Damn, #119's interdiff is wrong. Attached is the interdiff between #116 and #119. Sorry for the confusion!

e0ipso’s picture

I'd say using a non-drupal term could in turn be confusing for anyone who actually knows Drupal :)

I agree with this. However this term is going to be exposed through APIs to non-drupalers (iOS, Roku, React, …). In fact, they will be the main customers of this property. That's why I feel like @Wim Leers accurately describes in:

image_styles is a bad name for this computed property, because it's very Drupal-y. derivatives would be a better name.

That being said, I don't feel strongly about this. I just have a preference.

damiankloip’s picture

This is still looking good overall.

  1. +++ b/core/modules/image/src/Plugin/DataType/ImageStyle.php
    @@ -0,0 +1,54 @@
    + *   id = "image_styles",
    

    Should this just be "image_style"? I know it's mainly being used as a list implementation but this plural naming seems weird in this context.

  2. +++ b/core/modules/image/src/Plugin/DataType/ImageStyle.php
    @@ -0,0 +1,54 @@
    + *   label = @Translation("Image style URL"),
    

    This label should indicate we get more than just a URL maybe.

  3. +++ b/core/modules/rest/tests/src/Functional/EntityResource/EntityResourceTestBase.php
    @@ -555,7 +555,8 @@ public function testGet() {
    +// @todo fix \Drupal\image\Plugin\DataType\ComputedImageStyleList::computeImageStyleMetadata(), see comment 114
    +//      $this->assertSame($expected, $actual);
    

    Is this because EntityResourceTestBase::castToString() needs more smarts? I guess the expected response we assert against thinks all the properties should be strings as it works recursively?

    I wonder if it would help if we could use a MapDataDefinition type implementation instead, so we have actual typed data properties for the properties here. This would then fix the normalization case I think? As sites opting in to the BC behaviour would get all strings I think. Oh... hmm. That would mean we'd have to set the initial values as strings, and rely on casting in the primitive data normalizer...

  4. +++ b/core/modules/serialization/src/Normalizer/ListNormalizer.php
    @@ -25,8 +25,8 @@ class ListNormalizer extends NormalizerBase {
    +    foreach ($object as $key => $value) {
    +      $attributes[$key] = $this->serializer->normalize($value, $format, $context);
    

    Should we modify the ListNormalizerTest slightly to reflect this?

Wim Leers’s picture

So:

  1. @Berdir in #115 preferring "image styles"
  2. @e0ipso in #121 preferring "derivatives"

I see both points of view. But I think that any Drupalist will recognize image style URLs even if they're under the "derivatives" key. And "derivatives" makes more sense to the broader world. So I do tend to lean towards @e0ipso's preference/recommendation here.

Wim Leers’s picture

FileSize
2.16 KB
11.89 KB
  1. 👍 Yeah, is a remnant. Fixed. Also renamed the class to ComputedImageStyle.
  2. 👍 Another remnant.
  3. No, as the code comment says: see #114 for the explanation. The current code for ComputedImageStyle::getValue() is hacky. It shouldn't return PHP primitives, it should return TypedDataInterface objects implementing PrimitiveInteface.
    I literally can't figure out how to implement that, because I can't just do new IntegerData(…), because a data definition must be passed.

    This patch needs review from a Typed Data expert I think.

  4. Probably, but I'd first like sign-off on the way this uses Typed Data (and fix it, per the previous point).
Berdir’s picture

+++ b/core/modules/image/src/Plugin/DataType/ComputedImageStyleList.php
@@ -0,0 +1,92 @@
+    foreach (ImageStyle::loadMultiple() as $style) {
+      $this->list[$style->getName()] = $this->createItem($style->getName(), $this->computeImageStyleMetadata($file, $width, $height, $style));
+    }

One thing to consider is that sites tend have a lot of image styles. Especially when using responsive image styles (see below).

I just looked at one example of a site that I know has a lot of image styles and I'm seeing a *pager* on the image style site, in total 61 image styles.

Unconditionally showing all of them really isn't an option IMHO.

If this would be done in context of REST/serializer, then I could imagine it being controlled by a query argument like ?include_image_styles=medium,thumbnail. But having this on the entity field level makes that more complicated.

The second thing to consider are responsive image styles, but I suppose logic for that will be implemented client-side?

e0ipso’s picture

I just looked at one example of a site that I know has a lot of image styles and I'm seeing a *pager* on the image style site, in total 61 image styles.

Unconditionally showing all of them really isn't an option IMHO.

I strongly +1 this. I tried to explain my reasons in this article. The main objective of https://www.drupal.org/project/consumer_image_styles is to mitigate this problem.

Wim Leers’s picture

This patch needs review from a Typed Data expert I think.

I think this needs something like the attached patch.

Wim Leers’s picture

In any case, this can be updated to use ComputedItemListTrait, introduced in #2392845: Add a trait to standardize handling of computed item lists, right? Well, it doesn't work, for some reason $this->valueComputed starts of as TRUE! I suspect PathItemList::$valueComputed's value is somehow being transfered to ComputedImageStyleList… :O

Wim Leers’s picture

#125 + #126 I've already had this discussion with @e0ipso in #2921257-14: On Drupal 8.5, JSON API should respect Typed Data's new ::isInternal(), and JSON API Extras should use ::setInternal() through #2921257-17: On Drupal 8.5, JSON API should respect Typed Data's new ::isInternal(), and JSON API Extras should use ::setInternal(). Please read my arguments there too.

If this would be done in context of REST/serializer, then I could imagine it being controlled by a query argument like ?include_image_styles=medium,thumbnail. But having this on the entity field level makes that more complicated.

#2825814: [PP-1] Allow URL query argument to limit the image style URLs returned by ImageItemNormalizer exists for that (added in #2!). The default would still have to include all image styles. Because A) having dozens of image styles is not the norm, B) it ensures good discoverability.

e0ipso’s picture

Not to dwell on this, but it do think that dozens of image styles is indeed the norm. At least for the sites I am usually involved.

Wim Leers’s picture

If we're not going to expose this by default, then I don't see the point of doing this. If it's there, but so hidden that nobody will discover it (i.e. it's required to read docs first), then we might as well not do it.

Wim Leers’s picture

To be clear: #131 is not a knee-jerk reaction. I'm not mad or annoyed. I just am trying to ensure that we are working on higher impact issues first. And if this is not exposed by default, I don't believe this is high-impact anymore.

dawehner’s picture

Because A) having dozens of image styles is not the norm

Haha, websites are more complex than you imagine. Still, the strategy has been with Drupal core to always expose everything.
One example is to expose formatted text by default. The additional size of the response of adding formatted text easily outweights MANY image styles.

For me at least on the longrun jsonapi / the consumer module provides a better solution, but for the purpose of core itself exposing everything provides a reasonable solution.

Berdir’s picture

Good to know about that issue, but that kind of underlines my point :)

We define a computed property that automatically exposes and generates* all image style URL's and then the follow-up will have to implement a custom serializer to then limit those options again, because we definitely can not somehow pass URL query arguments to a computed property (which has no concept of passing arguments).

So.. why not make it a serializer in the first place that only generates the actually requested** image styles?

It's great that we have a new hammer (ability to expose computed properties) but not every missing information in REST is a nail :)

* note that doing this is not cheap in some cases, for example, when hosting images on S3, the current implementation has to fetch the file, convert it, and then send the generated image back up to S3 *when* the url is built, because it can not create them on-deman.

** Yeah, also not convinced that we should send all by default, I'd also say that any non-trivial site quickly has a dozen or more image styles, you just need 3 responsive image styles to get to 9, then a few thumbnails and so on and you're at a dozen.

Version: 8.5.x-dev » 8.6.x-dev

Drupal 8.5.0-alpha1 will be released the week of January 17, 2018, which means new developments and disruptive changes should now be targeted against the 8.6.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

justafish’s picture

Status: Needs review » Needs work
FileSize
13.59 KB
3.28 KB

This patch is exactly what I needed for my current project 👍Attached patch is from #124 and makes outputting each derivative optional.

justafish’s picture

Also needed the ability to filter by entity/bundle

justafish’s picture

Assigned: Unassigned » justafish
justafish’s picture

A bit more progress, though MediaJsonAnonTest is still failing

alexpott’s picture

Status: Needs work » Needs review
FileSize
5.48 KB
14.58 KB

The patch attached makes the ComputedImageStyle a Map so its properties are typed which then allows the normalizers to do their magic. This exposes an interesting feature that this kinda expects all values to come in as strings because that's how the db would handle them and then types them using the TypedData primitive.

Left a few @todo's in the code for things I thought whilst trying to make the core/modules/media/tests/src/Functional/Rest/MediaJsonAnonTest.php test green.

alexpott’s picture

Fixing some of the config schema related fails and protecting the new properties on the ImageStyle entity.

The last submitted patch, 140: 2825812-140.patch, failed testing. View results

Status: Needs review » Needs work

The last submitted patch, 141: 2825812-141.patch, failed testing. View results

alexpott’s picture

Status: Needs work » Needs review
FileSize
13.19 KB
12.87 KB

There's a way we can do this with less change. We can use the image style config entity's third party settings and store stuff there when the serialization module is enabled.

There are some things we need to decide:

  • when the serialization module is installed do we need to update all the existing configuration entities to have the default values
  • do we need to provide a UI for this
  • what are the defaults - atm all image styles will be included
justafish’s picture

Nice 👍

> when the serialization module is installed do we need to update all the existing configuration entities to have the default values
If we include all by default, then no (if include_in_normalized_entity is missing instead of explicitly false, we assume we include it)

> do we need to provide a UI for this
Maybe some checkboxes on the image style configuration if serialisation is enabled? Might be better to discuss in a follow up though

> what are the defaults - atm all image styles will be included
+1 including all by default

alexpott’s picture

I think it is okay to punt the UI and whether or not to add the defaults to image styles when serialization is enabled to a follow-up. We have the functionality for advanced use-cases and with the current approach the derivative info will be there for all image item / image style combos which is good.

Patch attached tries to use the ComputedItemListTrait which I definitely think we should use. I had a problem with the setValue() and the null situation. Plus we had to override the get because of the use of string keys here. I'm not sure how much the usage of string keys in a list item is going to continue to make troubles. I'm going to ping @amateescu since their knowledge of computed fields is second to none.

amateescu’s picture

Here's an initial review:

  1. +++ b/core/modules/image/src/Plugin/DataType/ComputedImageStyleList.php
    @@ -0,0 +1,125 @@
    +class ComputedImageStyleList extends ItemList {
    +  use ComputedItemListTrait;
    

    Needs an empty line for better readability.

  2. +++ b/core/modules/image/src/Plugin/DataType/ComputedImageStyleList.php
    @@ -0,0 +1,125 @@
    +          $entity = $image_item->getParent()->getParent()->getValue();
    

    We should try to get the entity outside the foreach, and return early if we couldn't find it. This way we'll also remove the need for the try/catch block.

    And we should use $image_item->getEntity() instead of manually going through the parents :)

  3. +++ b/core/modules/image/src/Plugin/DataType/ComputedImageStyleList.php
    @@ -0,0 +1,125 @@
    +      catch (Exception $e) {
    

    Missing a leading slash. Probably moot based on the point above.

  4. +++ b/core/modules/image/src/Plugin/DataType/ComputedImageStyleList.php
    @@ -0,0 +1,125 @@
    +        $this->list[$style->getName()] = $this->createItem($style->getName(), $this->computeImageStyleMetadata($file, $width, $height, $style));
    

    We can't use string values as keys for $this->list, since that property should only contain a numerically indexed array, see \Drupal\Core\TypedData\Plugin\DataType\ItemList::$list. Every part of the system works based on this definition of the list property, so I've no idea what other things might could break because of this..

    If we need the image style machine name, I would suggest to include it one level below, alongside url, width and height.

  5. +++ b/core/modules/image/src/Plugin/DataType/ComputedImageStyleList.php
    @@ -0,0 +1,125 @@
    +      'width' => (string) $dimensions['width'],
    +      'height' => (string) $dimensions['height'],
    
    +++ b/core/modules/rest/tests/src/Functional/EntityResource/XmlEntityNormalizationQuirksTrait.php
    @@ -95,6 +95,15 @@ protected function applyXmlFieldDecodingQuirks(array $normalization) {
    +                  $derivatives[$image_style]['width'] = (string) $derivatives[$image_style]['width'];
    +                  $derivatives[$image_style]['height'] = (string) $derivatives[$image_style]['height'];
    

    Shouldn't we use \Drupal\Core\TypedData\PrimitiveInterface::getCastedValue() instead?

  6. +++ b/core/modules/image/src/Plugin/DataType/ComputedImageStyleList.php
    @@ -0,0 +1,125 @@
    +  public function get($index) {
    +    // Unlike the base implementation of
    +    // \Drupal\Core\TypedData\ListInterface::get(), we do not add an empty item
    +    // automatically because computed item lists need to behave like
    +    // non-computed ones. For example, calling isEmpty() on a computed item list
    +    // should return TRUE when the values were computed and the item list is
    +    // truly empty.
    +    // @see \Drupal\Core\TypedData\Plugin\DataType\ItemList::get().
    +    $this->ensureComputedValue();
    +    return isset($this->list[$index]) ? $this->list[$index] : NULL;
    +  }
    

    This seems to contain exactly the same logic as code>\Drupal\Core\TypedData\ComputedItemListTrait::get, so it shouldn't be needed.

  7. +++ b/core/modules/serialization/src/Normalizer/ListNormalizer.php
    @@ -25,8 +25,8 @@ class ListNormalizer extends NormalizerBase {
    -    foreach ($object as $fieldItem) {
    -      $attributes[] = $this->serializer->normalize($fieldItem, $format, $context);
    +    foreach ($object as $key => $value) {
    +      $attributes[$key] = $this->serializer->normalize($value, $format, $context);
    

    When the point above on $this->list being numerically indexed is fixed, this change should not be needed anymore.

alexpott’s picture

@amateescu the problem with not using sting keys is that makes it way harder for someone to get the thumbnail or large image style of an image. If the image style machine names are keys this is simple.

amateescu’s picture

@alexpott, yes, I understood the reason why it's written like that, but if the goal is to use string keys for the derivatives property of the image field type, it can not use the default typed data item list (\Drupal\Core\TypedData\Plugin\DataType\ItemList) and it would need a custom version of it with different implementations for rekey(), first(), appendItem() and who knows how many other methods. Those are just the ones I found on a quick visual scan of that class..

Wim Leers’s picture

OMG I did not realize this had gotten so much attention/activity in the past week! (Nor Sally's first comment in #136.) Sorry, I've been deep down in JSON API land. I'll comment on this ASAP.

justafish’s picture

Thank you for the thorough review @amateescu! 👍

Big +1 on #148 - not having string keys massively reduces the usability of this

Wim Leers’s picture

This patch is exactly what I needed for my current project 👍

❤️

  • #136: I see where you're going with this. Not sure yet what to think.
  • #137: I definitely am concerned about this. It makes an image style depend on every possible entity type and bundle that uses the image style. This configuration would be better stored on the entity bundle, not on the image style.
  • #140: YES YES YES! I struggled so very much to get this to work (I dug deep in Typed Data for hours), so I'm very glad to see new attempts to get this to work! This looks very promising :)
    See #124.3 and #114 for my previous observations and attempts. I also had to fight the string handling.
  • #144: Using third party settings is already better, but the same concern continues to exist.
  • #146++
  • #147.4: I was gonna point out that this is not a FieldItemList, but even \Drupal\Core\TypedData\ListInterface::set() says this is not allowed :(
  • #147.6: it indeed is mostly the same logic, but it removes the need for keys to be numerical.
  • #149: you're right.
  • #151: indeed, couldn't agree more.
+++ b/core/modules/image/src/Plugin/DataType/ComputedImageStyle.php
@@ -0,0 +1,39 @@
+ *   list_class = "\Drupal\image\Plugin\DataType\ComputedImageStyleList",

+++ b/core/modules/image/src/Plugin/DataType/ComputedImageStyleList.php
@@ -0,0 +1,125 @@
+class ComputedImageStyleList extends ItemList {

+++ b/core/modules/image/src/Plugin/Field/FieldType/ImageItem.php
@@ -161,6 +162,12 @@ public static function propertyDefinitions(FieldStorageDefinitionInterface $fiel
+    $properties['derivatives'] = ListDataDefinition::create('image_style')

So I think all of this needs to change? It sounds like rather than a list (numerical keys), this should become a map (string keys)?

alexpott’s picture

In an conversation today @justafish suggested that maybe we could use a normalizer to add this information to an ImageItem instead of using TypedData and a computed field. What do people think?

amateescu’s picture

Since the main (only?) use-case for this feature seems to be REST API calls, I'd say that it makes sense for this code to live in a normalizer.

Berdir’s picture

Yes, that's also what I wondered in #115. I believe that goes against Wim's plan (#2926507: Discourage @FieldType-level normalizers, encourage @DataType-level normalizers, to strengthen the API-First ecosystem), but as i pointed out here and there, I'm not happy about putting everything into typed data, for performance and complexity reasons (things like string vs integer keys that is complex with typed data is a non-issue with a normalizer that can return arbitrary read-only data.

It also means that we might need to duplicate it into multiple normalizers because they return different structures, but that does not seem like a reason against doing that IMHO but more likely indicates that the architecture we have for the whole normalizer stuff isn't really such a great fit.

alexpott’s picture

Here's a version of the patch still using typed data but computing the map and not using the item list stuff.

Regarding the normalizer discussion - if we're going to go that way how can we ensure that we don't get into priority problems?

Wim Leers’s picture

In an conversation today @justafish suggested that maybe we could use a normalizer to add this information to an ImageItem instead of using TypedData and a computed field. What do people think?

Extremely strong -1.

See #2926507: Discourage @FieldType-level normalizers, encourage @DataType-level normalizers, to strengthen the API-First ecosystem.

We should NOT add more @FieldType-specific normalizers that only work for particular formats. Because that then won't work for JSON API or GraphQL. It means we'll have to implement the same logic three times.

I'm not happy about putting everything into typed data, for performance and complexity reasons

Can you explain this? I don't remember you bringing this up before?


#156 looks great!

Wim Leers’s picture

+++ b/core/modules/image/src/Plugin/DataType/ComputedImageStyleDerivatives.php
@@ -0,0 +1,171 @@
+      $include_image_style = $style->getThirdPartySetting('serialization', 'include_in_normalized_entity', TRUE);
+
+      try {
+        $granularity = $style->getThirdPartySetting('serialization', 'normalized_entity_granularity', []);
+        if (!empty($granularity)) {
+          /** @var \Drupal\Core\entity $entity */
+          $entity = $image_item->getParent()->getParent()->getValue();
+          if ($entity) {
+            $entity_type = $entity->getEntityTypeId();
+            $bundle = $entity->bundle;
+            if (empty($entity_type) || empty($bundle) || !in_array($entity_type, array_keys($granularity)) || !in_array($bundle, $granularity[$entity_type])) {
+              $include_image_style = FALSE;
+            }
+          }
+        }
+      }
+      catch (Exception $e) {
+        // No parent entity was found, this is fine.
+      }
+
+      if ($include_image_style) {

+++ b/core/modules/media/tests/src/Functional/Rest/MediaResourceTestBase.php
@@ -112,6 +113,11 @@ protected function createEntity() {
+    // Test excluding an image style based on entity type and bundle.
+    ImageStyle::load('large')
+      ->setThirdPartySetting('serialization', 'normalized_entity_granularity', ['media' => ['camelids']])
+      ->save();

+++ b/core/modules/serialization/config/schema/serialization.schema.yml
@@ -8,3 +8,19 @@ serialization.settings:
+image.style.*.third_party.serialization:
+  type: mapping
+  label: 'Image style serialization settings'
+  mapping:
+    include_in_normalized_entity:
+      type: boolean
+      label: 'Include in Normalized Entity'
+    normalized_entity_granularity:
+      type: sequence
+      label: 'Include only in specific Entities and Bundles'
+      sequence:
+        type: sequence
+        sequence:
+          type: string
+          label: 'Bundle'

If we can agree to postpone configurability/tweakability to a follow-up, then this is RTBC as far as I'm concerned. Then it could ship with Drupal 8.6!

Wim Leers’s picture

Issue tags: -Needs tests

This already has test coverage, so removing Needs tests.

Berdir’s picture

I know you are against that :)

Performance: Yes, I did, in #115 for example:

Also a bit worried about adding more computed properties. They aren't free and unlike non-computed properties are automatically created (not actually computed/accessed, but created) in the constructor of the FieldItemBase. There is an issue to try and optimize that but I couldn't make it work yet.

Also a bit in #125, simply because building a list of 20 or so image styles in typed data structure is far more expensive than just building a plain array structure.

alexpott’s picture

Re #158 well maybe we could start with only the include_in_normalized_entity setting since that does not have the complexity of specific bundle / entity type selecting and dependencies and goes a little bit of the way to addressing @Berdir's performance concerns if you have a gazillion images styles.

Wim Leers’s picture

#160: sorry, I did not find #115 when searching the other day. How much of a performance problem is this? It doesn't seem like it has a massive performance impact, plus doesn't entity cache largely mitigate this?

#161: I think that Berdir is saying that doing this using computed properties at all impacts performance; I think he doesn't necessarily care about how many things there are to compute. (Because he's saying he's concerned about create cost, not a compute on access cost, because they're not actually computed until accessed.)

Version: 8.6.x-dev » 8.7.x-dev

Drupal 8.6.0-alpha1 will be released the week of July 16, 2018, which means new developments and disruptive changes should now be targeted against the 8.7.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

ndobromirov’s picture

Status: Needs review » Reviewed & tested by the community

#123 - we should be able to accommodate both options. In the end it's just a property name. We should be able to put that in config, have the it defaulting to something and have a non-UI configuration to allow settings.php level overwrite, so people can tune it.

#160 - if you have that many stiles it's a design problem. Core can ship with this and have a follow-up to optimize. As it is it's unusable, so something slow that works is genuinely better than something fast that never comes. On top of that, there is page cache that will speed things up in the 90+% case.

Both of my points can be implemented in follow-up issues, so I will dare to put RTBC this (#156), because it:
- Has tests.
- Solves a real issue in using Drupal 8 in any decoupled scenario that has images in it.
- Works!!!

The last submitted patch, 139: 2825812-139.patch, failed testing. View results
- codesniffer_fixes.patch Interdiff of automated coding standards fixes only.

The last submitted patch, 136: 2825812-135.patch, failed testing. View results
- codesniffer_fixes.patch Interdiff of automated coding standards fixes only.

Wim Leers’s picture

Status: Reviewed & tested by the community » Needs review
Related issues: +#2992822: Image styles

@ndobromirov came here because I pointed him here from #2992822: Image styles, which I now marked as a duplicate.

#164:
RE #123: WFM!
RE #160: I agree :)

However, I think we should remove the configurability, like I said in #158. What do you think?

ndobromirov’s picture

There is no UI for changing that configuration, so using it is going to be tricky.
I think that we should ship with some way to disable items in the list, so contrib can make UIs and stuff.

As I see it patch is good to go because:
- If I have to pick one it should be derivatives as it currently is..
- Only on install everything is enabled.
- You can disable whatever is not needed at later stage, so that will reduce the performance issue that @Berdir was mentioning.
- I am OK with both options with or without the config.

To make things simpler - drop it out and have a follow-up.

BR0kEN’s picture

Status: Needs review » Needs work
+++ b/core/modules/image/src/Plugin/DataType/ComputedImageStyleDerivatives.php
@@ -0,0 +1,171 @@
+      catch (Exception $e) {

The Exception here cannot be caught since current namespace hasn't such class. Looks like a typo and should be \Exception.

  1. +++ b/core/modules/image/src/Plugin/DataType/ComputedImageStyleDerivatives.php
    @@ -0,0 +1,171 @@
    + * @ingroup typed_data
    

    PHPCS: Missing an empty line after description.

  2. +++ b/core/modules/image/src/Plugin/DataType/ComputedImageStyleDerivatives.php
    @@ -0,0 +1,171 @@
    +    $file = $image_item->entity;
    +    $width = $image_item->width;
    +    $height = $image_item->height;
    

    We don't need these variables unless $include_image_style is TRUE.

  3. +++ b/core/modules/image/src/Plugin/DataType/ComputedImageStyleDerivatives.php
    @@ -0,0 +1,171 @@
    +          /** @var \Drupal\Core\entity $entity */
    

    Non-existing class. Should be /** @var \Drupal\Core\Entity\EntityInterface $entity */

  4. +++ b/core/modules/image/src/Plugin/DataType/ComputedImageStyleDerivatives.php
    @@ -0,0 +1,171 @@
    +          $entity = $image_item->getParent()->getParent()->getValue();
    

    The result of $image_item->getParent()->getParent()->getValue() should never change and it looks like a good candidate to move out of the loop.

    It's also good to have commented what ->getParent()->getParent() means.

  5. +++ b/core/modules/image/src/Plugin/DataType/ComputedImageStyleDerivatives.php
    @@ -0,0 +1,171 @@
    +            $bundle = $entity->bundle;
    

    Should be a method call - $bundle = $entity->bundle();

  6. +++ b/core/modules/image/src/Plugin/DataType/ComputedImageStyleDerivatives.php
    @@ -0,0 +1,171 @@
    +            if (empty($entity_type) || empty($bundle) || !in_array($entity_type, array_keys($granularity)) || !in_array($bundle, $granularity[$entity_type])) {
    

    Looks like this line can be simply replaced by the if (empty($granularity[$entity_type]) || empty($granularity[$entity_type][$bundle])) {.

BR0kEN’s picture

Assigned: justafish » Unassigned
Status: Needs work » Needs review
FileSize
13.59 KB
11.36 KB

This variant reduces methods calls and allows to simply extend the ComputedImageStyleDerivatives for implementing custom rules in isImageStyleAllowed().

Also, I removed the use of file_url_transform_relative() because the relative URL is less useful in decoupled architecture due to the need to somewhere have the URL of the resource to which an image relates.

Status: Needs review » Needs work

The last submitted patch, 170: 2825812-170.patch, failed testing. View results
- codesniffer_fixes.patch Interdiff of automated coding standards fixes only.

BR0kEN’s picture

BR0kEN’s picture

The last submitted patch, 172: 2825812-172.patch, failed testing. View results
- codesniffer_fixes.patch Interdiff of automated coding standards fixes only.

Status: Needs review » Needs work

The last submitted patch, 173: 2825812-173.patch, failed testing. View results
- codesniffer_fixes.patch Interdiff of automated coding standards fixes only.

BR0kEN’s picture

Status: Needs work » Needs review
FileSize
14.45 KB
14.35 KB
306 bytes
BR0kEN’s picture

The last submitted patch, 176: 2825812-176.patch, failed testing. View results
- codesniffer_fixes.patch Interdiff of automated coding standards fixes only.

BR0kEN’s picture

Status: Needs review » Needs work
+++ b/core/modules/rest/tests/src/Functional/EntityResource/XmlEntityNormalizationQuirksTrait.php
@@ -99,6 +99,15 @@ protected function applyXmlFieldDecodingQuirks(array $normalization) {
+            if ($normalization[$field_name][$i]['derivatives'] && is_array($normalization[$field_name][$i]['derivatives'])) {
+              $derivatives = &$normalization[$field_name][$i]['derivatives'];
+              if (is_array($derivatives)) {

Hm, the $normalization[$field_name][$i]['derivatives'] is tested by is_array() twice.

BR0kEN’s picture

Why the upload of ~15 kb takes around 2 minutes? Started experiencing this on D.org since yesterday.

Wim Leers’s picture

@ndobromirov:

- You can disable whatever is not needed at later stage, so that will reduce the performance issue that @Berdir was mentioning.

The configurability that this patch is introducing (and which I'm opposing) does not address @Berdir's performance concern as far as I know, because computed values are always computed, see #162.

To make things simpler - drop it out and have a follow-up.

+1


@BR0kEN:

Also, I removed the use of file_url_transform_relative() because the relative URL is less useful in decoupled architecture due to the need to somewhere have the URL of the resource to which an image relates.

This is inconsistent with how the file URL is normalized for File entities, since #2825487: Fix normalization of File entities: file entities should expose the file URL as a computed property on the 'uri' base field. Please restore this.


I've proposed a way forward almost two months ago, in #158. An MVP. Contrib can handle the configurability (and accompanying complexity) of which image styles should show up. I'd love to see this land, but configurability of core REST is already painful enough (it's practically impossible without https://www.drupal.org/project/restui). This would make that considerably more painful. IMHO a contrib module like https://www.drupal.org/project/better_normalizers can decorate the normalizer that's being added here to add configurability. Then only sites that actually observe a performance problem with listing every available image style need this additional complexity.

So, this is what I'm proposing. @alexpott's #156 minus the configurability.

Wim Leers’s picture

This ports @BR0kEN's changes, plus CS fixes and minor cleanup.

The last submitted patch, 181: 2825812-181.patch, failed testing. View results
- codesniffer_fixes.patch Interdiff of automated coding standards fixes only.

Status: Needs review » Needs work

The last submitted patch, 182: 2825812-182.patch, failed testing. View results

BR0kEN’s picture

  1. +++ b/core/modules/image/src/Plugin/DataType/ComputedImageStyleDerivatives.php
    @@ -0,0 +1,151 @@
    + * @see \Drupal\image\Plugin\DataType\ImageStyle
    

    Where this namespace/class exists?

  2. +++ b/core/modules/image/src/Plugin/DataType/ComputedImageStyleDerivatives.php
    @@ -0,0 +1,151 @@
    +    foreach (ImageStyle::loadMultiple() as $style) {
    

    What about overridden entity class and "loadMultiple" method of it?

  3. +++ b/core/modules/image/src/Plugin/DataType/ComputedImageStyleDerivatives.php
    @@ -0,0 +1,151 @@
    +        $this->values[$style->getName()] = $this->getTypedDataManager()
    

    Why do we need to call $this->getTypedDataManager() in a loop?

@Wim Leers, what is the idea of having relative URLs?

Wim Leers’s picture

Status: Needs work » Needs review
FileSize
1.38 KB
10.22 KB
--- a/core/modules/rest/tests/src/Functional/EntityResource/XmlEntityNormalizationQuirksTrait.php
+++ b/core/modules/rest/tests/src/Functional/EntityResource/XmlEntityNormalizationQuirksTrait.php

I shouldn't have reverted this hunk.

Wim Leers’s picture

  1. ✔️ Good catch, fixed!
  2. ✔️
  3. ✔️ This is IMHO a premature optimization. Function calls have been fast in PHP for a long time now. Still, I did what you asked for 👍

@Wim Leers, what is the idea of having relative URLs?

This was discussed in detail in #2825487: Fix normalization of File entities: file entities should expose the file URL as a computed property on the 'uri' base field, and consensus was reached.

Wim Leers’s picture

Oh and rather than configuration, we could also make this controllable through the URL, like I suggested two years ago in #2: #2825814: [PP-1] Allow URL query argument to limit the image style URLs returned by ImageItemNormalizer. I propose we use that follow-up issue to make it controllable, be it through a URL query arg, through configuration, something else, or all of them.

Let's get this foundation in.

hamrant’s picture

I have tested last patch with JSON API, works great, thanks @Wim Leers

Some test results:

"derivatives": {
  "card": {
    "url": "/sites/default/files/styles/card/public/2018-08/test_image.jpg?itok=93mbnNgE",
    "width": 574,
    "height": 323
  },

I think better to use uri and url instead just url that was changed by `file_url_transform_relative()` function.
Now this used in file entity and looks like this:

"uri": {
  "value": "public://2018-08/test_image.jpg",
  "url": "/sites/default/files/2018-08/test_image.jpg"
},
"url": "http://test-site.docksal/sites/default/files/2018-08/test_image.jpg"

This is useful for internal use and for external (for example by vue or react app). I suggest using the same structure in derivatives. As result it should looks like this:

"derivatives": {
  "card": {
    "uri": {
      "value": "public://styles/card/public/2018-08/test_image.jpg?itok=93mbnNgE",
      "url": "/sites/default/files/styles/card/public/2018-08/test_image.jpg?itok=93mbnNgE"
    },
    "url": "http://test-site.docksal/sites/default/files/styles/card/public/2018-08/test_image.jpg?itok=93mbnNgE"
    "width": 574,
    "height": 323
  },
Wim Leers’s picture

@hamrant: Thanks for testing!

Now this used in file entity and looks like this:

The top-level url property you quote only exists when using JSON API, not in Drupal core. It also has been removed from JSON API 2.x, because Drupal core added that root-relative uri.url property.

BR0kEN’s picture

Found the issue when \Drupal\serialization\Normalizer\ComplexDataNormalizer got $object transformed to null.

Wim Leers’s picture

@BR0kEN: wow, interesting! Can you also share steps to reproduce that? Ideally a failing test.

BR0kEN’s picture

Had no time for a test yet, but during debugging it turned out that it's due to a field with svg.

Wim Leers’s picture

This came up again. This time in #3007268: Make Consumer Image Styles compatible with JSON API 2.0-beta2, which is blocking a stable release of JSON API 2.0. The idea of the https://www.drupal.org/project/consumer_image_styles module is to allow one to configure which consumers of the API exist, and which image styles those consumers care about, to then only get those image styles in the output.

Like I said in #188 two months ago (and many comments before it), I'm fine with supporting this. #3007268 implemented something like this already, but A) at the normalizer level, B) only for JSON API. It was modifying JSON API internals and hence it broke in the move from JSON API 1.x to 2.x. If it were implemented at the Typed Data level like this issue proposes, it wouldn't have been a problem at all.

So I checked what it would take to change that implementation, to instead build on top of this core patch.

I've confirmed it to be feasible, but one small change is necessary here: the patch here needs to respect the computed property definitions. Once that is done, it works fine.

Note: relative to #187, not #191, because #191 is not on top of #187.

Wim Leers’s picture

Here's also initial cacheability support. In line with what we did in #2626924: Include processed text in normalizations: "text" field type's "processed" computed property should be non-internal and carry cacheability metadata.

That issue updated \Drupal\serialization\Normalizer\TypedDataNormalizer, but in this case, a more specific normalizer takes precedence (\Drupal\serialization\Normalizer\ComplexDataNormalizer), which hasn't been updated yet.

EDIT: note I specifically used RefinableCacheableDependencyInterface instead of CacheableDependencyInterface to make it simpler for contrib/custom modules to customize the list of computed image style derivatives based on configuration, request context, et cetera.

Status: Needs review » Needs work

The last submitted patch, 195: 2825812-195.patch, failed testing. View results

Wim Leers’s picture

Status: Needs work » Needs review
FileSize
4.1 KB
13.11 KB

#195 failed due to newly added cache tags — great, this means that things are working, and our tests are catching the changes in cacheability! 👍

What was sitll missing was the fact that this by default will result in the computing (and normalizing) of every image style, which means that when the list of image styles changes, so must any cached results. So let's update the code responsible for generating the definition (which will also affect OpenAPI docs for example) to associate the appropriate cache tag.

Status: Needs review » Needs work

The last submitted patch, 197: 2825812-197.patch, failed testing. View results

Wim Leers’s picture

Status: Needs work » Needs review
FileSize
1.01 KB
13.99 KB

Down to 3 failures: the hal_json tests.

Because \Drupal\hal\Normalizer\EntityReferenceItemNormalizer does not normalize all properties on the field, it explicitly ignores those and only normalizes the referenced entity. That's also why e.g. field_media_file's description and display properties, and thumbnail's alt, width, height and title properties are not normalized in hal_json.

And because it doesn't normalize any properties, it also doesn't get the cacheability associated with them. And hence the 3 failures here.

e0ipso’s picture

Status: Needs review » Needs work

What do you think about:

  /**
   * {@inheritdoc}
   */
  public function getPropertyDefinitions() {
    if (isset($this->propertyDefinitions)) {
      return $this->propertyDefinitions;
    }
    $image_style_definition = MapDataDefinition::create();
    $image_style_definition->setPropertyDefinition('url', DataDefinition::create('uri'));
    $image_style_definition->setPropertyDefinition('width', DataDefinition::create('integer'));
    $image_style_definition->setPropertyDefinition('height', DataDefinition::create('integer'));
    // Map image style IDs to a definition.
    $derivatives = NULL;
    \Drupal::moduleHandler()
      ->alter('image_derivatives_exposed_image_style_ids', $derivatives);
    $this->propertyDefinitions = array_map(function () use ($image_style_definition) {
      return $image_style_definition;
    }, ImageStyle::loadMultiple($derivatives));
    return $this->propertyDefinitions;
  }

That will help ease the pain when creating an image style URL has performance implications. It will also simplify consumer_image_styles a lot.

Then one can do:

/**
 * Implements hook_image_derivatives_exposed_image_style_ids_alter().
 */
function mymodule_image_derivatives_exposed_image_style_ids_alter(&$data) {
  $data = ['medium', 'large'];
}
e0ipso’s picture

Status: Needs work » Needs review
FileSize
1.45 KB
6.93 KB

This is the idea I'm proposing above.

Status: Needs review » Needs work

The last submitted patch, 201: 2825812-201.patch, failed testing. View results

e0ipso’s picture

Ugh, my patch above is broken due to a blunt attempt to use D8.6.3 as a base install. Hopefully, the idea I'm proposing is clear enough.

Wim Leers’s picture

I missed your comments until now, sorry!

Introducing more alter hooks is problematic IMHO. We want fewer hooks, not more. Having alter hooks for just about anything is largely why Drupal has as much technical debt and complexity as it does.

This would make consumer_image_styles simpler, at the cost of making drupal more complex. The patch I provided at #3007268-18: Make Consumer Image Styles compatible with JSON API 2.0-beta2 already shows how consumer_image_styles can achieve the same with minimal code, without introducing more APIs.

If everybody else feels this is the way to go, then I'm fine with it. But I'd be concerned about the direction we're going with Drupal core.

jofitz’s picture

Correcting the patch in #201.

Leaving as NW to address @Wim Leers comments in #204.

Berdir’s picture

See #2975722: Many slow queries for lookup up crop of a image_style + file for an issue that this caused. If you use crop.module, it has to check each generated image style url for a crop configuration using an SQL query and add a query parameter so that we can invalidate caches if the crop changes.

Another example would be if you use amazon S3 to store images, many implementations then already check and generate the image styles when generating the URL's as they can't do it on-demand, so the first request to a node with a few images multiplied by bunch of image styles could take like a minute to generate.

So I still think that by default returning all styles is the wrong thing to do and I'm still unhappy about having all this exposed through entity field properties because generating/maintaining those is expensive and needs to be done every time you use that entity, not just on serialization.

Just yesterday I saw an example from a Drupal GraphQL project where the client could request the image styles he needs, I still believe that is the approach that makes the most sense because I'm pretty sure it's very common that different requests need different styles, e.g. when you fetch a list of articles for a list of teasers you need the teaser image style and when you fetch the information for the detail page, you need the large ones. I'm also aware that this means that we likely have to duplicate at least part of the logic for each API/serializer format :(

Wim Leers’s picture

Actually, #2975722: Many slow queries for lookup up crop of a image_style + file is a performance issue in the Crop module regardless of this.

I think you meant to link to #3014232: [regression] ResourceTypeRepository is significantly slower in JSON:API 2, becomes noticeable when handling hundreds of interlinked resources, where a site applied this core patch, and it is causing ~10% of the total response time (see #3014232-18: [regression] ResourceTypeRepository is significantly slower in JSON:API 2, becomes noticeable when handling hundreds of interlinked resources.3). Although to be fair, in that case we're computing all 22 (!!!) image style derivatives for 54 image fields. Having 22 image style derivatives is pretty exceptional, and questionable (the reporter acknowledged this, and said they could easily cut it in half over at #2975722-4: Many slow queries for lookup up crop of a image_style + file).

The Crop module overall seems to have some architectural problems: #2975722-7: Many slow queries for lookup up crop of a image_style + file.

Another example would be if you use amazon S3 to store images, many implementations then already check and generate the image styles when generating the URL's as they can't do it on-demand, so the first request to a node with a few images multiplied by bunch of image styles could take like a minute to generate.

Excellent point! Arguably this should happen during the saving of the node that references these images though, since that's already a slow operation. Lazily generating them the first time they're accessed is going to result in noticeable slowness for end users.

So I still think that by default returning all styles is the wrong thing to do and I'm still unhappy about having all this exposed through entity field properties because generating/maintaining those is expensive and needs to be done every time you use that entity, not just on serialization.

Can you think of a counterproposal?

I'm also aware that this means that we likely have to duplicate at least part of the logic for each API/serializer format :(

Yeah, so that is the alternative to the configuration-based proposal above. And like you say, that also comes with serious downsides.

I really want to address your concerns, but I also really don't want configuration in Drupal core that's pretty much impossible to discover. For Drupal to be actually API-First, all data needs to be accessible via its (HTTP) APIs.

Very rough idea: Is there perhaps something we could do like a generate-then-redirect link relation for each of the image style derivatives? That'd mean generating just a bunch of links, which an API client would have to follow in order to get to the actual data.

e0ipso’s picture

#205 thanks for fixing that!

Just to re-state it, I agree with two points @Berdir brings again in #206:

  1. So I still think that by default returning all styles is the wrong thing to do
  2. I'm still unhappy about having all this exposed through entity field properties because generating/maintaining those is expensive and needs to be done every time you use that entity, not just on serialization.

The patch in #205 will address the first concern, but not the second.


The major friction on this issue has always been performance. There was some hesitation in comments above that this could lead to performance issues, but #3014232: [regression] ResourceTypeRepository is significantly slower in JSON:API 2, becomes noticeable when handling hundreds of interlinked resources proves that the performance problem is real during serialization. It is probably real during entity loads as well, meaning that the performance degradation is even noticeable in non-decoupled projects.

A typical project will have many image styles (I don't think the number of image styles in #3014232: [regression] ResourceTypeRepository is significantly slower in JSON:API 2, becomes noticeable when handling hundreds of interlinked resources is unreasonable), and you have to multiply that by the number of different designs for different consumers.


I'm also aware that this means that we likely have to duplicate at least part of the logic for each API/serializer format :(

I don't think this is actually a problem. Every project has specific serialization needs. We could try to find some common ground around how to normalize typed data but even then there is no guarantee that all the projects will want the same result. This largely happens today, and will continue to happen regardless of the outcome of the resolution of this issue. For instance, GraphQL will allow the consumer to select an image style (or even generate one on the fly) so switching to this may be a step back. Maybe we can have @pmelab or other GraphQL devs confirm this.

I wouldn't make this a hard requirement for this feature.

e0ipso’s picture

In order to unblock this issue we met in a hangout.

Participants: Wim Leers, justafish, Berdir and e0ipso. Baby cameos happened but they were not of relevance for this issue.

Meeting conclusions:

  1. EDIT: (I forgot about this one). We need profile information on how big the performance hit is.
  2. We have to treat the generation of an image style URL as an expensive operation (not only the generation of the derivative image, but also the URL that will trigger its generation).
  3. Said performance impact affects even non-decoupled sites if we keep the computed property approach that generates URLs for all image styles on all image fields.
  4. Drupal core should provide a mechanism to have image style URLs. Very inline with the approach of current patch.
  5. Drupal core should provide extensibility to limit what image styles to return. This should be a PHP API that contribs can implement. The extensibility should allow an incoming request to specify what image styles should be generated.
  6. Each API module is responsible of using this PHP API to surface the image style URLs to the API users.

There is one key remaining question that we did not discuss:

What should be the default behavior? (a) do not generate image style URLs unless explicitly requested because they are expensive, or (b) generate all the all the image style URLs because the PHP API is hard to discover?

e0ipso’s picture

The patch in #205 may tick all boxes. It uses approach (a) to the default behavior. However there may be a problem with entity cache since whatever image styles were selected on a cold entity load will remain there until entity cache is invalidated.

Additionally we'll be adding another cache tag to our entities image_style.list, but I think that's OK.

e0ipso’s picture

Issue tags: +needs profiling
miiimooo’s picture

Re-rolled for last nights security release 8.6.10.. couldn't get the interdiff done.. sorry

Version: 8.7.x-dev » 8.8.x-dev

Drupal 8.7.0-alpha1 will be released the week of March 11, 2019, which means new developments and disruptive changes should now be targeted against the 8.8.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

vtcore’s picture

Re-rolled patch for 8.7.x

Wim Leers’s picture

Taking another fresh look at this :)

By the way, with 42 followers, this is one of the most-followed remaining API-First Initiative issues.


#208:

The patch in #205 will address the first concern, but not the second.

vs
#209:

The patch in #205 may tick all boxes.

That seems contradictory?


Quoting @Berdir in #206:

the client could request the image styles he needs, I still believe that is the approach that makes the most sense because I'm pretty sure it's very common that different requests need different styles […] I'm also aware that this means that we likely have to duplicate at least part of the logic for each API/serializer format :(

Thinking about this again, here's one crazy idea (that I have concerns about too, but I figured I'd at least leave it as a suggestion). What if we make 'derivatives' => [] by default, but add 'derivatives_instructions' => 'Add a`derivatives=style1,style2` query string parameter to get derivatives, valid derivative styles are: `thumbnail`, `medium` and `hero`.. Then when ?derivatives=thumbnail,medium appears in the URL, you'd get 'derivatives' => ['thumbnail' => …, 'medium' => …], and 'derivatives_instructions' would disappear.

This would work in JSON:API, REST and GraphQL.

It'd be a first time that we have request context-dependent computed data but … that's exactly what the url.query_args:derivatives cache context describes!


After having written this, I scanned the issue, and found @Berdir proposing the same in December 2017 in #125:

If this would be done in context of REST/serializer, then I could imagine it being controlled by a query argument like ?include_image_styles=medium,thumbnail. But having this on the entity field level makes that more complicated.

and this in #135:

[…] because we definitely can not somehow pass URL query arguments to a computed property (which has no concept of passing arguments).

I'm proposing we do do that, despite this being new territory.


Thoughts?

ndobromirov’s picture

I'm proposing we do do that, despite this being new territory.

+1. Having a solution in core for decoupled image styles is highly important.
As I see it a fast hack should be fairly easy to do on top of the existing patch, so we can have a working PoC to have discussions on.

e0ipso’s picture

We established that the image style URL generation needs to be treated as a resource intensive operation in the call referenced in #209.

Having anonymous users trigger resource intensive operations may be dangerous. I think the appropriate approach is to have a setting server-side that gates the image styles that may be used.

garphy’s picture

@e0ipso,
Image styles aren't generated until there actually requested : listing image style URLs in the response body doesn't actually generates the derivative. Putting the URLs in the response isn't intensive pre-se.
But maybe you care that the URLs are disclosed, then maliciously used to DoS the infra ?

Wim Leers’s picture

Thanks for chiming in, all! I was hoping for more responses. Hopefully this response from me results in more community members who previously spoke up to speak up again :)


#216: 👍 🙂

#218: it's not just computing the image style URL though, it's also instantiating typed data properties, and computing the values for the width and height typed data properties, and hence loading the File entity.

#217: Anonymous users can already trigger resource-intensive operations. It's already possible to bypass Page Cache by appending a random query string. Having a malicious user do that on the most expensive page on a site would cause a load similar to that of a malicious user requesting a lot of unneeded image styles.

e0ipso’s picture

#218 there is a whole discussion in this thread (I know... it's loooong) clarifying that point and building consensus on that statement.

#219 I don't think this is necessarily the same case. It certainly is from the point of view of the URL creation. It being a problem in other systems doesn't necessarily mean that we want to have another instance of the problem.

I'm sure you remember we had a security release specifically on the issue of image styles (leading to server side "rendered" image style URLs containing the famous #itok). I see where you are coming from though. However unless we limit the derivatives out of the box we'll be giving out *many* #itok which may defeat the point.

Let's try to unlock this again. What do you think it needs to happen for that? Should we have a recap summary of the current positions? This is an outstanding gap in the API First capabilities of core, let's fix it!

Wim Leers’s picture

First:

Let's try to unlock this again. What do you think it needs to happen for that? Should we have a recap summary of the current positions? This is an outstanding gap in the API First capabilities of core, let's fix it!

💪🥳👍 :)

However unless we limit the derivatives out of the box we'll be giving out *many* #itok which may defeat the point.

Great point. The goal of that ?itok query string is to ensure that only the server can choose which image styles to generate, not the client. If anonymous users can specify ?derivatives=medium,thumbnail,…, then it's effectively still user-controlled. You've convinced me that this is indeed a regression, an increase in risk. 😔

An obvious yet naïve way to mitigate that would be … to require a specify image styles permission, otherwise users wouldn't be able to specify ?derivatives. I haven't seen that proposed yet. However, perhaps that wasn't proposed precisely because it is naïve: that still means the anonymous user would not be able to get any image styles at all! We could choose to add a generate $image_style image style permission, to only allow a particular user role (especially anonymous) to generate particular image styles.

Then instead of my proposal in #215 which resulted in

'derivatives_instructions' => 'Add a`derivatives=style1,style2` query string parameter to get derivatives, valid derivative styles are: `thumbnail`, `medium` and `hero`.

this would result in

'derivatives_instructions' => 'Add a`derivatives=style1,style2` query string parameter to get derivatives, allowed derivative styles are: `thumbnail` and `medium`.

(Note "allowed" instead of "valid".)

What do you think?

ndobromirov’s picture

The added security will be OK, but if anonymous needs all the images it will cause maintenance overhead.
If we introduce permissions for this there should be a master permission for allow all.

smithmilner’s picture

Quoting @Wim Leers in #207

Having 22 image style derivatives is pretty exceptional, and questionable...

Just wanted to add that If the site uses responsive image styles this is very realistic. Each responsive style can use many regular image styles. For example, we have 164 regular image styles for the needs of one of our builds which has 22 responsive image styles.

That said, have we considered support for responsive image styles? Or would that be completely up to the client?

ndobromirov’s picture

FileSize
14.18 KB
698 bytes

I am still running on 8.6 and managed to hit another edge case - media referencing a missing / deleted file.
Here is patch that resolved it for me.
The patch is against 8.6.16, based on the one from #212.

jibran’s picture

+++ b/core/modules/serialization/src/Normalizer/ComplexDataNormalizer.php
@@ -28,6 +28,7 @@ class ComplexDataNormalizer extends NormalizerBase {
+    $this->addCacheableDependency($context, $object);

This is awefully similar to #2997123-89: Cacheability of normalized computed fields' properties is not captured during serialization.

+++ b/core/modules/serialization/src/Normalizer/PrimitiveDataNormalizer.php
@@ -21,6 +21,9 @@ class PrimitiveDataNormalizer extends NormalizerBase {
+    // Add cacheability if applicable.
+    $this->addCacheableDependency($context, $object);

Version: 8.8.x-dev » 8.9.x-dev

Drupal 8.8.0-alpha1 will be released the week of October 14th, 2019, which means new developments and disruptive changes should now be targeted against the 8.9.x-dev branch. (Any changes to 8.9.x will also be committed to 9.0.x in preparation for Drupal 9’s release, but some changes like significant feature additions will be deferred to 9.1.x.). For more information see the Drupal 8 and 9 minor version schedule and the Allowed changes during the Drupal 8 and 9 release cycles.

ndobromirov’s picture

Here is a re-roll against the latest 8.7 of #214 incorporating the changes from #224.

Version: 8.9.x-dev » 9.1.x-dev

Drupal 8.9.0-beta1 was released on March 20, 2020. 8.9.x is the final, long-term support (LTS) minor release of Drupal 8, which means new developments and disruptive changes should now be targeted against the 9.1.x-dev branch. For more information see the Drupal 8 and 9 minor version schedule and the Allowed changes during the Drupal 8 and 9 release cycles.

vsujeetkumar’s picture

Status: Needs work » Needs review
FileSize
13.5 KB

Re-roll patch created for 9.1.x

Status: Needs review » Needs work

The last submitted patch, 229: 2825812_229.patch, failed testing. View results

Version: 9.1.x-dev » 9.2.x-dev

Drupal 9.1.0-alpha1 will be released the week of October 19, 2020, which means new developments and disruptive changes should now be targeted for the 9.2.x-dev branch. For more information see the Drupal 9 minor version schedule and the Allowed changes during the Drupal 9 release cycle.

iivanov’s picture

FileSize
13.5 KB

Here is a re-roll against the latest 9.1.4. I was't able to apply the latest patch - 2825812_229.patch

Vinay15’s picture

Status: Needs work » Needs review
FileSize
13.32 KB
4.85 KB

Re-roll for 9.1.x, created from #229 as the patch from #232 isn't applying.

Status: Needs review » Needs work

The last submitted patch, 233: 2825812-233.patch, failed testing. View results

Version: 9.2.x-dev » 9.3.x-dev

Drupal 9.2.0-alpha1 will be released the week of May 3, 2021, which means new developments and disruptive changes should now be targeted for the 9.3.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

joachim’s picture

Patch works well, but a few things need tidying up or changing:

  1. +++ b/core/modules/image/src/Plugin/DataType/ComputedImageStyleDerivatives.php
    @@ -0,0 +1,190 @@
    + * Computed image style derivatives class.
    

    This line isn't very descriptive. Something like 'A data type for image derivatives.' would be better.

  2. +++ b/core/modules/image/src/Plugin/DataType/ComputedImageStyleDerivatives.php
    @@ -0,0 +1,190 @@
    +   * @param \Drupal\file\FileInterface $file
    +   * @param $width
    +   * @param $height
    +   * @param \Drupal\image\ImageStyleInterface $style
    +   * @return array|bool
    +   *
    +   * @todo rather than returning an array, return a value object that
    +   *   implements CacheableDependencyInterface
    +   *
    +   * @see \Drupal\image\Entity\ImageStyle::buildUrl
    +   * -> tag: config:image.settings
    +   *
    +   * -> tag: $style->getCacheTags()
    

    This docblock isn't formatted correctly.

    Also, is the TODO something that could be done now? If not, file a follow-up issue and explain there why it's blocked or delayed.

  3. +++ b/core/modules/image/src/Plugin/DataType/ImageStyleDerivativesDefinition.php
    @@ -0,0 +1,49 @@
    +namespace Drupal\image\Plugin\DataType;
    

    This looks like it's in the wrong namespace, as it's not a plugin.

    Maybe put it in Drupal\Image\TypedData, since the parent class is in TypedData too?

  4. +++ b/core/modules/image/src/Plugin/DataType/ImageStyleDerivativesDefinition.php
    @@ -0,0 +1,49 @@
    + * The definition of image style list, containing "width", "height" and "url".
    

    This should match the other related classes' first lines, which all start with 'A typed data definition class ...'

  5. +++ b/core/modules/image/src/Plugin/DataType/ImageStyleDerivativesDefinition.php
    @@ -0,0 +1,49 @@
    +    \Drupal::moduleHandler()
    +      ->alter('image_derivatives_exposed_image_style_ids', $derivatives);
    

    This is inventing a hook. Do we want or need that here?

    Also, hooks need to be documented.

vsujeetkumar’s picture

Re-roll patch created for 9.3.x

Status: Needs review » Needs work

The last submitted patch, 237: 2825812-237.patch, failed testing. View results

vsujeetkumar’s picture

Status: Needs work » Needs review
FileSize
13.51 KB
4.66 KB

Worked on #236, Please have a look.
#236.1: Done
#236.2: Done with dockblock formatting only.
#236.3: Done
#236.4: Done
#236.5: Needs to Work.

Status: Needs review » Needs work

The last submitted patch, 240: 2825812-240.patch, failed testing. View results

Version: 9.3.x-dev » 9.4.x-dev

Drupal 9.3.0-rc1 was released on November 26, 2021, which means new developments and disruptive changes should now be targeted for the 9.4.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

Version: 9.4.x-dev » 9.5.x-dev

Drupal 9.4.0-alpha1 was released on May 6, 2022, which means new developments and disruptive changes should now be targeted for the 9.5.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

cweiske’s picture

#240 works fine here on Drupal 9.4.2. It allows me to index image variants into elasticsearch.

ravi.shankar’s picture

Version: 9.5.x-dev » 10.1.x-dev

Drupal 9.5.0-beta2 and Drupal 10.0.0-beta2 were released on September 29, 2022, which means new developments and disruptive changes should now be targeted for the 10.1.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

Rassoni’s picture

Fix patch failed 10.1.x branch (not include test cases issues)

Rassoni’s picture

Fixed CC issue

Version: 10.1.x-dev » 11.x-dev

Drupal core is moving towards using a “main” branch. As an interim step, a new 11.x branch has been opened, as Drupal.org infrastructure cannot currently fully support a branch named main. New developments and disruptive changes should now be targeted for the 11.x branch, which currently accepts only minor-version allowed changes. For more information, see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.