Change record status: 
Project: 
Description: 

These change affects developers of image toolkit and image toolkit operations plugins only. Image style effects are not impacted, as the API surface that ImageStyleEffect plugins consume is not touched.

The architecture of the image processing toolkits has changed. All the image related data is now stored in an implementation of ImageInterface that is provided by each toolkit. Every state property is removed from ImageToolkit and ImageToolkitOperation plugins, so that they can only be instantiated once, and pass the ImageInterface object with its data to their methods.

In practice:

  • the ImageFactory receives a request to provide an image
  • it determines what is the toolkit to be used
  • the toolkit informs the factory about the image object implementing ImageInterface that should be used in connection with the toolkit
  • the factory only creates an instance of that image object
  • ImageToolkit and ImageToolkitOperation plugin managers create singletons of each plugin needed when needed
  • the image object is passed to the singletons' methods

How to convert an ImageToolkit plugin to stateless

  1. Add to the toolkit plugin attribute the $imageClass parameter, referring to a class implementing an ImageInterface object. For example, taking from GDToolkit:
    #[ImageToolkit(
      id: "gd",
      title: new TranslatableMarkup("GD2 image manipulation toolkit"),
      imageClass: GdImageWrapper::class,
    )]
    
  2. Move any state property from the toolkit plugin to the class implementing ImageInterface
  3. Indicate that the toolkit is stateless, adding to the toolkit code the appropriate override of the $isStateful property:
      // phpcs:disable
      /**
       * {@inheritdoc}
       */
      public bool $isStateful {
        get => FALSE;
      }
      // phpcs:enable
    
  4. Change the methods implementing the ImageToolkitInterface API so that they receive and handle the ImageInterface object:
    -  public function getHeight() {
    +  public function getHeight($image = NULL) { 
    

Deprecations

Existing toolkits and toolkit operations still work under a backwards compatibility (BC) layer, that will be retained until they are converted to stateless. A number of methods and properties have been deprecated:

  • ImageInterface::getToolkit() --> Use ::toolkit() on stateless toolkits instead.
  • ImageToolkitInterface::getSource() --> Get image source path via ImageInterface::getSource() instead.
  • ImageToolkitInterface::setSource() --> Set image source path via ImageInterface::setSource() instead.
  • ImageToolkitBase::$isClone --> Only introduced to support backwards compatibility; there is no replacement.
  • ImageToolkitBase::$isStateful --> Only introduced to support backwards compatibility; there is no replacement.
  • ImageToolkitBase::$backfillImage --> Only introduced to support backwards compatibility; there is no replacement.
  • ImageToolkitBase::$source --> Access image source path from the ImageInterface object directly.
  • ImageToolkitOperationInterface::setToolkit() --> Stateless toolkits must not be injected to the toolkit operation.
  • ImageToolkitOperationBase::$needsToolkitInjection --> Only introduced to support backwards compatibility; there is no replacement.
  • ImageToolkitOperationBase::$toolkit --> Stateless toolkits must not be injected to the toolkit operation.
  • ImageToolkitOperationBase::getToolkit() --> Stateless toolkits must not be injected to the toolkit operation.
  • GDToolkit::$image --> Access GdImageWrapper::$gdImage through its getter/setter instead.
  • GDToolkit::$type --> Access GdImageWrapper::$type through its getter/setter instead.
  • GDToolkit::$preLoadInfo --> Access GdImageWrapper::$preLoadInfo through its getter/setter instead.
  • GDToolkit::setImage() --> Use GdImageWrapper::setGdImageObject() instead.
  • GDToolkit::getImage() --> Use GdImageWrapper::getGdImageObject() instead.
  • GDToolkit::setType() --> Use GdImageWrapper::setType() instead.
  • GDToolkit::getType() --> Use GdImageWrapper::getType() instead.
Impacts: 
Module developers