From 9dfb602168e66fc7e833fd50cb05a3fc1fb84bdf Mon Sep 17 00:00:00 2001 From: Alex Pott Date: Tue, 22 Jan 2019 12:46:01 +0000 Subject: [PATCH] Issue #2591515 by joelpittet, Cottser, lauriii, NickWilde, kostyashupenko, alexpott, xjm: Move twig_without() to the TwigExtension where all the other filters are and deprecate --- .../Drupal/Core/Template/TwigEnvironment.php | 1 + .../Drupal/Core/Template/TwigExtension.php | 35 +++++++++++++++++- .../tests/src/Kernel/Theme/TwigFilterTest.php | 36 +++++++++++++++++++ core/themes/engines/twig/twig.engine | 22 +++++------- 4 files changed, 79 insertions(+), 15 deletions(-) diff --git a/core/lib/Drupal/Core/Template/TwigEnvironment.php b/core/lib/Drupal/Core/Template/TwigEnvironment.php index a3a83041168..59f2005490b 100644 --- a/core/lib/Drupal/Core/Template/TwigEnvironment.php +++ b/core/lib/Drupal/Core/Template/TwigEnvironment.php @@ -60,6 +60,7 @@ class TwigEnvironment extends \Twig_Environment { // Ensure that twig.engine is loaded, given that it is needed to render a // template because functions like TwigExtension::escapeFilter() are called. + // @todo remove in Drupal 9.0.0 https://www.drupal.org/node/3011393. require_once $root . '/core/themes/engines/twig/twig.engine'; $this->templateClasses = []; diff --git a/core/lib/Drupal/Core/Template/TwigExtension.php b/core/lib/Drupal/Core/Template/TwigExtension.php index 8f47ed40740..b7f51ecb1f3 100644 --- a/core/lib/Drupal/Core/Template/TwigExtension.php +++ b/core/lib/Drupal/Core/Template/TwigExtension.php @@ -177,7 +177,7 @@ class TwigExtension extends \Twig_Extension { new \Twig_SimpleFilter('safe_join', [$this, 'safeJoin'], ['needs_environment' => TRUE, 'is_safe' => ['html']]), // Array filters. - new \Twig_SimpleFilter('without', 'twig_without'), + new \Twig_SimpleFilter('without', [$this, 'withoutFilter']), // CSS class and ID filters. new \Twig_SimpleFilter('clean_class', '\Drupal\Component\Utility\Html::getClass'), @@ -641,4 +641,37 @@ class TwigExtension extends \Twig_Extension { return new Attribute($attributes); } + /** + * Removes child elements from a copy of the original array. + * + * Creates a copy of the renderable array and removes child elements by key + * specified through filter's arguments. The copy can be printed without these + * elements. The original renderable array is still available and can be used + * to print child elements in their entirety in the twig template. + * + * @param array|object $element + * The parent renderable array to exclude the child items. + * @param string[] ... + * The string keys of $element to prevent printing. + * + * @return array + * The filtered renderable array. + */ + public function withoutFilter($element) { + if ($element instanceof \ArrayAccess) { + $filtered_element = clone $element; + } + else { + $filtered_element = $element; + } + $args = func_get_args(); + unset($args[0]); + foreach ($args as $arg) { + if (isset($filtered_element[$arg])) { + unset($filtered_element[$arg]); + } + } + return $filtered_element; + } + } diff --git a/core/modules/system/tests/src/Kernel/Theme/TwigFilterTest.php b/core/modules/system/tests/src/Kernel/Theme/TwigFilterTest.php index c1c26dd032c..60951bafcf4 100644 --- a/core/modules/system/tests/src/Kernel/Theme/TwigFilterTest.php +++ b/core/modules/system/tests/src/Kernel/Theme/TwigFilterTest.php @@ -2,6 +2,7 @@ namespace Drupal\Tests\system\Kernel\Theme; +use Drupal\Core\Extension\Extension; use Drupal\KernelTests\KernelTestBase; /** @@ -120,4 +121,39 @@ class TwigFilterTest extends KernelTestBase { } } + /** + * Test "twig_without" filter function. + * + * @expectedDeprecation twig_without() is deprecated in Drupal 8.7.x and will be removed before Drupal 9.0.0. Use \Drupal\Core\Template\TwigExtension::withoutFilter(). See https://www.drupal.org/node/3011154. + * @group legacy + */ + public function testLegacyTwigWithoutFunction() { + // Load the twig engine to ensure twig_without() exists. + $twig_engine = new Extension($this->root, 'theme_engine', 'core/themes/engines/twig/twig.info.yml', 'twig.engine'); + $twig_engine->load(); + + $filter_test = [ + 'red' => '#F00', + 'green' => '#0F0', + 'blue' => '#00F', + ]; + + // Filter out red key. + $result_without_red = twig_without($filter_test, 'red'); + $expected_without_red = $filter_test; + unset($expected_without_red['red']); + $this->assertSame($expected_without_red, $result_without_red); + + // Filter nothing and check the array is unaltered. + $result_unaltered = twig_without($filter_test); + $this->assertSame($filter_test, $result_unaltered); + + // Filter out blue and green. + $result_without_blue_green = twig_without($filter_test, 'blue', 'green'); + $expected_without_blue_green = $filter_test; + unset($expected_without_blue_green['blue']); + unset($expected_without_blue_green['green']); + $this->assertSame($expected_without_blue_green, $result_without_blue_green); + } + } diff --git a/core/themes/engines/twig/twig.engine b/core/themes/engines/twig/twig.engine index 177e01a5114..a3d2a5e26dc 100644 --- a/core/themes/engines/twig/twig.engine +++ b/core/themes/engines/twig/twig.engine @@ -133,20 +133,14 @@ function twig_render_template($template_file, array $variables) { * * @return array * The filtered renderable array. + * + * @deprecated in Drupal 8.7.x and will be removed before 9.0.0. Use + * \Drupal\Core\Template\TwigExtension::withoutFilter() instead. */ function twig_without($element) { - if ($element instanceof ArrayAccess) { - $filtered_element = clone $element; - } - else { - $filtered_element = $element; - } - $args = func_get_args(); - unset($args[0]); - foreach ($args as $arg) { - if (isset($filtered_element[$arg])) { - unset($filtered_element[$arg]); - } - } - return $filtered_element; + @trigger_error('twig_without() is deprecated in Drupal 8.7.x and will be removed before Drupal 9.0.0. Use \Drupal\Core\Template\TwigExtension::withoutFilter(). See https://www.drupal.org/node/3011154.', E_USER_DEPRECATED); + /** @var \Drupal\Core\Template\TwigExtension $extension */ + $extension = \Drupal::service('twig.extension'); + + return call_user_func_array([$extension, 'withoutFilter'], func_get_args()); }