mirror of
https://github.com/twigphp/Twig.git
synced 2026-08-30 03:57:21 +00:00
Add the possibility to deprecate attributes and nodes on Node
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
# 3.11.0 (2024-XX-XX)
|
||||
|
||||
* Add the possibility to deprecate attributes and nodes on `Node`
|
||||
* Add the possibility to add a package and a version to the `deprecated` tag
|
||||
* Add the possibility to add a package for filter/function/test deprecations
|
||||
* Mark `ConstantExpression` as being `@final`
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
<?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\Node;
|
||||
|
||||
/**
|
||||
* Represents a deprecation for a named node or attribute on a Node.
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
*/
|
||||
class NameDeprecation
|
||||
{
|
||||
private $package;
|
||||
private $version;
|
||||
private $newName;
|
||||
|
||||
public function __construct(string $package = '', string $version = '', string $newName = '')
|
||||
{
|
||||
$this->package = $package;
|
||||
$this->version = $version;
|
||||
$this->newName = $newName;
|
||||
}
|
||||
|
||||
public function getPackage(): string
|
||||
{
|
||||
return $this->package;
|
||||
}
|
||||
|
||||
public function getVersion(): string
|
||||
{
|
||||
return $this->version;
|
||||
}
|
||||
|
||||
public function getNewName(): string
|
||||
{
|
||||
return $this->newName;
|
||||
}
|
||||
}
|
||||
@@ -30,6 +30,10 @@ class Node implements \Countable, \IteratorAggregate
|
||||
protected $tag;
|
||||
|
||||
private $sourceContext;
|
||||
/** @var array<string, NameDeprecation> */
|
||||
private $nodeNameDeprecations = [];
|
||||
/** @var array<string, NameDeprecation> */
|
||||
private $attributeNameDeprecations = [];
|
||||
|
||||
/**
|
||||
* @param array $nodes An array of named nodes
|
||||
@@ -109,14 +113,39 @@ class Node implements \Countable, \IteratorAggregate
|
||||
throw new \LogicException(\sprintf('Attribute "%s" does not exist for Node "%s".', $name, static::class));
|
||||
}
|
||||
|
||||
$triggerDeprecation = \func_num_args() > 1 ? func_get_arg(1) : true;
|
||||
if ($triggerDeprecation && isset($this->attributeNameDeprecations[$name])) {
|
||||
$dep = $this->attributeNameDeprecations[$name];
|
||||
if ($dep->getNewName()) {
|
||||
trigger_deprecation($dep->getPackage(), $dep->getVersion(), 'Getting attribute "%s" on a "%s" class is deprecated, get the "%s" attribute instead.', $name, static::class, $dep->getNewName());
|
||||
} else {
|
||||
trigger_deprecation($dep->getPackage(), $dep->getVersion(), 'Getting attribute "%s" on a "%s" class is deprecated.', $name, static::class);
|
||||
}
|
||||
}
|
||||
|
||||
return $this->attributes[$name];
|
||||
}
|
||||
|
||||
public function setAttribute(string $name, $value): void
|
||||
{
|
||||
$triggerDeprecation = \func_num_args() > 2 ? func_get_arg(2) : true;
|
||||
if ($triggerDeprecation && isset($this->attributeNameDeprecations[$name])) {
|
||||
$dep = $this->attributeNameDeprecations[$name];
|
||||
if ($dep->getNewName()) {
|
||||
trigger_deprecation($dep->getPackage(), $dep->getVersion(), 'Setting attribute "%s" on a "%s" class is deprecated, set the "%s" attribute instead.', $name, static::class, $dep->getNewName());
|
||||
} else {
|
||||
trigger_deprecation($dep->getPackage(), $dep->getVersion(), 'Setting attribute "%s" on a "%s" class is deprecated.', $name, static::class);
|
||||
}
|
||||
}
|
||||
|
||||
$this->attributes[$name] = $value;
|
||||
}
|
||||
|
||||
public function deprecateAttribute(string $name, NameDeprecation $dep): void
|
||||
{
|
||||
$this->attributeNameDeprecations[$name] = $dep;
|
||||
}
|
||||
|
||||
public function removeAttribute(string $name): void
|
||||
{
|
||||
unset($this->attributes[$name]);
|
||||
@@ -133,11 +162,31 @@ class Node implements \Countable, \IteratorAggregate
|
||||
throw new \LogicException(\sprintf('Node "%s" does not exist for Node "%s".', $name, static::class));
|
||||
}
|
||||
|
||||
$triggerDeprecation = \func_num_args() > 1 ? func_get_arg(1) : true;
|
||||
if ($triggerDeprecation && isset($this->nodeNameDeprecations[$name])) {
|
||||
$dep = $this->nodeNameDeprecations[$name];
|
||||
if ($dep->getNewName()) {
|
||||
trigger_deprecation($dep->getPackage(), $dep->getVersion(), 'Getting node "%s" on a "%s" class is deprecated, get the "%s" node instead.', $name, static::class, $dep->getNewName());
|
||||
} else {
|
||||
trigger_deprecation($dep->getPackage(), $dep->getVersion(), 'Getting node "%s" on a "%s" class is deprecated.', $name, static::class);
|
||||
}
|
||||
}
|
||||
|
||||
return $this->nodes[$name];
|
||||
}
|
||||
|
||||
public function setNode(string $name, self $node): void
|
||||
{
|
||||
$triggerDeprecation = \func_num_args() > 2 ? func_get_arg(2) : true;
|
||||
if ($triggerDeprecation && isset($this->nodeNameDeprecations[$name])) {
|
||||
$dep = $this->nodeNameDeprecations[$name];
|
||||
if ($dep->getNewName()) {
|
||||
trigger_deprecation($dep->getPackage(), $dep->getVersion(), 'Setting node "%s" on a "%s" class is deprecated, set the "%s" node instead.', $name, static::class, $dep->getNewName());
|
||||
} else {
|
||||
trigger_deprecation($dep->getPackage(), $dep->getVersion(), 'Setting node "%s" on a "%s" class is deprecated.', $name, static::class);
|
||||
}
|
||||
}
|
||||
|
||||
if (null !== $this->sourceContext) {
|
||||
$node->setSourceContext($this->sourceContext);
|
||||
}
|
||||
@@ -149,6 +198,11 @@ class Node implements \Countable, \IteratorAggregate
|
||||
unset($this->nodes[$name]);
|
||||
}
|
||||
|
||||
public function deprecateNode(string $name, NameDeprecation $dep): void
|
||||
{
|
||||
$this->nodeNameDeprecations[$name] = $dep;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
|
||||
@@ -12,10 +12,14 @@ namespace Twig\Tests\Node;
|
||||
*/
|
||||
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Symfony\Bridge\PhpUnit\ExpectDeprecationTrait;
|
||||
use Twig\Node\NameDeprecation;
|
||||
use Twig\Node\Node;
|
||||
|
||||
class NodeTest extends TestCase
|
||||
{
|
||||
use ExpectDeprecationTrait;
|
||||
|
||||
public function testToString()
|
||||
{
|
||||
// callable is not a supported type for a Node attribute, but Drupal uses some apparently
|
||||
@@ -23,4 +27,68 @@ class NodeTest extends TestCase
|
||||
|
||||
$this->assertEquals('Twig\Node\Node(value: \Closure)', (string) $node);
|
||||
}
|
||||
|
||||
public function testAttributeDeprecationIgnore()
|
||||
{
|
||||
$node = new Node([], ['foo' => false]);
|
||||
$node->deprecateAttribute('foo', new NameDeprecation('foo/bar', '2.0', 'bar'));
|
||||
|
||||
$this->assertSame(false, $node->getAttribute('foo', false));
|
||||
}
|
||||
|
||||
/**
|
||||
* @group legacy
|
||||
*/
|
||||
public function testAttributeDeprecationWithoutAlternative()
|
||||
{
|
||||
$node = new Node([], ['foo' => false]);
|
||||
$node->deprecateAttribute('foo', new NameDeprecation('foo/bar', '2.0'));
|
||||
|
||||
$this->expectDeprecation('Since foo/bar 2.0: Getting attribute "foo" on a "Twig\Node\Node" class is deprecated.');
|
||||
$this->assertSame(false, $node->getAttribute('foo'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @group legacy
|
||||
*/
|
||||
public function testAttributeDeprecationWithAlternative()
|
||||
{
|
||||
$node = new Node([], ['foo' => false]);
|
||||
$node->deprecateAttribute('foo', new NameDeprecation('foo/bar', '2.0', 'bar'));
|
||||
|
||||
$this->expectDeprecation('Since foo/bar 2.0: Getting attribute "foo" on a "Twig\Node\Node" class is deprecated, get the "bar" attribute instead.');
|
||||
$this->assertSame(false, $node->getAttribute('foo'));
|
||||
}
|
||||
|
||||
public function testNodeDeprecationIgnore()
|
||||
{
|
||||
$node = new Node(['foo' => $foo = new Node()], []);
|
||||
$node->deprecateNode('foo', new NameDeprecation('foo/bar', '2.0'));
|
||||
|
||||
$this->assertSame($foo, $node->getNode('foo', false));
|
||||
}
|
||||
|
||||
/**
|
||||
* @group legacy
|
||||
*/
|
||||
public function testNodeDeprecationWithoutAlternative()
|
||||
{
|
||||
$node = new Node(['foo' => $foo = new Node()], []);
|
||||
$node->deprecateNode('foo', new NameDeprecation('foo/bar', '2.0'));
|
||||
|
||||
$this->expectDeprecation('Since foo/bar 2.0: Getting node "foo" on a "Twig\Node\Node" class is deprecated.');
|
||||
$this->assertSame($foo, $node->getNode('foo'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @group legacy
|
||||
*/
|
||||
public function testNodeAttributeDeprecationWithAlternative()
|
||||
{
|
||||
$node = new Node(['foo' => $foo = new Node()], []);
|
||||
$node->deprecateNode('foo', new NameDeprecation('foo/bar', '2.0', 'bar'));
|
||||
|
||||
$this->expectDeprecation('Since foo/bar 2.0: Getting node "foo" on a "Twig\Node\Node" class is deprecated, get the "bar" node instead.');
|
||||
$this->assertSame($foo, $node->getNode('foo'));
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user