Problem/Motivation

ImageInterface has currently methods setWidth() and setHeight(). They might give a user the impression that calling that method will somehow change the width /height of the image. It doesn't.

These methods were necessary due to the historically grown separation between ImageInterface and ImageToolkitInterface. If a toolkit changes the image by performing an operation on it (like resize or rotate), the Image must be able to tell the new dimensiions to users of its interface. So the only objects that should use these methods are toolkit objects. To all others these methods are confusing (and should not be used at all).

Proposed resolution

  • Issue #2103621: Move GD logic from ImageInterface to toolkit, tie toolkit instance to Image instance, toolkits should no longer be instantiated separately creates a 1-1 relation between instances of ImageInterface and ImageToolkitInterface. This gives the opportunity to move the width and height properties to the toolkit and remove the set methods.
  • The get methods on ImageInterface should be forwarded to and return the value from their toolkit counterparts.
  • The GdToolkit should implement the get methods by returning imagesx()/imagesy() on its (own) resource property.
  • The current patch contains some cleanup and other polishing changes as well (Document that Image and ImageFactory constructors can accept NULL $source; injected the ImageFactory services in the setUp methods of toolkit tests; add getToolkitId() to image factory (besides already existing setToolkitId())

Remaining tasks

Agree on "scope creep", I (@fietserwin, OP) do agree on it.

User interface changes

None

API changes

Removal of those 2 methods, currently only used by GdToolkit (and some tests)

Comments

mondrake’s picture

Definitely makes sense to me. We will have to be careful though and see there are no impacts (or alternative solutions) to effects that in D7 are cloning the stdClass Image object to start fresh a new image for overlaying on another, or for checking e.g. transformDimensions. Definitely cloning is a no go anymore in D8 (tested on my skin).

mondrake’s picture

Assigned: Unassigned » mondrake
Status: Postponed » Active

I'll take at stab at this now that parent landed.

mondrake’s picture

Assigned: mondrake » Unassigned
Status: Active » Needs review
Related issues: +#2063373: Cannot save image created from scratch
StatusFileSize
new26.22 KB

This will fail, but let's see where. It's removing height/width properties and setters from ImageInterface and moving to toolkit, but also addressing #1 and the OP in #2063373: Cannot save image created from scratch, by introducing a new method to the image factory that allows to create Image objects without reading the image from a file. More explanations when this will turn green.

Status: Needs review » Needs work

The last submitted patch, 3: 2196067-remove_hw-3.patch, failed testing.

mondrake’s picture

Status: Needs work » Needs review
StatusFileSize
new30.11 KB

Bot?

mondrake’s picture

Title: Remove setWidth and setHeight from Imageinterface » Remove setWidth and setHeight from ImageInterface; enable creation of non-file based Image objects

Status: Needs review » Needs work

The last submitted patch, 5: 2196067-remove_hw-5.patch, failed testing.

mondrake’s picture

Status: Needs work » Needs review
StatusFileSize
new4.33 KB
new33.08 KB
fietserwin’s picture

I tried to review the patch. IMO this is far more than this issue is about. So I could highlight all things that do not belong to the original intent of this issue, but I will await your explanation. My idea is to not do the other features it in this patch, but in a follow-up (the already created and now related issue). This because the features seem so unrelated. Moreover, the whole image system is about processing existing images. The only use through Drupal (and that includes all of D7 contrib as known by me) is: take an existing image, process it (resize on file upload or create derivatives using image styles). So we are talking about a feature request! This issue is about misleading and incorrect interface methods. And now we are mixing in a feature request to this issue to be able to start an image from scratch (blank canvas). I'm not opposed to that, but can we defer that to #2063373: Cannot save image created from scratch?

If all these changes are needed to keep some tests running, I would think that these tests are wrong and should be removed or adapted. If so, what tests are the failing ones?

If #1 needs to be addressed in this issue (seems a bit unrelated as well), we need to define what this means: do you really need to create an image object or do you need to be able create another GD resource or do you need to be able to stack commands to imagemagick? In the latter case, the Image object is not the place to do so, we will have toolkit operations for that.

[EDIT: cross-post: I am referring to the patch in #5, I am awaiting your explanation]

mondrake’s picture

Title: Remove setWidth and setHeight from ImageInterface; enable creation of non-file based Image objects » Remove setWidth and setHeight from ImageInterface
Status: Needs review » Needs work

#9 - Yes, this is going too far, agree. Let's step back to OP. Will post a reworked patch.

In Textimage 7, I am creating a blank canvas image in memory that I use to overlay text on via imagettftext. Then that canvass image is overlayed itself onto a background image via the imagecache_actions overlay effect. In D8 I am not able to start a blank canvass image anymore, I will have to always load it from disk as we stand. So it's not really a Feature Request IMO, but rather a regression.

mondrake’s picture

Status: Needs work » Needs review
StatusFileSize
new23.6 KB

So this patch:

  1. removes height/width properties and related setters from ImageInterface
  2. height/width getters in Image now defer request to the underlying toolkit
  3. introduce height/width getters in ImageToolkitInterface and implementations
  4. adds an optional parameter in ImageFactory get() to specify the toolkit id to use for an image, useful in tests and in preparation for future work (I would like to expand ImageFactory with isSupported($uri, $toolkit_id) and supportedTypes($toolkit_id) methods to find a home for the image type checks to be discussed in #2211227: Refactor image and imagetoolkit: isExisting, isSupported, supportedTypes, getMimeType)
  5. inject the ImageFactory service in web tests (cleanup; also a if ($this->container->has('image.toolkit.manager')) in ValidatorTest.php was wrongly converted in previous patch when ->has('image.toolkit') had a sense)
  6. in order to be able to PHPUnit test image width and height getters, since their properties are no longer in Image, the Toolkit mock needs to be stubbed 'less' and let it do its work. Done here.

Status: Needs review » Needs work

The last submitted patch, 11: 2196067-remove_hw-9.patch, failed testing.

mondrake’s picture

Status: Needs work » Needs review
StatusFileSize
new1.91 KB
new23.76 KB

Reverted too much...

fietserwin’s picture

  1. +++ b/core/lib/Drupal/Core/Image/Image.php
    @@ -91,8 +77,11 @@ class Image implements ImageInterface {
    +    if ($source) {
    +      $this->source = $source;
    

    So Image is able to handle not passing in a source. Can you adapt the comment to something like:
    * @param string $source
    * The path to an image file or the empty string to start with no image source.
    Or make it allow NULL as well

  2. +++ b/core/lib/Drupal/Core/Image/Image.php
    @@ -91,8 +77,11 @@ class Image implements ImageInterface {
    +      $this->processInfo();
    +    }
    

    Not sure that this is needed here now, though it would mean we could remove all the calls to it in the getters (if we also add it to setSource() and save(), though that one has this call already).

  3. +++ b/core/lib/Drupal/Core/Image/ImageFactory.php
    @@ -53,19 +53,38 @@ public function setToolkitId($toolkit_id) {
    +   * Constructs a new Image object from an image file.
        *
    

    A bit inconsistent with the change on the Image constructor, where we now do accept an empty source param.

  4. +++ b/core/lib/Drupal/Core/Image/ImageFactory.php
    @@ -53,19 +53,38 @@ public function setToolkitId($toolkit_id) {
    +   * @param string $toolkit_id
    +   *   (Optional) The image toolkit ID to use for this image.
        *
    

    I like this idea, though it will hardly have a normal use. But it does allow for easier and more dynamic toolkit selection. We can get the same with setToolkit and a getToolkit to be able to set the toolkit to its original value. Do we need a getToolkit anyway, for reasons of completeness? (may be a follow up).

  5. +++ b/core/lib/Drupal/Core/ImageToolkit/ImageToolkitInterface.php
    @@ -193,11 +190,9 @@ public function scaleAndCrop(ImageInterface $image, $width, $height);
    -   * @return array
    +   * @return array|bool
        *   FALSE, if the file could not be found or is not an image. Otherwise, a
    

    I think that the Drupal standard is to specify array|FALSE (not official phpdoc syntax, but it is clearer).

  6. +++ b/core/modules/system/lib/Drupal/system/Plugin/ImageToolkit/GDToolkit.php
    @@ -304,10 +295,8 @@ public function getInfo(ImageInterface $image) {
    -    if (isset($data) && is_array($data) && in_array($data[2], $this->supportedTypes())) {
    +    if (isset($data) && is_array($data) && in_array($data[2], static::supportedTypes())) {
           $details = array(
    

    Correct, but may be postponed to one of the follow-ups.

  7. +++ b/core/tests/Drupal/Tests/Core/Image/ImageTest.php
    @@ -70,10 +60,14 @@ protected function setUp() {
       protected function getToolkitMock(array $stubs = array()) {
         $mock_builder = $this->getMockBuilder('Drupal\system\Plugin\ImageToolkit\GDToolkit');
         if ($stubs && is_array($stubs)) {
    -      $mock_builder->setMethods($stubs);
    +      $stubs += array('getPluginId', 'save');
    +    }
    +    else {
    
    @@ -208,11 +184,13 @@ public function testChmodFails() {
    +    $this->assertFalse((bool) $image->getWidth());
       }
    

    The type hinting will assure that you have an array, and NULL is not an array. So the if condition and the else branch can be removed.

  8. +++ b/core/tests/Drupal/Tests/Core/Image/ImageTest.php
    @@ -208,11 +184,13 @@ public function testChmodFails() {
    +    $this->assertFalse((bool) $image->getWidth());
       }
    

    The specification says "..., or 0 if the image is invalid". Tests should test the specification (and as such clarify the specification), so lets test for 0.

In general the patch is OK, though there are a few points above that need to be solved (1, 5, 7, 8). Other points are more a matter of do it here or in the designated follow ups that already exist: #2211227: Refactor image and imagetoolkit: isExisting, isSupported, supportedTypes, getMimeType and #2063373: Cannot save image created from scratch.

fietserwin’s picture

Status: Needs review » Needs work
mondrake’s picture

Status: Needs work » Needs review
StatusFileSize
new4.53 KB
new25.53 KB

#14 - thanks for the review.

1. Done. Later in #2063373: Cannot save image created from scratch we should exclude NULL from the get() method of ImageFactory, i.e. it should check that a $source file exists before instantiating an Image object; $source = NULL should be left for the to be 'createNew' or 'createCanvas' method.

2. These were removed in the patch in #8, then reverted to manage scope. I suggest to go back to this in #2063373: Cannot save image created from scratch where we will have to manage the status of the $processed property in relation to starting an image from scratch.

3. Adapted to (1)

4. Good point, added a getToolkitId() method, and a test for it.

5. Done

6. It should have been like this in the parent patch...

7. Reworked

8. Reworked to test isExisting()

fietserwin’s picture

Issue summary: View changes
  1. +++ b/core/lib/Drupal/Core/Image/ImageFactory.php
    @@ -53,10 +53,21 @@ public function setToolkitId($toolkit_id) {
        * @param string $source
    -   *   The path to an image file.
    +   *   The path to an image file, or NULL to construct the object with no
    +   *   image source.
        * @param string $toolkit_id
    

    @param string|NULL $source (change accordingly for constructor in Image as well)

  2. +++ b/core/tests/Drupal/Tests/Core/Image/ImageTest.php
    @@ -55,11 +55,11 @@ protected function setUp() {
    -    if ($stubs && is_array($stubs)) {
    +    if (!empty($stubs)) {
           $stubs += array('getPluginId', 'save');
    

    Formerly, you did add them in all cases, now only if the array passed in is not empty?

With the 2 changes from 1 this is good to go for me. Updated issue summary to reflect current status and contents of patch.

mondrake’s picture

StatusFileSize
new1.04 KB
new25.6 KB

re #17

1. Done

2. We always need save() and getPluginId() to be stubbed, regardless of other methods to be stubbed. So:

input: none or empty array() => output: $stubs = array('getPluginId', 'save');
input: array('rotate') => output: $stubs = array('rotate', 'getPluginId', 'save');

and yes, this is a change vs. current HEAD. In current HEAD, all methods of the toolkit get test doubles, if $stubs is empty. This means the toolkit is practically non-operational. With the change here, we let the toolkit do toolkit-ish job, and only get test doubles for getPluginId() (because that one would be returning null in PHPUnit, since we disable the toolkit's original constructor) and for save() as a precaution to avoid that test changes are actually written back to the test image (plus it would fail when invoking Image::chmod()). We need that change because otherwise the test for width and height getters would not be possible (before, these getters would return the value of the properties on the Image class, but now we removed those properties, and we need to have the toolkit respond to the request 'measuring' the actual test image).

mondrake’s picture

Issue summary: View changes

Re. issue summary update - Image and ImageFactory constructors would very well accept NULL as $source even currently, just it was not documented. What we do here is documenting that, and forcing 'processInfo' call in the Image constructor if a $source is specified (besides that it makes sense, this is also needed for PHPUnit tests). Updated in issue summary.

Status: Needs review » Needs work

The last submitted patch, 18: 2196067-remove_hw-18.patch, failed testing.

mondrake’s picture

Status: Needs work » Needs review

18: 2196067-remove_hw-18.patch queued for re-testing.

Status: Needs review » Needs work

The last submitted patch, 18: 2196067-remove_hw-18.patch, failed testing.

mondrake’s picture

#20 failed because of #2216701: Random test failure in ToolbarAdminMenuTest, #22 no clue :(

mondrake’s picture

Status: Needs work » Needs review

18: 2196067-remove_hw-18.patch queued for re-testing.

Status: Needs review » Needs work

The last submitted patch, 18: 2196067-remove_hw-18.patch, failed testing.

mondrake’s picture

Issue tags: +Random test failure

Looks like we need to wait for

#2216701: Random test failure in ToolbarAdminMenuTest and
#2216909: Random test failure in ConfigTranslationUiTest

Not sure about the tag, please just remove if not relevant.

EDIT - #2216909: Random test failure in ConfigTranslationUiTest landed, retrying-

mondrake’s picture

Status: Needs work » Needs review

18: 2196067-remove_hw-18.patch queued for re-testing.

mondrake’s picture

Issue tags: -Random test failure

OK, back to green.

fietserwin’s picture

Status: Needs review » Needs work
Issue tags: +Random test failure

Sorry, I did not read the patch correctly. So my remark was a bit off and thus too vague for you:

+++ b/core/tests/Drupal/Tests/Core/Image/ImageTest.php
@@ -65,15 +55,19 @@ protected function setUp() {
+    if (!empty($stubs)) {
+      $stubs += array('getPluginId', 'save');
+    }
+    else {
+      $stubs = array('getPluginId', 'save');
     }
     return $mock_builder

Because we know that stubs is an array, the single line
$stubs += array('getPluginId', 'save');
will work both when stubs is an empty array and when it is not an empty array. So replace the whole if-else with this single line (from the if branch).

mondrake’s picture

Status: Needs work » Needs review
Issue tags: -Random test failure
StatusFileSize
new745 bytes
new25.51 KB

#29 - Indeed :) Thanks

fietserwin’s picture

Status: Needs review » Reviewed & tested by the community

Thanks.

mondrake’s picture

Change record to be updated after commit: https://drupal.org/node/2084547

catch’s picture

Status: Reviewed & tested by the community » Needs work
  1. +++ b/core/lib/Drupal/Core/Image/Image.php
    @@ -85,14 +71,18 @@ class Image implements ImageInterface {
    +   * @param string|NULL $source
    

    Why not empty string instead of string|NULL?

  2. +++ b/core/lib/Drupal/Core/Image/ImageFactory.php
    @@ -53,19 +53,49 @@ public function setToolkitId($toolkit_id) {
    +  protected function resolveToolkitId($toolkit_id = NULL) {
    

    $this->toolkitId is never set if the $toolkit_parameter is set? If that's by design I think it could use a comment.

mondrake’s picture

Status: Needs work » Needs review
StatusFileSize
new3.4 KB
new25.56 KB

Thanks @catch.

#34.1 - made change, I hope I understood the direction :/

#34.2 - moved the initial setting of $this->toolkitId to the constructor, which makes resolveToolkitId() no longer necessary. Also added to the docblock of ::get() some comments on the ways to instantiate Image objects with alternative toolkits.

Status: Needs review » Needs work

The last submitted patch, 35: 2196067-remove_hw-35.patch, failed testing.

fietserwin’s picture

+++ b/core/lib/Drupal/Core/Image/ImageFactory.php
@@ -59,43 +60,33 @@ public function setToolkitId($toolkit_id) {
   public function get($source, $toolkit_id = NULL) {
-    $toolkit_id = $this->resolveToolkitId($toolkit_id);

public function get($source, $toolkit_id = '') {

#34.2: the way that #35 solves this is better, as getToolkitId() does not initialize the value,it just returns it. So it should indeed be set in the constructor.

I am looking into the test failure, but as that also happens in #2217783: Remove $extension and $mimeType from Image, use image_type_to_xxx function in the getters instead I don't think it is related to this change.

mondrake’s picture

#37 - thanks, there are testbot failures at the moment I understand, need to wait for them to be solved

fietserwin’s picture

Locally the test passes. Though I did get an "PHP Fatal error: Allowed memory size of 134217728 bytes exhausted (tried to allocate 1130497 bytes) in ...\core\includes\common.inc on line 3917" While browsing to the test page. I think that rendering can be done more memory efficient, but that's something else.

@mondrake: can you make the little change from #37 and set to NR again?

mondrake’s picture

Status: Needs work » Needs review
StatusFileSize
new659 bytes
new25.58 KB

Done.

fietserwin’s picture

Status: Needs review » Needs work

On a last review I found this tricky bug (already introduced in the parent issue):

+++ b/core/modules/file/lib/Drupal/file/Tests/ValidatorTest.php
@@ -79,7 +79,7 @@ function testFileValidateImageResolution() {
+    if ($this->container->get('image.toolkit.manager')->getDefaultToolkitId()) {
       // Copy the image so that the original doesn't get resized.

All image objects that get created will now get a toolkit assigned based on the toolkitId property of the ImageFactory. This means that code outside the image system may no longer call getDefaultToolkitId() on the toolkit manager, because that may not be the image toolkit in use! So

  • ALL usages of getDefaultToolkitId() outside the image system should use getToolkitId() on ImageFactory instead. This method is only called in this test, so no real harm is done here, but I propose to change it anyway as test should also document how things are to be used/queried.
  • ALL usages of getDefaultToolkit() outside the image system should use getToolkit() on an image itself, if available, or use createInstance() and pass in the id from getToolkitId() from ImageFactory. This method is called in file.module and image.install. For completeness (best practices, documentation) and robustness, I would change the latter as well, although at this moment, I can't come up with a scenario where its usage might do any harm. The usage in file.module is easy to solve as there is already an image object.

If we don't do so, advanced scenario's in contrib, where e.g. toolkits are switched based on image field instance or whatever use case one can come up with, might fail.

This error was already introduced in the parent issue, but this issue allows us to solve it, as it adds a getToolkitId() method on Image Factory. Sometimes plans do come together...

mondrake’s picture

Status: Needs work » Needs review
StatusFileSize
new797 bytes
new26.35 KB

Re #41

1 - ValidatorTest - that if() is checking if a default toolkit is available before an image is loaded a few lines below. So we cannot get the toolkit from the image yet: there is no image... A few more lines of code below, there's an else with a TODO for the case no toolkit is available. We need to check existence of a default toolkit directly from the toolkit manager then - or refactor entirely the test which is not in scope here. Note - before the parent issue was committed, that line was if ($this->container->has('image.toolkit')) { which had the same concept as the line as gets modified by this patch - that 'if' would have failed when no toolkit was available.

2 - file.module - good catch. Corrected here.

3 - image.install - here we need an instance of the default image toolkit to be able to invoke its getRequirements() method to build the Status Report. We do not need to load an image arbitrarily for that, so it is correct we get this toollkit instance from the toolkit manager directly.

fietserwin’s picture

IMO the validator test can and should use:

     if ($this->container->get('image.factory)->getToolkitId()) {

As that one returns exactly the same value in a set-up where the default toolkit is used (and thus also a value that evaluates to false when no toolkit is available). IMO this is better as toolkit becomes more and more a thing on the background. Image and ImageFactory are the classes that can be used by the rest of the system. Imagetoolkit and ImageToolkitManager should be avoided whenever possible. This would make the test reusable for other toolkits, although they are not the subject of the test.

Similarly image.install can use:

  $toolkit = \Drupal::service('image.toolkit.manager')->createInstance(\Drupal::service('image.factory')->getToolkitId());

But I agree that is too far off for this issue.

mondrake’s picture

StatusFileSize
new808 bytes
new26.34 KB

OK

fietserwin’s picture

Status: Needs review » Reviewed & tested by the community

Great, thanks.

claudiu.cristea’s picture

Status: Reviewed & tested by the community » Needs work
  1. +++ b/core/lib/Drupal/Core/Image/Image.php
    @@ -86,13 +72,17 @@ class Image implements ImageInterface {
    +   *   The path to an image file, or an empty string to construct the object
    +   *   with no image source.
    ...
       public function __construct($source, ImageToolkitInterface $toolkit) {
    

    No. Empty string it's still a string, it's still "something". We should change the constructor interface and make $source optional defaulting to NULL.

  2. +++ b/core/lib/Drupal/Core/Image/ImageFactory.php
    @@ -53,19 +54,39 @@ public function setToolkitId($toolkit_id) {
    +   *   The path to an image file, or an empty string to construct the object
    +   *   with no image source.
    

    Same here. $source should be optional, defaulting to NULL. This is the common pattern in PHP to say "it has no $source".

  3. +++ b/core/lib/Drupal/Core/Image/ImageFactory.php
    @@ -53,19 +54,39 @@ public function setToolkitId($toolkit_id) {
    +   * @param string $toolkit_id
    +   *   (Optional) The image toolkit ID to use for this image.
    ...
    +  public function get($source, $toolkit_id = '') {
    

    Same here. Don't use empty string to denote "nothing". Use NULL instead.

  4. +++ b/core/lib/Drupal/Core/Image/ImageInterface.php
    @@ -37,42 +37,22 @@ public function isExisting();
    +   *   The height of the image, or 0 if the image is invalid.
    ...
    +   *   The width of the image, or 0 if the image is invalid.
    

    We should return NULL for no width|height. That would be conceptually correct.

  5. +++ b/core/lib/Drupal/Core/ImageToolkit/ImageToolkitInterface.php
    @@ -193,11 +190,9 @@ public function scaleAndCrop(ImageInterface $image, $width, $height);
    +   * @return array|FALSE
    

    Use false with lowercase. See https://drupal.org/coding-standards/docs#types.

  6. +++ b/core/lib/Drupal/Core/ImageToolkit/ImageToolkitInterface.php
    @@ -206,6 +201,28 @@ public function scaleAndCrop(ImageInterface $image, $width, $height);
    +   * @return int
    +   *   The height of the image, or 0 if the image is invalid.
    ...
    +   * @return int
    +   *   The width of the image, or 0 if the image is invalid.
    

    Again, let's fix this bug. I know it was inherited.

  7. +++ b/core/modules/system/lib/Drupal/system/Plugin/ImageToolkit/GDToolkit.php
    @@ -367,6 +356,20 @@ public function createTmp($type, $width, $height) {
    +  public function getWidth(ImageInterface $image) {
    +    return $this->getResource() ? imagesx($this->getResource()) : 0;
    +  }
    ...
    +  public function getHeight(ImageInterface $image) {
    +    return $this->getResource() ? imagesy($this->getResource()) : 0;
    +  }
    

    NULL, not 0.

  8. +++ b/core/modules/system/tests/modules/image_test/lib/Drupal/image_test/Plugin/ImageToolkit/TestToolkit.php
    @@ -21,6 +21,20 @@
    +  protected $width = 0;
    ...
    +  protected $height = 0;
    

    Am I missing something? We removed width & height from image but we added back only to TestToolkit? And why here? Why we don't add those properties directly to ImageToolkitBase so that all implementations will inherit them?

    And again, let's initialize them to NULL.

fietserwin’s picture

All the empty string versus NULL is from @catch's remark in #34. To say that this is the common pattern for PHP is too strong. PHP is notoriously bad in handling edge cases like the absence of a value (too many ways, empty versus !isset etc.). if I can see any tendency, it is towards working more type strictly, thus specify 1 type only and have an empty value within that type. int and string do have such a value and as 0 is indeed not a valid value for a width or height it is usable.

RE #46.8: We removed width and height from Image, not toolkit. GD doesn't need to store the width and height in properties as it has imagesx() and imagesy(). OTOH, IM will need to keep track of width and height as it has no resource like GD that keeps track of this info.. So, these properties do not belong to a base object as they are really implementation specific.

For me, this issue remains RTBC, except perhaps 5, but that can be done on committing.

claudiu.cristea’s picture

Well, this time I have to disagree with @catch. NULL means (literally) "nothing" and this is the case here. PHP is just flexible but nothing stops us to use it right. See comment #5: https://drupal.org/comment/7566547#comment-7566547.

mondrake’s picture

Assigned: Unassigned » mondrake
Status: Needs work » Reviewed & tested by the community

Moving to RTBC only to see if we can have @catch feedback here before proceeding in any sense. My personal preference is to proceed with NULL on all points of #46 1 to 7, but before doing so I'd like signoff. #46.8 has been clarified I believe.

EDIT

The current implementation of the ::save() method in ImageInterface is using NULL:

  /**
   * Closes the image and saves the changes to a file.
   *
   * @param string|null $destination
   *   (optional) Destination path where the image should be saved. If it is empty
   *   the original image file will be overwritten.
   *
   * @return bool
   *   TRUE on success, FALSE on failure.
   *
   * @see \Drupal\Core\ImageToolkit\ImageToolkitInterface::save()
   */
  public function save($destination = NULL);

Status: Reviewed & tested by the community » Needs work

The last submitted patch, 44: 2196067-remove_hw-44.patch, failed testing.

mondrake’s picture

StatusFileSize
new26.19 KB
new2.83 KB

Needed a reroll after #2217783: Remove $extension and $mimeType from Image, use image_type_to_xxx function in the getters instead got committed. Just merge conflicts resolved, no change vs #44.

mondrake’s picture

Status: Needs work » Needs review
fietserwin’s picture

Status: Needs review » Reviewed & tested by the community

Setting to RTBC as per #49 and a review of the reroll. The article #48 refers to is not very explicit on the use of NULL, it also tells us to return 1 type only, or to throw an exception. So IMO an "empty" value within a type also does.

catch’s picture

Status: Reviewed & tested by the community » Needs work
+++ b/core/lib/Drupal/Core/ImageToolkit/ImageToolkitInterface.php
@@ -193,11 +190,9 @@ public function scaleAndCrop(ImageInterface $image, $width, $height);
+   * @return array|FALSE

No for return values, if you're returning an array, you should always return an array. Otherwise you constantly have to type check for array comparisons/foreach etc. I don't mind much about int/string vs. null, but especially arrays it is horrible to return FALSE.

Previous example where we changed from FALSE to array: #1927884: Always return an array from field_get_items().

mondrake’s picture

Assigned: mondrake » Unassigned
Status: Needs work » Needs review
StatusFileSize
new11.75 KB
new29.4 KB

OK, this covers #46 - 1, 2, 3, 4, 6, 7.

#46.5 and #54 - I finally went for an empty array instead of FALSE when getInfo cannot process the source file. This was inherited here.

Status: Needs review » Needs work

The last submitted patch, 55: 2196067-remove_hw-55.patch, failed testing.

mondrake’s picture

Status: Needs work » Needs review
StatusFileSize
new1.16 KB
new30.31 KB

Fix for PHPUnit test.

fietserwin’s picture

Status: Needs review » Reviewed & tested by the community

I have to (partially) disagree with @catch. The article from Larry Garfield teaches us: throw an exception or return null when the array is actually a struct and not a collection.

So returning false indeed is wrong, as is (IMO) returning an empty struct. But this can be handled when we really solve working with blank canvases #2063373: Cannot save image created from scratch. Then we'll see if we better throw an error.

catch’s picture

Status: Reviewed & tested by the community » Fixed

Yes in that case an exception would be better but OK with working in the followup. Let's unblock the other patches. Committed/pushed to 8.x, thanks!

  • Commit 5e642cf on 8.x by catch:
    Issue #2196067 by mondrake, fietserwin: Remove setWidth and setHeight...
mondrake’s picture

Change record updated, thanks @fietserwin:

https://drupal.org/node/2084547/revisions/view/7110713/7144009

Status: Fixed » Closed (fixed)

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