Problem/Motivation

FocalPointEffectBase::create() passes $container->get('request_stack')->getCurrentRequest() to the constructor, but the constructor has a required, non-nullable Request $request argument. getCurrentRequest() returns NULL when there is no current request.

Core creates every effect plugin of an image style when it needs the derivative extension (ImageStyle::buildUri() → addExtension() → getDerivativeExtension()). So any image style with a Focal Point effect throws a TypeError as soon as it is used while there is no current request.

We hit this on Drupal 11.4.9 with Focal Point 2.1.3 under Drush. A media entity was saved in a shutdown function, and the WebP module's entity update hook called ImageStyle::buildUri() for all image styles:

Uncaught exception thrown in shutdown function.
TypeError: Drupal\focal_point\FocalPointEffectBase::__construct(): Argument #8 ($request) must be of type Symfony\Component\HttpFoundation\Request, null given
#0 focal_point/src/FocalPointEffectBase.php(90): FocalPointEffectBase->__construct()
#1 core/lib/Drupal/Core/Plugin/Factory/ContainerFactory.php(21): FocalPointEffectBase::create()
...
#7 core/modules/image/src/Entity/ImageStyle.php(369): LazyPluginCollection->getIterator()
#8 core/modules/image/src/Entity/ImageStyle.php(531): ImageStyle->getDerivativeExtension()
#9 core/modules/image/src/Entity/ImageStyle.php(210): ImageStyle->addExtension()
#10 webp/webp.module(116): ImageStyle->buildUri()
#11 webp/webp.module(42): webp_flush_webp_derivatives()
#12 [internal function]: webp_entity_update()
...
#26 [internal function]: _drupal_shutdown_function()

We did not see it in the same script on Drupal 11.3.3, but the steps below fail on 11.3 too, so it is not specific to 11.4. Drupal 11.4 only makes it easy to hit under Drush.

Steps to reproduce

  1. Install Focal Point 2.1.x and create an image style with the "Focal Point Scale and Crop" effect.
  2. Run, with no current request:
    drush php:eval 'while (\Drupal::requestStack()->getCurrentRequest()) { \Drupal::requestStack()->pop(); } \Drupal\image\Entity\ImageStyle::load("STYLE_ID")->buildUri("public://example.png");'
  3. See the TypeError above.

Proposed resolution

Make the argument nullable in FocalPointEffectBase::__construct() (?Request $request = NULL), and use the null-safe operator in getPreviewValue(), which is the only place that reads the request. The preview value is only needed in a web request, so nothing changes there. The patch also adds two unit tests: creating an effect without a request, and reading the preview value from a request.

API changes

  • The $request argument of FocalPointEffectBase::__construct() is now nullable (?Request $request = NULL), and the public $request property can be NULL. Existing callers are not affected.

Release notes snippet

  • Fixed a TypeError when an image style with a Focal Point effect is used without a current request (Drush, cron).

Comments

mutasim al-shoura created an issue. See original summary.

mutasim al-shoura’s picture