Problem/Motivation

Follow-up from #2211227: Refactor image and imagetoolkit: isExisting, isSupported, supportedTypes, getMimeType.

In the above mentioned issue, we discussed and decided that passing around an image parameter to calls to a toolkit is useless.

Why? Because a toolkit instance is linked to exactly 1 Image object, passing around that object seems not correct. Better would be to pass it to the constructor. However, this is not possible as the toolkit object is created just before the image object, as we also need to pass the toolkit object to the Image constructor.

Proposed resolution

Instead of passing the Image to the methods (as now) or to the constructor (which is not possible), we create a property and (public) setter/getter for the ImageInterface object in toolkit that should be called by the constructor of the Image class. A 2nd call to that setter is not expected and thus should fail with an exception.

In addition to this basic part of the issue, the currently RTBC'd patch:
- streamlines some documentation in involved classes.
- declares a not yet declared but used property in a test class ($source in ImageTest.php).

Remaining tasks

Commit patch.

User interface changes

None.

API changes

The signature of several methods will change. This will be documented in the Change record that documents the new Image API.

Comments

fietserwin’s picture

fietserwin’s picture

Status: Active » Needs review
StatusFileSize
new53.33 KB
new26.95 KB

Patch is built on top of parent issue #2211227: Refactor image and imagetoolkit: isExisting, isSupported, supportedTypes, getMimeType and is for the test bot, the interdiff is the patch for this issue and is thus for manual review.

Status: Needs review » Needs work

The last submitted patch, 2: 2211227-2257587-2.patch, failed testing.

fietserwin’s picture

Status: Needs work » Needs review
StatusFileSize
new59.73 KB
new33.66 KB

