Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Deprecate internal extension functions in favor of methods on the extension classes #3883

Merged
merged 10 commits into from
Dec 10, 2023
Merged
4 changes: 3 additions & 1 deletion CHANGELOG
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
# 3.8.1 (2023-XX-XX)
# 3.9.0 (2023-XX-XX)

* Add return type for Symfony 7 compatibility
* Fix premature loop exit in Security Policy lookup of allowed methods/properties
* Deprecate all internal extension functions in favor of methods on the extension classes
* Mark all extension functions as @internal

# 3.8.0 (2023-11-21)

Expand Down
7 changes: 7 additions & 0 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
"require": {
"php": ">=7.2.5",
"symfony/polyfill-php80": "^1.22",
"symfony/deprecation-contracts": "^2.5|^3",
"symfony/polyfill-mbstring": "^1.3",
"symfony/polyfill-ctype": "^1.8"
},
Expand All @@ -34,6 +35,12 @@
"psr/container": "^1.0|^2.0"
},
"autoload": {
"files": [
"src/Resources/core.php",
"src/Resources/debug.php",
"src/Resources/escaper.php",
"src/Resources/string_loader.php"
],
"psr-4" : {
"Twig\\" : "src/"
}
Expand Down
7 changes: 7 additions & 0 deletions doc/deprecated.rst
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,10 @@ Functions

* The `twig_test_iterable` function is deprecated; use the native
`is_iterable` instead.

Extensions
----------

* All functions defined in Twig extensions are marked as internal as of Twig
3.9.0, and will be removed in Twig 4.0. They have been replaced by internal
methods on their respective extension classes.
21 changes: 12 additions & 9 deletions extra/cssinliner-extra/CssInlinerExtension.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,17 +20,20 @@ class CssInlinerExtension extends AbstractExtension
public function getFilters()
{
return [
new TwigFilter('inline_css', 'Twig\\Extra\\CssInliner\\twig_inline_css', ['is_safe' => ['all']]),
new TwigFilter('inline_css', [self::class, 'inlineCss'], ['is_safe' => ['all']]),
];
}
}

function twig_inline_css(string $body, string ...$css): string
{
static $inliner;
if (null === $inliner) {
$inliner = new CssToInlineStyles();
}
/**
* @internal
*/
public static function inlineCss(string $body, string ...$css): string
{
static $inliner;
if (null === $inliner) {
$inliner = new CssToInlineStyles();
}

return $inliner->convert($body, implode("\n", $css));
return $inliner->convert($body, implode("\n", $css));
}
}
24 changes: 24 additions & 0 deletions extra/cssinliner-extra/Resources/functions.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<?php

/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace Twig\Extra\CssInliner;

/**
* @internal
*
* @deprecated since Twig 3.9.0
*/
function twig_inline_css(string $body, string ...$css): string
{
trigger_deprecation('twig/cssinliner-extra', '3.9.0', 'Using the internal "%s" function is deprecated.', __FUNCTION__);

return CssInlinerExtension::inlineCss($body, ...$css);
}
28 changes: 28 additions & 0 deletions extra/cssinliner-extra/Tests/LegacyFunctionsTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
<?php

