trait DoTrustedCallbackTrait

Same name and namespace in other branches
  1. 9 core/lib/Drupal/Core/Security/DoTrustedCallbackTrait.php \Drupal\Core\Security\DoTrustedCallbackTrait
  2. 8.9.x core/lib/Drupal/Core/Security/DoTrustedCallbackTrait.php \Drupal\Core\Security\DoTrustedCallbackTrait
  3. 10 core/lib/Drupal/Core/Security/DoTrustedCallbackTrait.php \Drupal\Core\Security\DoTrustedCallbackTrait

Ensures that only predefined methods can be used as callback methods.

Hierarchy

See also

\Drupal\Core\Security\Attribute\TrustedCallback

\Drupal\Core\Security\TrustedCallbackInterface

6 files declare their use of DoTrustedCallbackTrait
ComponentElement.php in core/modules/sdc/src/Element/ComponentElement.php
ComponentElement.php in core/lib/Drupal/Core/Render/Element/ComponentElement.php
Datelist.php in core/lib/Drupal/Core/Datetime/Element/Datelist.php
Datetime.php in core/lib/Drupal/Core/Datetime/Element/Datetime.php
DoTrustedCallbackTraitTest.php in core/tests/Drupal/Tests/Core/Security/DoTrustedCallbackTraitTest.php

... See full list

File

core/lib/Drupal/Core/Security/DoTrustedCallbackTrait.php, line 13

Namespace

Drupal\Core\Security
View source
trait DoTrustedCallbackTrait {
    
    /**
     * Performs a callback.
     *
     * If the callback is trusted the callback will occur. Trusted callbacks must
     * be methods that are tagged with the
     * \Drupal\Core\Security\Attribute\TrustedCallback attribute, or be methods of
     * a class that implements
     * \Drupal\Core\Security\TrustedCallbackInterface or $extra_trusted_interface,
     * or be an anonymous function. If the callback is not trusted then whether or
     * not the callback is called and what type of error is thrown depends on
     * $error_type. To provide time for dependent code to use trusted callbacks
     * use TrustedCallbackInterface::TRIGGER_SILENCED_DEPRECATION and then at a
     * later date change this to TrustedCallbackInterface::THROW_EXCEPTION.
     *
     * @param callable $callback
     *   The callback to call. Note that callbacks which are objects and use the
     *   magic method __invoke() are not supported.
     * @param array $args
     *   The arguments to pass the callback.
     * @param $message
     *   The error message if the callback is not trusted. If the message contains
     *   "%s" it will be replaced in with the resolved callback.
     * @param string $error_type
     *   (optional) The type of error to trigger. One of:
     *   - TrustedCallbackInterface::THROW_EXCEPTION
     *   - TrustedCallbackInterface::TRIGGER_SILENCED_DEPRECATION
     *   Defaults to TrustedCallbackInterface::THROW_EXCEPTION.
     * @param string $extra_trusted_interface
     *   (optional) An additional interface that if implemented by the callback
     *   object means any public methods on that object are trusted.
     *
     * @return mixed
     *   The callback's return value.
     *
     * @throws \Drupal\Core\Security\UntrustedCallbackException
     *   Exception thrown if the callback is not trusted and $error_type equals
     *   TrustedCallbackInterface::THROW_EXCEPTION.
     *
     * @see \Drupal\Core\Security\Attribute\TrustedCallback
     * @see \Drupal\Core\Security\TrustedCallbackInterface
     */
    public function doTrustedCallback(callable $callback, array $args, $message, $error_type = TrustedCallbackInterface::THROW_EXCEPTION, $extra_trusted_interface = NULL) {
        $object_or_classname = $callback;
        $safe_callback = FALSE;
        if (is_array($callback)) {
            [
                $object_or_classname,
                $method_name,
            ] = $callback;
        }
        elseif (is_string($callback) && str_contains($callback, '::')) {
            [
                $object_or_classname,
                $method_name,
            ] = explode('::', $callback, 2);
        }
        if (isset($method_name)) {
            if ($extra_trusted_interface && is_subclass_of($object_or_classname, $extra_trusted_interface)) {
                $safe_callback = TRUE;
            }
            elseif (is_subclass_of($object_or_classname, TrustedCallbackInterface::class)) {
                if (is_object($object_or_classname)) {
                    $methods = $object_or_classname->trustedCallbacks();
                }
                else {
                    $methods = call_user_func($object_or_classname . '::trustedCallbacks');
                }
                $safe_callback = in_array($method_name, $methods, TRUE);
            }
            if (!$safe_callback) {
                $method = new \ReflectionMethod($object_or_classname, $method_name);
                $safe_callback = (bool) $method->getAttributes(TrustedCallback::class);
            }
        }
        elseif ($callback instanceof \Closure) {
            $safe_callback = TRUE;
        }
        if (!$safe_callback) {
            $description = $object_or_classname;
            if (is_object($description)) {
                $description = get_class($description);
            }
            if (isset($method_name)) {
                $description .= '::' . $method_name;
            }
            $message = sprintf($message, $description);
            if ($error_type === TrustedCallbackInterface::TRIGGER_SILENCED_DEPRECATION) {
                @trigger_error($message, E_USER_DEPRECATED);
            }
            else {
                throw new UntrustedCallbackException($message);
            }
        }
        // @todo Allow named arguments in https://www.drupal.org/node/3174150
        return call_user_func_array($callback, array_values($args));
    }

}

Members

Title Sort descending Modifiers Object type Summary
DoTrustedCallbackTrait::doTrustedCallback public function Performs a callback.

Buggy or inaccurate documentation? Please file an issue. Need support? Need help programming? Connect with the Drupal community.