Problem

This is a follow-up from #1069140: Requirements should be provided by image toolkit, where comment #1069140-35: Requirements should be provided by image toolkit noted that

There's an interesting crossover here between the requirements method and isAvailable method

.

To decouple the requirements checking from that "crossover", it was decided to create a follow-up issue, this issue.

It was noted that isAvailable():
- Is not cached, so called over and over again for each instantiation of the selected toolkit for ALL toolkits.
- Becomes a bit superfluous when requirements checking per toolkit has landed.
- Current way of returning false when no available toolkit exists, may lead to WSOD (though itmight also be a "recoverable fatal".

Proposed resolution

Remove isAvailable() all together.

This might lead to errors in a later stage, but only if requirements checking is ignored and the toolkit is indeed not available. Moreover, these errors probably occur on image derivative generation and thus won't result in a WSOD, "just" a missing image on a page. Image uploading and subsequent resizing due to field settings, is probably the exception here, as the image processing is done during page generation.

Remaining tasks

- Agree on proposed resolution.
- Write patch after the originating issue has landed.

User interface changes

API changes

ImageToolkitInterface will be changed, this should be documented in the same change notification as the originating issue.

Comments

claudiu.cristea’s picture

Status: Postponed » Active

Few comments. This method is used only once, in ImageToolkitManager::getAvailableToolkits(), to filter out broken toolkits:

$ grep -nr --exclude-dir=core/vendor  isAvailable core
core/lib/Drupal/Core/ImageToolkit/ImageToolkitInterface.php:196:  public static function isAvailable();
core/lib/Drupal/Core/ImageToolkit/ImageToolkitManager.php:87:      if (call_user_func($definition['class'] . '::isAvailable')) {
core/modules/system/lib/Drupal/system/Plugin/ImageToolkit/GDToolkit.php:299:  public static function isAvailable() {
core/modules/system/tests/modules/image_test/lib/Drupal/image_test/Plugin/ImageToolkit/BrokenToolkit.php:23:  public static function isAvailable() {
core/modules/system/tests/modules/image_test/lib/Drupal/image_test/Plugin/ImageToolkit/TestToolkit.php:136:  public static function isAvailable() {

The interesting part here is, IMO, how the system is picking up the active toolkit. Right now Drupal is:

  1. Checking the toolkit stored either by install process, either by site admin in system.image.toolkit and use it if it's valid.
  2. If is not valid, it picks up the first, arbitrary valid toolkit.

This behavior was inherited from the legacy Drupal 7 functions: image_get_toolkit() and image_get_available_toolkits().

Here we have a problem. I don't think that the system should assign an arbitrary toolkit. This would hide the failure. I think the site admin should be warned that the configured toolkit is either uninstalled (if the provider module is no more enabled), either broken (something occurred on the platform — e.g. GD2 extension was uninstalled). Course this check should be performed also when the admin submits the toolkit form in admin/config/media/image-toolkit.

What I think now is that this issue must be more an issue about getDefaultToolkit() than isAvailable(). The functionality of isAvailable() should be triggered only once, against the config stored toolkit and not all toolkits. I really don't know if this should be cached or not. At least for GD toolkit it doesn't seems an expensive operation (checking a function existence) but, in terms of performance, we already gained by not checking each toolkit. Probably we'll need to check each toolkit availability in admin/config/media/image-toolkit but still display all toolkits together with a warning message attached to broken ones — so that site admin is able to see the "whole picture". So, the active (configured) toolkit validity check may occur:

  1. On each instantiation with exception throw (plus form validation and critical requirements). The most expensive (but less expensive than the current implementation).
  2. On each instantiation but with cached value of availability (plus form validation and critical requirements). Less expensive but needs a cache invalidation mechanism and opportunity (cron?).
  3. Without any check at runtime, only form validation and critical requirements. The most cheap solution.

A last note: While per-toolkit requirements is returning a classical hook_requirements() array and not other availability information, how we'll remove isAvailable()? Regardless of the solution we follow, we still need to check the availability (e.g. toolkit form validation, when setting the "is available" cache, in image_requirements(), etc).

fietserwin’s picture

This would hide the failure. I think the site admin should be warned that the configured toolkit is either uninstalled ..., either broken

- Correct: fail early, fail clear.

Probably we'll need to check each toolkit availability in admin/config/media/image-toolkit but still display all toolkits together

- We must show all toolkits, as, e.g. IM needs a path to the convert binary before it can be considered to be available. And this path can only be entered, on the admin/config/media/image-toolkit screen, once that toolkit has been chosen and its configuration form fields become visible.

- What is the problem at runtime? A comparison with other sub systems: E.g., there is no check either if the configured database is available and of the correct type. Drupal just fails if it is incorrectly configured. There is no check if the stream wrappers (temporary://, private://, and public://) are correctly configured. So why should we check if a toolkit is correctly configured time after time (for IM it needs an is_executable() call, thus file system access).

Regardless of the solution we follow, we still need to check the availability

- Why: consider each registered toolkit as being available. Form validation means we can directly present messages to the admin, so a toolkit could either implement its own form validation or "abuse" the requirements() return values for that. I'm not sure if the toolkit needs to hook into the form or that the form needs a hook into the toolkit (the latter would probably indeed require a method on the interface, but for now I prefer the former).

- Note: because the algorithm to get the default toolkit is questionable, I don't want the patch of the originating issue to follow that algorithm... Especially as the algorithm is swappable and will probably be changed in this issue, it is not good to base requirements() on having to have knowledge of that algorithm.

mondrake’s picture

My opinion: let's wait till #2111263: Toolkit setup form displays settings for multiple toolkits gets committed, then go with a single patch to address both this issue and #1069140: Requirements should be provided by image toolkit, built on top of patch in #1069140-50: Requirements should be provided by image toolkit. We can also adjust the Imagemagick conversion in the sandbox at the same time so to have two toolkits to play with.

Based on all the discussion, it seems to me that the key player in terms of checking the requirements would be the toolkit setup form, and a specific toolkit being set as default only on its requirements pass. Then the status report would be more or less 'subsidiary' i.e. a reference to check if something suddenly stops working - and that would happen only if something changed in the underlying setup (GD extension removed, path to convert changed, etc.).

Then I would go with

Without any check at runtime, only form validation and critical requirements. The most cheap solution.

from #1: effects already fail with a watchdog entry if the toolkit call fails.

claudiu.cristea’s picture

Why everybody want to mix #1069140: Requirements should be provided by image toolkit with other issues, like this one? #1069140: Requirements should be provided by image toolkit is a D7 issue but moved to D8 according to the rule that an issue must be fixed first in the development release and after that back-ported. That one has a specific scope: Stop hardcoding requirements from GD, let the active toolkit scream! If, hypothetically, this issue will never be committed, #1069140: Requirements should be provided by image toolkit is still a valid, standalone issue, just good to get in D8 and back-ported to D7. Because is doing only that simple thing: passes the requirements generation from image to toolkit. The only "sin" of #1069140: Requirements should be provided by image toolkit is that is using that damn getDefaultToolkit() to get the active toolkit. But that's how we are selecting now the toolkit. So that is ready to go as it is because D7 is waiting for it too.

Here, in this issue, is the place were we need to discuss and fix getDefaultToolkit(), along with others. And if #1069140: Requirements should be provided by image toolkit is committed first we just need to touch again image_requirements() and use maybe the config value instead that method. But that change is not related to how requirements are built but is related with this issue. That's why, even touching again image.install, that change belong to this issue.

claudiu.cristea’s picture

Issue summary: View changes

added that we should agree on solution

mondrake’s picture

Issue summary: View changes
Status: Active » Needs review
Parent issue: » #1069140: Requirements should be provided by image toolkit
StatusFileSize
new12.81 KB
new18.99 KB

Here's a proposal, built on top of #2111263: Toolkit setup form displays settings for multiple toolkits and of #1069140: Requirements should be provided by image toolkit.

- drop the isAvailable() method from the toolkit.
- adds to the requirements() method a $form_state parameter, being the form_state of the Image toolkit setup form, to allow for bypassing stored config values while the toolkit is being setup (e.g. to change the path in ImageMagick).
- drop the getAvailableToolkits() method from the toolkit manager. Just use getDefinitions() instead, which bears all the toolkit plugins found (regardless if valid or not).
- getDefaultToolkit() in the manager will only return the configured toolkit. Will fail with an error message if no toolkit configured or toolkit is no longer existing (e.g. uninstalled).
- most of the checking is done via the toolkit setup form, at form validation. If this passes, we assume that the toolkit is configured properly, and make no runtime checks.
- the status report will report any error occurred 'outside' of Drupal toolkit configuration (e.g. change in PHP GD library, change in ImageMagick path).

do-not-test is diff against #2111263: Toolkit setup form displays settings for multiple toolkits and of #1069140: Requirements should be provided by image toolkit, the other is against HEAD.

Status: Needs review » Needs work

The last submitted patch, 5: 2122605-5.patch, failed testing.

fietserwin’s picture

  1. +++ b/core/lib/Drupal/Core/ImageToolkit/ImageToolkitManager.php
    @@ -52,43 +52,14 @@ public function __construct(\Traversable $namespaces, CacheBackendInterface $cac
    +    if (empty($toolkit_id) || !isset($toolkits[$toolkit_id]) || !class_exists($toolkits[$toolkit_id]['class'])) {
    +      drupal_set_message(t('The Image toolkit is missing or not configured properly. Visit the <a href="@url">Image toolkit</a> configuration page to correct this.', array('@url' => url('admin/config/media/image-toolkit'))), 'error');
    +      return FALSE;
    

    - Placing all of "Image toolkit configuration page" within the anchor tags looks more logical to me.
    - replace the return FALSE by throwing an exception to fail more clearly. (Though I do not know the current consensus in Drupal regarding throwing exceptions), but returning FALSE will subsequently fail with a "Fatal error: Call to a member function ... on a non-object"." Throwing an exception with the given message makes the drupal_set_message redundant and shows more clearly what went wrong.

  2. +++ b/core/modules/system/lib/Drupal/system/Form/ImageToolkitForm.php
    @@ -108,6 +108,47 @@ public function processToolkitDetails($form, $form_state) {
    +    if (!empty($requirements)) {
    

    Not necessary to check for empty, a foreach over an empty array is perfectly possible and will yield the same result (and requirements() must return an (possibly empty) array).

mondrake’s picture

Status: Needs work » Needs review
StatusFileSize
new19.82 KB
new4.74 KB

Placing all of "Image toolkit configuration page" within the anchor tags

done

Not necessary to check for empty...

done

replace the return FALSE by throwing an exception to fail more clearly

there are only two cases when getDefaultToolkit is used. One is in image.install, and if a FALSE value is returned, then it is managed. The other is more complex as it is connected to the instantiation of the image.factory service: here the default toolkit is looked for and instantiated as well, then passed on to the Image object. Not sure what will happen if we just throw an exception here. For the time being I just allowed the image.factory constructor to accept a FALSE value if no default toolkit is found. To me it seems we may need to sort this out with try/exception/catch in #2105863: [meta] Images, toolkits and operations in the interaction between Image and Toolkit - i.e. let an Image be created with no toolkit and catch the exceptions that Image will get into by calling a missing toolkit.

mondrake’s picture

BTW - I adjusted the Imagemagick conversion in the sandbox, to work with this patch. You can play with that to test if you wish.

fietserwin’s picture

Thanks for adapting the patch

  1. +++ b/core/lib/Drupal/Core/Image/ImageFactory.php
    @@ -24,11 +24,14 @@ class ImageFactory {
    +  public function __construct($toolkit) {
    

    Still not sure about this. Can an image exist without Toolkit? Apart from the reasons why one would like to be able to do so (an (Drupal) Image object is there to perform some manipulations on it, not for other reasons), looking at the code, almost every method of Image calls a method on the toolkit property (albeit indirectly) and thus will fail with a fatal.

    The only methods of image that won't fail (if toolkit is not a toolkit object) are:
    - setWidth/setHeight: there existence is an error in itself: width and height are adapted by operations from the toolkit, not by setting a property (I should create an issue for that).
    - setResource/hasResource: GD specific, will only be called by the GD toolkit, thus if the toolkit is a toolkit after all.
    - setSource/getSource: nice, but if you create an image only to set and retrieve a source ...
    - chmod: there is a todo that this in the wrong place and it doesn't use $this at all...

    So I would say: keep the type hinting and let's fail clearly with an exception.

    Note: image_install could catch the exception and still do the same as when checking for FALSE.

    Another option is to let ImageFactory::get() fail when toolkit is not a proper toolkit object. But then we would loose the type hinting again, unless we return null instead of false (which in itself is already more logical).

  2. +++ b/core/modules/system/lib/Drupal/system/Form/ImageToolkitForm.php
    @@ -65,34 +67,88 @@ public function getFormId() {
    +        $message .= (' - ' . $requirement['value']);
    

    brackets not necessary

  3. +++ b/core/modules/system/lib/Drupal/system/Form/ImageToolkitForm.php
    @@ -65,34 +67,88 @@ public function getFormId() {
    +        $message .= (' - ' . $requirement['description']);
    

    idem

  4. +++ b/core/modules/system/lib/Drupal/system/Form/ImageToolkitForm.php
    @@ -65,34 +67,88 @@ public function getFormId() {
    +        \Drupal::formBuilder()->setErrorByName('image_toolkit', $this->t('Selected toolkit %toolkit_id is invalid.', array('%toolkit_id' => $form_state['values']['image_toolkit'])));
    

    Does the toolkit have a name that we can display to the user? (and is easily accessible here)

mondrake’s picture

StatusFileSize
new20.77 KB
new5.86 KB

brackets not necessary

done

Does the toolkit have a name that we can display to the user?

done

Can an image exist without Toolkit?

I think not. For the time being I changed ImageFactory::get() to return NULL if no toolkit is selected. There are a few points here:

  1. More general. I just recently realised that the ImageToolkit is instantiated at the ImageFactory level, then the same instance is passed on to any Image being created. I think this is wrong when we look at #2103621: Move GD logic from ImageInterface to toolkit, tie toolkit instance to Image instance, toolkits should no longer be instantiated separately: if we move the resource object (in GD) and the ops array (in ImageMagick) to the toolkit, then each image should isolate its own instance of the toolkit. Suppose we 'get' two images in parallel, we cannot mix the resource/ops of each. I'd say this one needs to be tackled more in #2103621: Move GD logic from ImageInterface to toolkit, tie toolkit instance to Image instance, toolkits should no longer be instantiated separately.
  2. If we accept that getDefaultToolkit can return NULL, then we cannot typehint the __construct in ImageFactory, otherwise unit tests will fail (NULL is throwing a recoverable fatal). setToolkit() we can, as we assume that the toolkit object will be checked before invoking it.
  3. If we accept that ImageFactory::get() can return NULL if no toolkit is set (which I believe it's sane), then currently in the codebase there are no checks that the returned Image object is valid. This leads to WSOD, e.g. in the image style preview. If we agree this is the way forward, then we need to add this checks (not done here).
fietserwin’s picture

Great, patch looks good now.

11.1) That's why I want this data in Image, which implies:
- that an Image is created by the toolkit
- that A toolkit comes with its own class derived from Image (to rename to ImageBase)

11.2) MY fault, I thought that type hinting allows null (every other language I worked in does it that way). Thus, in practice, returning null turns out to be the same as returning false :(.

11.3) I still think it is not sane to allow images to be created without a working toolkit...
A search for all uses of ImageFactory (and thus Image I think) teaches me that Image is indeed only created:
- for processing (resizing on image upload if max dimensions are set for an image filed, image style handling)
- for testing if a (uploaded) file is an image and if its type is supported. This isSupported handling is (correctly) moved to Toolkit, as the toolkit defines which image types are supported.

So, I think, no toolkit is no image, hence throw an exception.

claudiu.cristea’s picture

I cannot review a "3 issues" combined patch. Can we have also a separate "do not test" patch only for this issue?

  1. +++ b/core/lib/Drupal/Core/ImageToolkit/ImageToolkitManager.php
    @@ -48,47 +48,18 @@ public function __construct(\Traversable $namespaces, CacheBackendInterface $cac
    +      drupal_set_message(t('The Image toolkit is missing or not configured properly. Visit the <a href="@url">Image toolkit configuration page</a> to correct this.', array('@url' => url('admin/config/media/image-toolkit'))), 'error');
    

    We don't want to popup anything here because we cannot anticipate where we'll use this manager method. Retuning NULL should be enough but I think even to throw here an exception instead.

  2. +++ b/core/modules/system/lib/Drupal/system/Form/ImageToolkitForm.php
    @@ -65,34 +67,91 @@ public function getFormId() {
    +  /**
    +   * {@inheritdoc}
    +   *
    +   * Validates the toolkit selection, by checking toolkit requirements.
    +   */
    

    It seems that in code standards we cannot use both {@inheritdoc} and custom docblock content. See {@inheritdoc}.

  3. +++ b/core/lib/Drupal/Core/ImageToolkit/ImageToolkitInterface.php
    @@ -174,12 +174,24 @@ public function save(ImageInterface $image, $destination);
    +   * @param array $form_state
    +   *   (optional) The current form state if the method is invoked from
    +   *   within the Image toolkit setup form. Allows the method to bypass stored
    +   *   config values if the parameters in the form are relevant to check the
    +   *   requirements.
    ...
    +  public function requirements(array &$form_state = array());
    
    +++ b/core/modules/system/lib/Drupal/system/Form/ImageToolkitForm.php
    @@ -65,34 +67,91 @@ public function getFormId() {
    +  public function validateForm(array &$form, array &$form_state) {
    

    I don't like, at all, the idea to mix requirements with form validation. Especially, to send $form_state as argument into requirements(). The form is an UI element while requirements() is most something placed at the model level. I would let each toolkit simply provide its own form validation callback that should be called when validating — as the submit callback is called now. That one has the possibility to call its own requirements but ONLY if he decides that.

  4. +++ b/core/modules/system/lib/Drupal/system/Plugin/ImageToolkit/GDToolkit.php
    @@ -275,14 +275,33 @@ public function createTmp(ImageInterface $image, $width, $height) {
    +    $check = get_extension_funcs('gd');
    +    if (!$check || !in_array('imagegd2', $check)) {
    +      $requirements['image_gd'] = array(
    +        'title' => t('GD Library'),
    +        'value' => t('Not installed'),
    +        'description' => t('The GD library for PHP is missing or outdated. Check the <a href="@url">PHP image documentation</a> for information on how to correct this.', array('@url' => 'http://www.php.net/manual/book.image.php')),
    +        'severity' => REQUIREMENT_ERROR,
    +      );
    +      return $requirements;
    

    Hm... See my final comment.

As generic comment: Even this issue goal seems to be "Drop isAvailable()!", I'm not convinced anymore that we need that removal. I see 3 level of errors here:

  1. No toolkit configured (system.image.toolkit is empty). This one is already treated in #1069140: Requirements should be provided by image toolkit.
  2. The configured toolkit cannot be used at all. That one is handled now by isAvailable() and I think we can live with it. Action to take:
    • Change the severity of the toolkit requirement (image.toolkit) and add a proper description — handled in image_requirements()
    • Validation error in form
  3. The configured toolkit can be used but has limitations/warnings. Requirements already provided in #1069140: Requirements should be provided by image toolkit, plus we need to set specific form validations on each toolkit.
mondrake’s picture

StatusFileSize
new16.03 KB

#13, here's the do not test patch.

mondrake’s picture

StatusFileSize
new7.88 KB
new16.46 KB
new21.47 KB

I don't like, at all, the idea to mix requirements with form validation.

You're right. Changed approach here.

in code standards we cannot use both {@inheritdoc} [...]

Corrected.

Retuning NULL should be enough but I think even to throw here an exception instead.

Not sure how to do that. Can you advise?

To the overall comment. I find having both isAvailable() and requirements() confusing. So I'd prefer if we can drop isAvailable().

fietserwin’s picture

(#15) To the overall comment. I find having both isAvailable() and requirements() confusing. So I'd prefer if we can drop isAvailable().

Agree. isAvailable() does not handle situation 2 from #13. It hides the problem instead of handling it (the way it currently is used). and there is no other factory that does some checking on each instantiation.

(#13.1) We don't want to popup anything here because we cannot anticipate where we'll use this manager method. Retuning NULL should be enough but I think even to throw here an exception instead.

Exceptions:
Can we use an existing exception type?
- Exception
- PluginException

The former is to generic, the latter is also still qute non-descriptive and seems to be some kind of intermediate/base class. So I would go for creating our own type.

Name:
- ImageToolkitException
- Or we could differentiate the different error situations (config key not set, toolkit broken, class not available) and create 3 exception types. As all of them will be extremely rare, I would go for 1 exception type, thus not to differentiate.

Where should this class derive from?
- Exception
- PluginException
- UnknownPluginException

The latter seems to be specific for an incorrect id , so I would go for PluginException.

mondrake’s picture

@fietserwin thanks. New patch tomorrow, with an ImageToolkitException extending PluginException.

mondrake’s picture

StatusFileSize
new22.21 KB
new17.21 KB
new2.49 KB

Here, ImageToolkitManager::getDefaultToolkit() returns null if it the default plugin is not set or missing, and ImageFactory::get() throws a new ImageToolkitException if the toolkit is not set.

mondrake’s picture

Title: is ImagetoolkitInterface::isAvailable() still needed » Remove isAvailable() from ImagetoolkitInterface
fietserwin’s picture

  • +++ b/core/lib/Drupal/Core/Image/ImageFactory.php
    @@ -19,16 +19,19 @@ class ImageFactory {
    +  protected $toolkit = NULL;
    

    Isn't this by default? Anyway, this is more explicit, so perhaps better leave it.

  • +++ b/core/lib/Drupal/Core/Image/ImageFactory.php
    @@ -48,6 +52,8 @@ public function setToolkit(ImageToolkitInterface $toolkit) {
    +   * Throws an ImageToolkitException if the toolkit is not set.
    +   *
    

    @throws

I would throw the exception when getting the toolkit, it is a plugin failure after all. Moreover, it also solves point #13.1; and we retain the type hinting and don't have to complicate the docs by adding |NIULL (and describing it)

mondrake’s picture

Title: Remove isAvailable() from ImagetoolkitInterface » Remove isAvailable() from ImageToolkitInterface
StatusFileSize
new5.11 KB
new16.77 KB
new20.92 KB

#20: OK, here we go. ImageFactory is now back to original. We have to try/catch getDefaultToolkit in image.install to manage invalid default.

Status: Needs review » Needs work

The last submitted patch, 21: 2122605-21.patch, failed testing.

mondrake’s picture

StatusFileSize
new21.62 KB
new17.46 KB
new715 bytes

Hm... #21 fails GD Toolkit unit test as there is no default toolkit set in config in that context, and the new exception is thrown on

  $image_factory = $this->container->get('image.factory')->setToolkit($toolkit);

at get('image.factory'), before the toolkit is reset in setToolkit($toolkit).

In other words, we can not instantiate the ImageFactory at all if there is not a configured toolkit, and we can set a different toolkit for the ImageFactory only if this is already instantiated. This is the effect of moving the exception throwing at the toolkit plugin level instead on ImageFactory::get().

Here I changed the test so to set explicity 'gd' as the default toolkit in config.

mondrake’s picture

Status: Needs work » Needs review
fietserwin’s picture

Ouch. This shows again how tied Image and Toolkit are to each other. IMO, setToolkit() on an already created Image looks ridiculous and dangerous. You can't change toolkit halfway, thus if you only can set it at the start, set it in the constructor. Let's get rid of this method. That would prevent this kind of code and errors.

(Other note: in my vision, the toolkit should be the factory, Doing it that way, would also state very clearly the link between the 2 classes).

mondrake’s picture

#25 no, here we do not change the toolkit to the Image, we change it to the ImageFactory, so that if we get() an image from that factory, it will 'inherit' the toolkit set at that point (OK, in #11.1 we say there's a problem with 'inheriting' that toolkit instead of getting a new instance, but will address that elsewhere). I believe it's valid to provide developers the possibility to manage images with toolkits alternative to the default one; even if core won't use that.

mondrake’s picture

Reroll, after #1069140: Requirements should be provided by image toolkit went in, and with latest patch from #2111263: Toolkit setup form displays settings for multiple toolkits.

This still requires #2111263: Toolkit setup form displays settings for multiple toolkits before being reviewable, so I'll mark it postponed after the test run.

mondrake’s picture

StatusFileSize
new1.45 KB
new22.98 KB
new15.87 KB

Ooops...

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

mondrake’s picture

Status: Needs review » Postponed
mondrake’s picture

Assigned: Unassigned » mondrake
Status: Postponed » Needs work

#2111263: Toolkit setup form displays settings for multiple toolkits landed, so we can reopen this. Needs reroll and re-thinking about how to manage ImageToolkitForm validation.

claudiu.cristea’s picture

Things that should be fixed here:

  1. Fix getDefaultToolkit().
  2. Errors should follow the next precedence:
    • No toolkit configured => system.image.toolkit is empty.
    • Toolkit configured but invalid => isAvailable(): (1) needs validation form error — invalid toolkits cannot be selected as default and (2) proper Status Report message — it might become invalid after selection.
    • Toolkit configured, available but has limitations/warnings. Already fixed.

Didn't have a position now on form validation.

As a conclusion: I think that we should keep isAvailable() as a hard flag, that tells if a toolkit is valid. Basically it's below the bottom line of requirements.

fietserwin’s picture

This is a follow up issue to clean up the API regarding the creation of ImageToolkits. So, I would like to extend the scope of this cleaning a bit to the whole ImageToolkitManager class:

  1. Naming: I had a quick look at some other managers and found that repeating the name of the object in method names, (image)toolkit in our case, is not standard in Drupal. So rename getDefaultToolkit() to getDefault() or even better getConfigured/getSelected/getActive, as, IMO, getDefault actually means get the GD toolkit.
  2. Besides creating the configured toolkit, someone might want to be able to create another available toolkit plugin, so I would like to introduce a new method: get($id).
  3. The manager should create the plugin and not be bothered with “validity” or “availability”. Drupal has a good requirements checking and reporting system, at install time, selection time and via the status report. So the manager should not be bothered with this. This means that the methods getAvailableToolkits() and isAvailable() (from ImageToolkitInterface) can be removed.
  4. Error handling in get/getConfigured (basically what Claudiu already proposed):
    1. No toolkit configured: this is a situation that normally should not occur. A new Drupal install has a toolkit configured and it is not possible to delete this via the UI: throw an exception.
    2. The configured toolkit cannot be used: create the plugin object and let the plugin do its own error handling (this already happens in a few places by e.g. checking if a specific GD function does exist). If the plugin code would crash in its constructor, we have another (huge) problem during toolkit selection and other requirements checking moments. So ImageToolkits should not crash in their constructor and the manager does not have to handle that case.
    3. The configured toolkit can be used but has limitations/warnings: same as above. The manager should not be bothered.
claudiu.cristea’s picture

@fietserwin,

#33.1: Agree but as a followup to have a clear distinction between issues. getActive() seems the more correct option.

#33.2: I don't understand exactly what would be the reason for accessing other toolkit than the active one? Can you show us a use case? Do you suggest that modules will be able to use Drupal with more than one toolkit in the same time? Or? Will the ImageToolkitManager::get($id) method be an alias of ImageToolkitManager::createInstance($id)? If yes, why not using that straight method?

#33.3: Agree with getAvailableToolkits() removal but I don't understand what you mean by "Drupal has a good requirements checking and reporting system, at install time, selection time and via the status report". So you want to replace isAvailable() method with per-toolkit arbitrary checks? Why?

#33.4: I'm not sure that I understood your point 2. "So ImageToolkits should not crash in their constructor...". Is crashing now in constructor? Or? Confused about this explanation. Can you illustrate this with a scenario or a piece of code?

What I feel is that you made strong scope from removing isAvailable(). I'm not against but also not in favor. I don't see why this unified edge check should be replaced with per-toolkit arbitrary checks. Give me a reason.

Also, let's synchronise our effort with the very slow progress of committing our work. Trying to radically change the image system (e.g. by letting multiple active toolkits) can ruin the whole plan.

mondrake’s picture

Assigned: mondrake » Unassigned
Status: Needs work » Needs review
StatusFileSize
new16.52 KB
new5.22 KB

Basically just a reroll of #28, plus with the form validation logic moved to the new ImageToolkitBase. Only the currently selected toolkit is validated, however all the toolkits' submits handler are invoked.

This is just to set a new starting point; I did not review #32 and #33 yet.

mondrake’s picture

Status: Needs review » Needs work

NW anyway to deal with #32, #33. Also unassigned myself as I am not sure about the time I can give to this in the short term.

fietserwin’s picture

#34.re#33.1: OK, lets go with getActive

#34.re#33.2: didn't know that one existed in the base class. Drop this.

#34.re#33.3: I don't want any runtime checks at all, let the code just fail if the status report would not show green. However, the current code does contain some checks, e.g. whether functions exist, but (I guess) mainly on the warnings (rotate and desaturate). And because I don't see the need for runtime checks, both functions can be removed (we are not building a high availability embedded system, Drupal does not do much runtime error checking)

I don't want multiple active toolkits, but I want to be able to change the toolkit (at the start of the request) without messing around with the configuration..

mondrake’s picture

Status: Needs work » Postponed
Related issues: +#2096703: Image toolkits should use PluginFormInterface and ContainerFactoryPluginInterface

This patch would introduce methods that overlap with those in #2096703: Image toolkits should use PluginFormInterface and ContainerFactoryPluginInterface. It'd be better have that one first. In any case the patch in #35 would need serious rework at this stage.

mgifford’s picture

Status: Postponed » Active

Version: 8.0.x-dev » 8.1.x-dev

Drupal 8.0.6 was released on April 6 and is the final bugfix release for the Drupal 8.0.x series. Drupal 8.0.x will not receive any further development aside from security fixes. Drupal 8.1.0-rc1 is now available and sites should prepare to update to 8.1.0.

Bug reports should be targeted against the 8.1.x-dev branch from now on, and new development or disruptive changes should be targeted against the 8.2.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

Version: 8.1.x-dev » 8.2.x-dev

Drupal 8.1.9 was released on September 7 and is the final bugfix release for the Drupal 8.1.x series. Drupal 8.1.x will not receive any further development aside from security fixes. Drupal 8.2.0-rc1 is now available and sites should prepare to upgrade to 8.2.0.

Bug reports should be targeted against the 8.2.x-dev branch from now on, and new development or disruptive changes should be targeted against the 8.3.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

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

Drupal 8.2.6 was released on February 1, 2017 and is the final full bugfix release for the Drupal 8.2.x series. Drupal 8.2.x will not receive any further development aside from critical and security fixes. Sites should prepare to update to 8.3.0 on April 5, 2017. (Drupal 8.3.0-alpha1 is available for testing.)

Bug reports should be targeted against the 8.3.x-dev branch from now on, and new development or disruptive changes should 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.

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

Drupal 8.3.6 was released on August 2, 2017 and is the final full bugfix release for the Drupal 8.3.x series. Drupal 8.3.x will not receive any further development aside from critical and security fixes. Sites should prepare to update to 8.4.0 on October 4, 2017. (Drupal 8.4.0-alpha1 is available for testing.)

Bug reports should be targeted against the 8.4.x-dev branch from now on, and new development or disruptive changes should 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.

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

Drupal 8.4.4 was released on January 3, 2018 and is the final full bugfix release for the Drupal 8.4.x series. Drupal 8.4.x will not receive any further development aside from critical and security fixes. Sites should prepare to update to 8.5.0 on March 7, 2018. (Drupal 8.5.0-alpha1 is available for testing.)

Bug reports should be targeted against the 8.5.x-dev branch from now on, and new development or disruptive changes should 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.

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

Drupal 8.5.6 was released on August 1, 2018 and is the final bugfix release for the Drupal 8.5.x series. Drupal 8.5.x will not receive any further development aside from security fixes. Sites should prepare to update to 8.6.0 on September 5, 2018. (Drupal 8.6.0-rc1 is available for testing.)

Bug reports should be targeted against the 8.6.x-dev branch from now on, and new development or disruptive changes should 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.

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

Drupal 8.6.x will not receive any further development aside from security fixes. Bug reports should be targeted against the 8.8.x-dev branch from now on, and new development or disruptive changes should be targeted against the 8.9.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.

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

Drupal 8.8.7 was released on June 3, 2020 and is the final full bugfix release for the Drupal 8.8.x series. Drupal 8.8.x will not receive any further development aside from security fixes. Sites should prepare to update to Drupal 8.9.0 or Drupal 9.0.0 for ongoing support.

Bug reports should be targeted against the 8.9.x-dev branch from now on, and new development or disruptive changes should 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.

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

Drupal 8 is end-of-life as of November 17, 2021. There will not be further changes made to Drupal 8. Bugfixes are now made to the 9.3.x and higher branches only. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

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

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

Drupal 9.3.15 was released on June 1st, 2022 and is the final full bugfix release for the Drupal 9.3.x series. Drupal 9.3.x will not receive any further development aside from security fixes. Drupal 9 bug reports should be targeted for the 9.4.x-dev branch from now on, and new development or disruptive changes should 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.

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

Drupal 9.4.9 was released on December 7, 2022 and is the final full bugfix release for the Drupal 9.4.x series. Drupal 9.4.x will not receive any further development aside from security fixes. Drupal 9 bug reports should be targeted for the 9.5.x-dev branch from now on, and new development or disruptive changes should 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.

Version: 9.5.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. For more information, see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

smustgrave’s picture

Status: Active » Postponed (maintainer needs more info)
Issue tags: +stale-issue-cleanup

Thank you for creating this issue to improve Drupal.

We are working to decide if this task is still relevant to a currently supported version of Drupal. There hasn't been any discussion here for over 8 years which suggests that this has either been implemented or is no longer relevant. Your thoughts on this will allow a decision to be made.

Since we need more information to move forward with this issue, the status is now Postponed (maintainer needs more info). If we don't receive additional information to help with the issue, it may be closed after three months.

Thanks!

smustgrave’s picture

Status: Postponed (maintainer needs more info) » Needs work

believe to still be valid as isAvailable() is still part of this interface

Version: 11.x-dev » main

Drupal core is now using the main branch as the primary development branch. New developments and disruptive changes should now be targeted to the main branch.

Read more in the announcement.