/*
* This file is part of Twig.
*
* (c) Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace Twig\Extra\CssInliner\Tests;

use PHPUnit\Framework\TestCase;
use Twig\Extra\CssInliner\CssInlinerExtension;

use function Twig\Extra\CssInliner\twig_inline_css;

/**
* @group legacy
*/
class LegacyFunctionsTest extends TestCase
{
public function testInlineCss()
{
$this->assertSame(CssInlinerExtension::inlineCss('<p>body</p>', 'p { color: red }'), twig_inline_css('<p>body</p>', 'p { color: red }'));
}
}
2 changes: 2 additions & 0 deletions extra/cssinliner-extra/composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,15 @@
],
"require": {
"php": ">=7.2.5",
"symfony/deprecation-contracts": "^2.5|^3",
"tijsverkoyen/css-to-inline-styles": "^2.0",
"twig/twig": "^3.0"
},
"require-dev": {
"symfony/phpunit-bridge": "^6.4|^7.0"
},
"autoload": {
"files": [ "Resources/functions.php" ],
"psr-4" : { "Twig\\Extra\\CssInliner\\" : "" },
"exclude-from-classmap": [
"/Tests/"
Expand Down
54 changes: 28 additions & 26 deletions extra/html-extra/HtmlExtension.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,10 @@
* file that was distributed with this source code.
*/

namespace Twig\Extra\Html {
namespace Twig\Extra\Html;

use Symfony\Component\Mime\MimeTypes;
use Twig\Error\RuntimeError;
use Twig\Extension\AbstractExtension;
use Twig\TwigFilter;
use Twig\TwigFunction;
Expand All @@ -34,7 +36,7 @@ public function getFilters(): array
public function getFunctions(): array
{
return [
new TwigFunction('html_classes', 'twig_html_classes'),
new TwigFunction('html_classes', [self::class, 'htmlClasses']),
];
}

Expand All @@ -45,6 +47,8 @@ public function getFunctions(): array
* be done before calling this filter.
*
* @return string The generated data URI
*
* @internal
*/
public function dataUri(string $data, string $mime = null, array $parameters = []): string
{
Expand Down Expand Up @@ -79,33 +83,31 @@ public function dataUri(string $data, string $mime = null, array $parameters = [

return $repr;
}
}
}

namespace {
use Twig\Error\RuntimeError;

function twig_html_classes(...$args): string
{
$classes = [];
foreach ($args as $i => $arg) {
if (\is_string($arg)) {
$classes[] = $arg;
} elseif (\is_array($arg)) {
foreach ($arg as $class => $condition) {
if (!\is_string($class)) {
throw new RuntimeError(sprintf('The html_classes function argument %d (key %d) should be a string, got "%s".', $i, $class, \gettype($class)));
}
if (!$condition) {
continue;
/**
* @internal
*/
public static function htmlClasses(...$args): string
{
$classes = [];
foreach ($args as $i => $arg) {
if (\is_string($arg)) {
$classes[] = $arg;
} elseif (\is_array($arg)) {
foreach ($arg as $class => $condition) {
if (!\is_string($class)) {
throw new RuntimeError(sprintf('The html_classes function argument %d (key %d) should be a string, got "%s".', $i, $class, \gettype($class)));
}
if (!$condition) {
continue;
}
$classes[] = $class;
}
$classes[] = $class;
} else {
throw new RuntimeError(sprintf('The html_classes function argument %d should be either a string or an array, got "%s".', $i, \gettype($arg)));
}
} else {
throw new RuntimeError(sprintf('The html_classes function argument %d should be either a string or an array, got "%s".', $i, \gettype($arg)));
}
}

return implode(' ', array_unique($classes));
}
return implode(' ', array_unique($classes));
}
}
24 changes: 24 additions & 0 deletions extra/html-extra/Resources/functions.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<?php

/*
* This file is part of Twig.
*
* (c) Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

use Twig\Extra\Html\HtmlExtension;

/**
* @internal
*
* @deprecated since Twig 3.9.0
*/
function twig_html_classes(...$args): string
{
trigger_deprecation('twig/html-extra', '3.9.0', 'Using the internal "%s" function is deprecated.', __FUNCTION__);

return HtmlExtension::htmlClasses(...$args);
}
26 changes: 26 additions & 0 deletions extra/html-extra/Tests/LegacyFunctionsTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
<?php

/*
* This file is part of Twig.
*
* (c) Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace Twig\Extra\Html\Tests;

use PHPUnit\Framework\TestCase;
use Twig\Extra\Html\HtmlExtension;

/**
* @group legacy
*/
class LegacyFunctionsTest extends TestCase
{
public function testHtmlToMarkdown()
{
$this->assertSame(HtmlExtension::htmlClasses(['charset' => 'utf-8']), \twig_html_classes(['charset' => 'utf-8']));
}
}
2 changes: 2 additions & 0 deletions extra/html-extra/composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,15 @@
],
"require": {
"php": ">=7.2.5",
"symfony/deprecation-contracts": "^2.5|^3",
"symfony/mime": "^5.4|^6.0|^7.0",
"twig/twig": "^3.0"
},
"require-dev": {
"symfony/phpunit-bridge": "^6.4|^7.0"
},
"autoload": {
"files": [ "Resources/functions.php" ],
"psr-4" : { "Twig\\Extra\\Html\\" : "" },
"exclude-from-classmap": [
"/Tests/"
Expand Down
13 changes: 8 additions & 5 deletions extra/inky-extra/InkyExtension.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,15 @@ class InkyExtension extends AbstractExtension
public function getFilters()
{
return [
new TwigFilter('inky_to_html', 'Twig\\Extra\\Inky\\twig_inky', ['is_safe' => ['html']]),
new TwigFilter('inky_to_html', [self::class, 'inky'], ['is_safe' => ['html']]),
];
}
}

function twig_inky(string $body): string
{
return false === ($html = Pinky\transformString($body)->saveHTML()) ? '' : $html;
/**
* @internal
*/
public static function inky(string $body): string
{
return false === ($html = Pinky\transformString($body)->saveHTML()) ? '' : $html;
}
}
24 changes: 24 additions & 0 deletions extra/inky-extra/Resources/functions.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<?php

/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace Twig\Extra\Inky;

/**
* @internal
*
* @deprecated since Twig 3.9.0
*/
function twig_inky(string $body): string
{
trigger_deprecation('twig/inky-extra', '3.9.0', 'Using the internal "%s" function is deprecated.', __FUNCTION__);

return InkyExtension::inky($body);
}
28 changes: 28 additions & 0 deletions extra/inky-extra/Tests/LegacyFunctionsTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
<?php

/*
* This file is part of Twig.
*
* (c) Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace Twig\Extra\Inky\Tests;

use PHPUnit\Framework\TestCase;
use Twig\Extra\Inky\InkyExtension;

use function Twig\Extra\Inky\twig_inky;

/**
* @group legacy
*/
class LegacyFunctionsTest extends TestCase
{
public function testInlineCss()
{
$this->assertSame(InkyExtension::inky('<p>Foo</p>'), twig_inky('<p>Foo</p>'));
}
}
2 changes: 2 additions & 0 deletions extra/inky-extra/composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,15 @@
],
"require": {
"php": ">=7.2.5",
"symfony/deprecation-contracts": "^2.5|^3",
"lorenzo/pinky": "^1.0.5",
"twig/twig": "^3.0"
},
"require-dev": {
"symfony/phpunit-bridge": "^6.4|^7.0"
},
"autoload": {
"files": [ "Resources/functions.php" ],
"psr-4" : { "Twig\\Extra\\Inky\\" : "" },
"exclude-from-classmap": [
"/Tests/"
Expand Down
Loading
Loading