Support from Acquia helps fund testing for Drupal Acquia logo

Comments

timmillwood created an issue. See original summary.

dawehner’s picture

Just curious, should we have a is_callable in the if statement?

timmillwood’s picture

FileSize
742 bytes

I'm up for that.

dawehner’s picture

+++ b/core/modules/options/options.module
@@ -84,8 +84,8 @@ function options_allowed_values(FieldStorageDefinitionInterface $definition, Fie
+      $values = call_user_func_array($function, [$definition, $entity, &$cacheable]);

Oh passing a parameter by reference is still a thing?

timmillwood’s picture

I guess so because if I don't pass it by reference I get the following error:

[Mon Feb 29 16:03:17.232248 2016] [:error] [pid 14826] [client 127.0.0.1:40820] Error: Unsupported operand types in /home/timmillwood/Code/drupal/core/lib/Drupal/Core/Field/Plugin/Field/FieldWidget/OptionsWidgetBase.php on line 125
tstoeckler’s picture

This is just me, but I disagree with the is_callable. You can only ever set allowed_values_function from code, so even if it ends up in code, there's really no user interaction that could cause a failure. So if the allowed_values_function is not a callable it's either a straight up developer error (typo, ...) or it's a problem with the setup (borked autoloader, module not installed, ...). In both cases I'd rather have a fatal, than use a potentially bogus default value, so I can actually fix the problem.

Leaving at needs review to get more opinions on this.

timmillwood’s picture

Good points @tstoeckler, so either patch is open for RTBC ;)

dawehner’s picture

I agree, well ideally we would check it and otherwise throw an exception, but I agree, there is no much difference to a call to undefined function.

tstoeckler’s picture

well ideally we would check it and otherwise throw an exception

I would totally dig that, but yeah, not sure whether the twisted joy that I feel when I see typed exceptions bubble up to my browser is worth coding and maintaining those extra LOCs.

dawehner’s picture

Why not, its just 3 lines.

timmillwood’s picture

How about this?

dawehner’s picture