We are testing order and position of parameters in 3 places:
- unit test \Drupal\Tests\Core\Image\ImageTest (that was already adapted in the patch of #2)
- webtest \Drupal\image\Tests\ImageEffectsTest (corrected here)
- webtest \Drupal\system\Tests\Image\ToolkitTest (corrected here)

This does need some clean up, especially the latter 2 seem to test very similar things.

The patch is, as in #2, a combination of patch for the parent issue and this issue and is for the test bot, the interdiff is the patch for this issue and is thus for manual review (and is thus not the interdiff between #2 and #4, that's not interesting and nobody had already reviewed #2 (I think)).

fietserwin’s picture

Issue summary: View changes
mondrake’s picture

Review of interdiff code in #4

+++ b/core/lib/Drupal/Core/ImageToolkit/ImageToolkitInterface.php
@@ -60,25 +60,39 @@ public function settingsForm();
+   * @throws \BadMethodCallException when called twice.

The @throws description should be a separate line, see the coding standards.
Also, I see @throws is usually after the @param/@return blocks. I don't know if it matters though.

+++ b/core/modules/system/lib/Drupal/system/Plugin/ImageToolkit/GDToolkit.php
@@ -7,6 +7,7 @@
+use BadMethodCallException;

You don't need use for root classes, just call \BadMethodCallException with backslash in the code. OTOH, how about introducing a specific ImageToolkitException here? There's one waiting in #2122605-18: Remove isAvailable() from ImageToolkitInterface.

+++ b/core/modules/system/lib/Drupal/system/Plugin/ImageToolkit/GDToolkit.php
@@ -37,6 +45,23 @@ class GDToolkit extends ImageToolkitBase {
+      throw new BadMethodCallException(__METHOD__ . '() may only be called once');

Same here

+++ b/core/modules/system/lib/Drupal/system/Plugin/ImageToolkit/GDToolkit.php
@@ -23,6 +24,13 @@
+   * Image object this toolkit instance is tied to..
+   *
+   * @var \Drupal\Core\Image\ImageInterface
+   */
+  protected $image;
+
+  /**
    * A GD image resource.
    *
    * @var resource
@@ -37,6 +45,23 @@ class GDToolkit extends ImageToolkitBase {

@@ -37,6 +45,23 @@ class GDToolkit extends ImageToolkitBase {
   protected $type;
 
   /**
+   * {@inheritdoc}
+   */
+  public function setImage(ImageInterface $image) {
+    if ($this->image) {
+      throw new BadMethodCallException(__METHOD__ . '() may only be called once');
+    }
+    $this->image = $image;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getImage() {
+    return $this->image;
+  }
+

This could go to the ImageToolkitBase? I am expecting this to be same in all toolkits, and GDToolkit and TestToolkit already extend from ImageToolkitBase.

+++ b/core/modules/system/lib/Drupal/system/Plugin/ImageToolkit/GDToolkit.php
@@ -23,6 +24,13 @@
+   * Image object this toolkit instance is tied to..

One full stop too much ;)

+++ b/core/modules/system/lib/Drupal/system/Plugin/ImageToolkit/GDToolkit.php
@@ -37,6 +45,23 @@ class GDToolkit extends ImageToolkitBase {
+      throw new BadMethodCallException(__METHOD__ . '() may only be called once');

Full stop at the end of text?

mondrake’s picture

Status: Needs review » Needs work
fietserwin’s picture

Status: Needs work » Needs review
StatusFileSize
new60.15 KB
new34.12 KB
new2.94 KB

Thanks for reviewing. All points done, except the introduction of our own exception. Let's postpone that to the mentioned issue.

As before:
-.patch is for test bot (combined patch)
- interdiff.txt is for manual review
- interdiff4-8.txt is some kind of interdiff between the interdffs of #4 and #8. [EDIT: but I failed to create it properly. In fact, I moved the property, getter and setter from GD to base toolkit including any use statements]

mondrake’s picture

Status: Needs review » Needs work
  1. +++ b/core/modules/system/tests/modules/image_test/lib/Drupal/image_test/Plugin/ImageToolkit/TestToolkit.php
    @@ -7,6 +7,7 @@
    +use BadMethodCallException;
    

    Leftover, it's in the parent class now

  2. +++ b/core/modules/system/tests/modules/image_test/lib/Drupal/image_test/Plugin/ImageToolkit/TestToolkit.php
    @@ -45,6 +53,23 @@ class TestToolkit extends ImageToolkitBase {
    +  public function setImage(ImageInterface $image) {
    +    if ($this->image) {
    +      throw new BadMethodCallException(__METHOD__ . '() may only be called once');
    +    }
    +    $this->image = $image;
    +  }
    +
    +  /**
    +   * {@inheritdoc}
    +   */
    +  public function getImage() {
    +    return $this->image;
    +  }
    +
    +  /**
    +   * {@inheritdoc}
    +   */
    

    Same

+++ b/core/modules/system/tests/modules/image_test/lib/Drupal/image_test/Plugin/ImageToolkit/TestToolkit.php
@@ -7,6 +7,7 @@
 use Drupal\Core\Image\ImageInterface;

I suppose it can be removed here too, now?

mondrake’s picture

Sorry, couple more minor things

+++ b/core/modules/system/lib/Drupal/system/Plugin/ImageToolkit/GDToolkit.php
@@ -8,7 +8,6 @@
@@ -35,7 +34,6 @@ class GDToolkit extends ImageToolkitBase {

@@ -35,7 +34,6 @@ class GDToolkit extends ImageToolkitBase {
    * @var int
    */
   protected $type;
-
   /**

Let's keep this blank line.

+++ b/core/tests/Drupal/Tests/Core/Image/ImageTest.php
@@ -16,6 +16,13 @@
   /**
+   * Path to the image file.
+   *
+   * @var string
+   */
+  protected $source;
+

Just to check, this is because setUp() is setting this property but it was not declared in the class, right?

fietserwin’s picture

Status: Needs work » Needs review
StatusFileSize
new59.45 KB
new33.09 KB

Thanks, all corrected, I was a bit too fast with posting the new patch and forgot the test class. And yes you are right (PHPStorm complained about it and (AFAIK) in Drupal we do declare properties explicitly).

You probably also noticed that:
- I also streamlined some documentation in this patch.
- In ImageTest, I had to create new toolkit instances, if not the default image was used in the test. Thus properties image and toolkit of that class are linked together and cannot be reused without the other (setImage() will throw).
(For the core committer, I will update the summary with this info as well)

(More or less) As before:
- .patch is for test bot (combined patch).
- interdiff-11.txt is for manual review (patch for this issue only on top of parent issue patch).

mondrake’s picture

Status: Needs review » Postponed

Seems OK now, we need to wait for the parent to get in first.

fietserwin’s picture

Issue summary: View changes
Status: Postponed » Reviewed & tested by the community

RTBC per #12 and comment #26 of the parent issue: #2211227-26: Refactor image and imagetoolkit: isExisting, isSupported, supportedTypes, getMimeType.

- This patch is a combination of the parent issue and this issue.
- The interdiff is the "patch" for this issue only.

tim.plunkett’s picture

+++ b/core/lib/Drupal/Core/Image/Image.php
@@ -58,6 +58,7 @@ class Image implements ImageInterface {
+    $this->toolkit->setImage($this);

@@ -75,14 +76,14 @@ public function isValid() {
-    return $this->toolkit->getHeight($this);
+    return $this->toolkit->getHeight();

+++ b/core/lib/Drupal/Core/ImageToolkit/ImageToolkitBase.php
@@ -7,11 +7,36 @@
+      throw new \BadMethodCallException(__METHOD__ . '() may only be called once.');

Why is this desirable? Why would we *choose* to make the toolkit stateful?

fietserwin’s picture

An image is strictly tied to 1 toolkit: we cannot change toolkit halfway processing an image style.
Vice versa, 1 toolkit is tied to 1 image. This because Image holds the source, but (GD)Toolkit holds the (GD) resource based on that source and subsequent manipulations. so there is state in toolkit that Image depends on and that Image does not have itself. Though this tie may not be so strict, a toolkit object could be reused when it is finished with 1 Image, but we chose to not do so and always create a new toolkit object together with an Image object. In practice this won't be a problem, as Images (and their toolkits) are created via the factory, but a few tests indeed did reuse a toolkit object.

(In fact, what we see here is a (1 of many) code smell that tells us that toolkit and image should be unified in 1 class/interface/factory. Time permitting, we might end up doing that yet in D8.)

fietserwin’s picture

StatusFileSize
new59.48 KB
new33.09 KB

Reroll after reroll of #2211227: Refactor image and imagetoolkit: isExisting, isSupported, supportedTypes, getMimeType which was needed after #375062: imagecolorsforindex() Color index nnn out of range in GDToolkit.

As before:
- .patch is for both issues at the same time
- interdiff-16.txt is only for this issue (and thus not an interdiff with #11)

xjm’s picture

Status: Reviewed & tested by the community » Postponed

Can we edit https://drupal.org/node/2084547 to add a reference to this issue? That way, the CR can document the work in progress and will appear in the sidebar of this node.

Also, this and that shouldn't both be RTBC at the same time. This seriously confused me. :P .Postponing on #2211227: Refactor image and imagetoolkit: isExisting, isSupported, supportedTypes, getMimeType.

fietserwin’s picture

Status: Postponed » Needs review
StatusFileSize
new32.86 KB

#2211227: Refactor image and imagetoolkit: isExisting, isSupported, supportedTypes, getMimeType is in, so the interdiff now becomes the patch. Had to change some paths in it though.

mondrake’s picture

Status: Needs review » Needs work

Very minor, but let's fix it anyway :)

+++ b/core/lib/Drupal/Core/ImageToolkit/ImageToolkitInterface.php
@@ -244,10 +235,10 @@ public function getMimeType(ImageInterface $image);
+   *   True if the toolkit is available on this machine, false otherwise.

TRUE and FALSE (capital letters)

fietserwin’s picture

Status: Needs work » Needs review
StatusFileSize
new32.86 KB
new636 bytes

fixed that minor.

mondrake’s picture

Status: Needs review » Reviewed & tested by the community

Good to go for me. Nice cleanup. RTBC

catch’s picture

Status: Reviewed & tested by the community » Fixed

Committed/pushed to 8.x, thanks!

  • catch committed dbb3bb0 on 8.x
    Issue #2257587 by fietserwin: Remove  parameter in calls between and...

Status: Fixed » Closed (fixed)

Automatically closed - issue fixed for 2 weeks with no activity.