+++ b/core/modules/options/options.module
@@ -85,7 +84,12 @@ function options_allowed_values(FieldStorageDefinitionInterface $definition, Fie
+        throw new Exception($function . " is not callable.");

Are we sure $function can be cast to a string?

timmillwood’s picture

hrm... good point!

Tested this by setting

'allowed_values_function' => array('\Drupal\workspace\Entity\Replication', 'getPointerAllowedValue')

This throws

Uncaught PHP Exception Exception: "\\Drupal\\workspace\\Entity\\Replication::getPointerAllowedValue is not callable." at /home/timmillwood/Code/drupal/core/modules/options/options.module line 9
dawehner’s picture

Status: Needs review » Reviewed & tested by the community

OOOHHH
I didn't knew is_callable() has this functionality!

timmillwood’s picture

Just wondering if we should extend the scope of this patch by catching the exception in \Drupal\options\Plugin\Field\FieldType\ListItemBase::getSettableOptions and \Drupal\options\Plugin\Field\FieldType\ListItemBase::generateSampleValue.

Not sure if it's best to throw it uncaught, or to catch it, but will leave the option out there with this patch.

deviantintegral’s picture

Status: Reviewed & tested by the community » Needs work

This patch has the nice side effect of clearing up a PHPStorm error that the entire file is invalid due to the setting method returning mixed and not a callable.

  1. +++ b/core/modules/options/options.module
    @@ -62,11 +62,10 @@ function options_field_storage_config_delete(FieldStorageConfigInterface $field_
    - *
    

    Code style, we need this blank line and the one between @return and @throws.

  2. +++ b/core/modules/options/options.module
    @@ -85,7 +84,12 @@ function options_allowed_values(FieldStorageDefinitionInterface $definition, Fie
    +        throw new Exception($callable_name . " is not callable.");
    

    Should we throw http://php.net/manual/en/class.badfunctioncallexception.php or http://php.net/manual/en/class.badmethodcallexception.php instead?

  3. +++ b/core/modules/options/src/Plugin/Field/FieldType/ListItemBase.php
    @@ -63,17 +63,30 @@ public function getSettableValues(AccountInterface $account = NULL) {
    +      watchdog_exception('options', $e);
    

    This I think highlights why we should throw an exception above. Let's say the callback throws it's own exception, it's going to be silently logged instead of giving any other code a chance to deal with it.

    I would say we should either catch a specific exception (possibly even subclassing one of the above) or remove the catches entirely.

timmillwood’s picture

Status: Needs work » Needs review
FileSize
1.41 KB
1.24 KB

I think we should remove the catches too, so working from patch in #13.

Updated the docblock, and throwing BadFunctionCallException now, that seemed appropriate seeing as this is allowed_values_function, and not allowed_values_method.

deviantintegral’s picture

Status: Needs review » Reviewed & tested by the community

Agreed, this looks good to me.

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

Drupal 8.1.0-beta1 was released on March 2, 2016, which means new developments and disruptive changes should now 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.

alexpott’s picture

Version: 8.2.x-dev » 8.1.x-dev
Status: Reviewed & tested by the community » Needs work
+++ b/core/modules/options/options.module
@@ -85,7 +87,12 @@ function options_allowed_values(FieldStorageDefinitionInterface $definition, Fie
+        throw new BadFunctionCallException($callable_name . " is not callable.");

Needs a leading slash and exception messages shouldn't end in a fullstop because they appear as part of the sentence when displayed. And it probably could be tested.

Given this is a bug fix and actually just provides a nicer way to break this is definitely eligible for 8.1.x

alexpott’s picture

Issue tags: +Needs tests
arunkumark’s picture

Status: Needs work » Needs review
FileSize
1.24 KB

Hi,
As per the Comment #20 made a small change in timmillwood's patch.

tstoeckler’s picture

Status: Needs review » Needs work

Patch looks great, thanks @arunkumark!

Still needs tests, though, so setting back to "needs work" for now, now that the test bot has confirmed the patch is good.

xjm’s picture

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

#20 was true during the beta phase for 8.1.x, but since the fix changes the error flow, we should target it for the development minor after the first release candidate of the previous minor. (I.e., it's not patch-eligible.)

Agreed on needing tests; they should be pretty simple to write I think?

Thanks everyone!

tstoeckler’s picture

@xjm: Can you elaborate on what you mean by "changes the error flow"? Seems to me this is purely a DX-nicety and, thus, 8.2.x eligible (both before and after 8.2.0).

dawehner’s picture

I think @xjm points to the different of providing a fatal: call to undefined function vs. throwing an exception. As long we are not in PHP7 land, where those errors are maybe handled in a better way, replacing a fatal error with an exception is really the only sane way of doing it. One thing I would try to figure out: What do other places in core do here? Do they silently fail and just don't call the function (the render/theme/form systems should have a bunch of those examples). IMHO we should follow that example.

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

Drupal 8.3.0-alpha1 will be released the week of January 30, 2017, which means new developments and disruptive changes should now 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.

pwolanin’s picture

@dawhener looking at the renderer it would just fatal in \Drupal\Core\Render\Renderer::render()

    // Make any final changes to the element before it is rendered. This means
    // that the $element or the children can be altered or corrected before the
    // element is rendered into the final text.
    if (isset($elements['#pre_render'])) {
      foreach ($elements['#pre_render'] as $callable) {
        if (is_string($callable) && strpos($callable, '::') === FALSE) {
          $callable = $this->controllerResolver->getControllerFromDefinition($callable);
        }
        $elements = call_user_func($callable, $elements);
      }
    }

Throwing the exception still seems better than a fatal since we can test that behavior.

Note - patch #22 still applies to 8.4.x

dawehner’s picture

Status: Needs work » Needs review

Throwing the exception still seems better than a fatal since we can test that behavior.

Yeah a fatal is never what you want, IMHO.

Setting back to needs review, as the patch passes.

pwolanin’s picture

Title: Handle allowed_values_function in a slightly better way » Handle any callable for options allowed_values_function
Issue tags: -Needs tests
Related issues: +#2547505: "allowed_values_function" doesn't use call_user_func()
FileSize
5.44 KB
4.2 KB

closed this other as duplicate: #2547505: "allowed_values_function" doesn't use call_user_func()

Note from discussion with Berdir in IRC, you can only set in the field config a string for this, so you can use a string or static method but not an array.

If you try to save a field storage definition with an array callable you get an exception. So, it's probably fine to support any callable, but in practice (and for tests) we need only consider strings.

Here's with some added tests.

Status: Needs review » Needs work

The last submitted patch, 30: 2678014-29.patch, failed testing. View results

timmillwood’s picture

Issue tags: +Needs reroll
pk188’s picture

Status: Needs work » Needs review
Issue tags: -Needs reroll
FileSize
5.49 KB

Re rolled.

dawehner’s picture

+++ b/core/modules/options/options.module
@@ -67,6 +67,8 @@ function options_field_storage_config_delete(FieldStorageConfigInterface $field_
+ * @throws \BadFunctionCallException
+ *

We should document when this is thrown.

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

Drupal 8.4.0-alpha1 will be released the week of July 31, 2017, which means new developments and disruptive changes should now 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.5.x-dev » 8.6.x-dev

Drupal 8.5.0-alpha1 will be released the week of January 17, 2018, which means new developments and disruptive changes should now 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.

joachim’s picture

Status: Needs review » Needs work

Looks good apart from:

+++ b/core/modules/options/options.module
@@ -85,7 +87,12 @@ function options_allowed_values(FieldStorageDefinitionInterface $definition, Fie
+      if (is_callable($function, FALSE, $callable_name)) {

$callable_name is not defined.

Do we need to use the long form of is_callable() here anyway?

Sam152’s picture

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

Drupal 8.6.0-alpha1 will be released the week of July 16, 2018, which means new developments and disruptive changes should now 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.7.x-dev » 8.8.x-dev

Drupal 8.7.0-alpha1 will be released the week of March 11, 2019, which means new developments and disruptive changes should now be targeted against the 8.8.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

joachim’s picture

joachim’s picture

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

Actually, I think this can be closed in favour of #2975503: allow FieldConfigInterface::setDefaultValueCallback() to accept a callback in service notation, which also depends on #2982949: Introduce CallableResolver to help standardise the DX and error handling for callbacks across various subsystems.

Static method notation works fine in versions of PHP that are now supported by Drupal 8. Eg:

      ->setSettings([
        'allowed_values_function' => [MyClass::class, 'myCallback'],
      ])

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

Drupal 8.8.0-alpha1 will be released the week of October 14th, 2019, which means new developments and disruptive changes should now be targeted against the 8.9.x-dev branch. (Any changes to 8.9.x will also be committed to 9.0.x in preparation for Drupal 9’s release, but some changes like significant feature additions will be deferred to 9.1.x.). 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.1.x-dev

Drupal 8.9.0-beta1 was released on March 20, 2020. 8.9.x is the final, long-term support (LTS) minor release of Drupal 8, which means new developments and disruptive changes should now 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: 9.1.x-dev » 9.2.x-dev

Drupal 9.1.0-alpha1 will be released the week of October 19, 2020, which means new developments and disruptive changes should now be targeted for the 9.2.x-dev branch. For more information see the Drupal 9 minor version schedule and the Allowed changes during the Drupal 9 release cycle.

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

Drupal 9.2.0-alpha1 will be released the week of May 3, 2021, which means new developments and disruptive changes should now be targeted for the 9.3.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.3.x-dev » 9.4.x-dev

Drupal 9.3.0-rc1 was released on November 26, 2021, which means new developments and disruptive changes should now be targeted for the 9.4.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.0-alpha1 was released on May 6, 2022, which means new developments and disruptive changes should now 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.

Amber Himes Matz’s picture

Status: Postponed (maintainer needs more info) » Closed (duplicate)
Issue tags: +Bug Smash Initiative

Per @joachim's comment in #42, looks like this issue should be closed as a duplicate in favor of #2975503: allow FieldConfigInterface::setDefaultValueCallback() to accept a callback in service notation. I'm closing this one and transferring credit over to that issue, as there was a lot of great discussion, review, patches, and triaging work here.

Triaged as part of the Bug Smash Initiative.

Amber Himes Matz’s picture

Amber Himes Matz’s picture

Since credit was transferred to the other issue #2975503: allow FieldConfigInterface::setDefaultValueCallback() to accept a callback in service notation, removing the credit here.