Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 9d3621e

Browse files
committed
bug #28878 [OptionsResolver] Trigger deprecation only if the option is used (yceruto)
This PR was merged into the 4.2-dev branch. Discussion ---------- [OptionsResolver] Trigger deprecation only if the option is used | Q | A | ------------- | --- | Branch? | master | Bug fix? | no | New feature? | no | BC breaks? | no | Deprecations? | no | Tests pass? | yes | Fixed tickets | #28848 | License | MIT | Doc PR | symfony/symfony-docs#10496 It's true that showing a deprecation message when the option is not used is a bit annoying and it would be heavy to get rid of it. Now, a deprecated option is triggered only when it's provided by the user or each time is being called from a lazy evaluation (except for deprecations based on the value, they're triggered only when provided by the user). Commits ------- 1af23c9 [OptionsResolver] Trigger deprecation only if the option is used
2 parents 01dfca1 + 1af23c9 commit 9d3621e

File tree

3 files changed

+131
-19
lines changed

3 files changed

+131
-19
lines changed

src/Symfony/Component/OptionsResolver/Options.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@
1616
*
1717
* @author Bernhard Schussek <[email protected]>
1818
* @author Tobias Schultze <http://tobion.de>
19+
*
20+
* @method mixed offsetGet(string $option, bool $triggerDeprecation = true)
1921
*/
2022
interface Options extends \ArrayAccess, \Countable
2123
{

src/Symfony/Component/OptionsResolver/OptionsResolver.php

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,11 @@ class OptionsResolver implements Options
8888
*/
8989
private $deprecated = array();
9090

91+
/**
92+
* The list of options provided by the user.
93+
*/
94+
private $given = array();
95+
9196
/**
9297
* Whether the instance is locked for reading.
9398
*
@@ -744,6 +749,7 @@ public function resolve(array $options = array())
744749

745750
// Override options set by the user
746751
foreach ($options as $option => $value) {
752+
$clone->given[$option] = true;
747753
$clone->defaults[$option] = $value;
748754
unset($clone->resolved[$option], $clone->lazy[$option]);
749755
}
@@ -772,7 +778,8 @@ public function resolve(array $options = array())
772778
/**
773779
* Returns the resolved value of an option.
774780
*
775-
* @param string $option The option name
781+
* @param string $option The option name
782+
* @param bool $triggerDeprecation Whether to trigger the deprecation or not (true by default)
776783
*
777784
* @return mixed The option value
778785
*
@@ -784,14 +791,20 @@ public function resolve(array $options = array())
784791
* @throws OptionDefinitionException If there is a cyclic dependency between
785792
* lazy options and/or normalizers
786793
*/
787-
public function offsetGet($option)
794+
public function offsetGet($option/*, bool $triggerDeprecation = true*/)
788795
{
789796
if (!$this->locked) {
790797
throw new AccessException('Array access is only supported within closures of lazy options and normalizers.');
791798
}
792799

800+
$triggerDeprecation = 1 === \func_num_args() || \func_get_arg(1);
801+
793802
// Shortcut for resolved options
794803
if (array_key_exists($option, $this->resolved)) {
804+
if ($triggerDeprecation && isset($this->deprecated[$option]) && \is_string($this->deprecated[$option])) {
805+
@trigger_error(strtr($this->deprecated[$option], array('%name%' => $option)), E_USER_DEPRECATED);
806+
}
807+
795808
return $this->resolved[$option];
796809
}
797810

@@ -920,7 +933,8 @@ public function offsetGet($option)
920933
}
921934

922935
// Check whether the option is deprecated
923-
if (isset($this->deprecated[$option])) {
936+
// and it is provided by the user or is being called from a lazy evaluation
937+
if ($triggerDeprecation && isset($this->deprecated[$option]) && (isset($this->given[$option]) || ($this->calling && \is_string($this->deprecated[$option])))) {
924938
$deprecationMessage = $this->deprecated[$option];
925939

926940
if ($deprecationMessage instanceof \Closure) {

src/Symfony/Component/OptionsResolver/Tests/OptionsResolverTest.php

Lines changed: 112 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -491,12 +491,12 @@ public function testSetDeprecatedFailsIfInvalidDeprecationMessageType()
491491
public function testLazyDeprecationFailsIfInvalidDeprecationMessageType()
492492
{
493493
$this->resolver
494-
->setDefault('foo', true)
494+
->setDefined('foo')
495495
->setDeprecated('foo', function (Options $options, $value) {
496496
return false;
497497
})
498498
;
499-
$this->resolver->resolve();
499+
$this->resolver->resolve(array('foo' => null));
500500
}
501501

502502
/**
@@ -506,16 +506,15 @@ public function testLazyDeprecationFailsIfInvalidDeprecationMessageType()
506506
public function testFailsIfCyclicDependencyBetweenDeprecation()
507507
{
508508
$this->resolver
509-
->setDefault('foo', null)
510-
->setDefault('bar', null)
509+
->setDefined(array('foo', 'bar'))
511510
->setDeprecated('foo', function (Options $options, $value) {
512511
$options['bar'];
513512
})
514513
->setDeprecated('bar', function (Options $options, $value) {
515514
$options['foo'];
516515
})
517516
;
518-
$this->resolver->resolve();
517+
$this->resolver->resolve(array('foo' => null, 'bar' => null));
519518
}
520519

521520
public function testIsDeprecated()
@@ -539,10 +538,15 @@ public function testIsNotDeprecatedIfEmptyString()
539538
/**
540539
* @dataProvider provideDeprecationData
541540
*/
542-
public function testDeprecationMessages(\Closure $configureOptions, array $options, ?array $expectedError)
541+
public function testDeprecationMessages(\Closure $configureOptions, array $options, ?array $expectedError, int $expectedCount)
543542
{
543+
$count = 0;
544544
error_clear_last();
545-
set_error_handler(function () { return false; });
545+
set_error_handler(function () use (&$count) {
546+
++$count;
547+
548+
return false;
549+
});
546550
$e = error_reporting(0);
547551

548552
$configureOptions($this->resolver);
@@ -555,6 +559,7 @@ public function testDeprecationMessages(\Closure $configureOptions, array $optio
555559
unset($lastError['file'], $lastError['line']);
556560

557561
$this->assertSame($expectedError, $lastError);
562+
$this->assertSame($expectedCount, $count);
558563
}
559564

560565
public function provideDeprecationData()
@@ -571,6 +576,7 @@ function (OptionsResolver $resolver) {
571576
'type' => E_USER_DEPRECATED,
572577
'message' => 'The option "foo" is deprecated.',
573578
),
579+
1,
574580
);
575581

576582
yield 'It deprecates an option with custom message' => array(
@@ -588,20 +594,27 @@ function (OptionsResolver $resolver) {
588594
'type' => E_USER_DEPRECATED,
589595
'message' => 'The option "foo" is deprecated, use "bar" option instead.',
590596
),
597+
2,
591598
);
592599

593-
yield 'It deprecates a missing option with default value' => array(
600+
yield 'It deprecates an option evaluated in another definition' => array(
594601
function (OptionsResolver $resolver) {
602+
// defined by superclass
595603
$resolver
596-
->setDefaults(array('foo' => null, 'bar' => null))
604+
->setDefault('foo', null)
597605
->setDeprecated('foo')
598606
;
607+
// defined by subclass
608+
$resolver->setDefault('bar', function (Options $options) {
609+
return $options['foo']; // It triggers a deprecation
610+
});
599611
},
600-
array('bar' => 'baz'),
612+
array(),
601613
array(
602614
'type' => E_USER_DEPRECATED,
603615
'message' => 'The option "foo" is deprecated.',
604616
),
617+
1,
605618
);
606619

607620
yield 'It deprecates allowed type and value' => array(
@@ -623,20 +636,46 @@ function (OptionsResolver $resolver) {
623636
'type' => E_USER_DEPRECATED,
624637
'message' => 'Passing an instance of "stdClass" to option "foo" is deprecated, pass its FQCN instead.',
625638
),
639+
1,
626640
);
627641

628-
yield 'It ignores deprecation for missing option without default value' => array(
642+
yield 'It triggers a deprecation based on the value only if option is provided by the user' => array(
629643
function (OptionsResolver $resolver) {
630644
$resolver
631-
->setDefined(array('foo', 'bar'))
632-
->setDeprecated('foo')
645+
->setDefined('foo')
646+
->setAllowedTypes('foo', array('null', 'bool'))
647+
->setDeprecated('foo', function (Options $options, $value) {
648+
if (!\is_bool($value)) {
649+
return 'Passing a value different than true or false is deprecated.';
650+
}
651+
652+
return '';
653+
})
654+
->setDefault('baz', null)
655+
->setAllowedTypes('baz', array('null', 'int'))
656+
->setDeprecated('baz', function (Options $options, $value) {
657+
if (!\is_int($value)) {
658+
return 'Not passing an integer is deprecated.';
659+
}
660+
661+
return '';
662+
})
663+
->setDefault('bar', function (Options $options) {
664+
$options['baz']; // It does not triggers a deprecation
665+
666+
return $options['foo']; // It does not triggers a deprecation
667+
})
633668
;
634669
},
635-
array('bar' => 'baz'),
636-
null,
670+
array('foo' => null), // It triggers a deprecation
671+
array(
672+
'type' => E_USER_DEPRECATED,
673+
'message' => 'Passing a value different than true or false is deprecated.',
674+
),
675+
1,
637676
);
638677

639-
yield 'It ignores deprecation if closure returns an empty string' => array(
678+
yield 'It ignores a deprecation if closure returns an empty string' => array(
640679
function (OptionsResolver $resolver) {
641680
$resolver
642681
->setDefault('foo', null)
@@ -647,6 +686,7 @@ function (OptionsResolver $resolver) {
647686
},
648687
array('foo' => Bar::class),
649688
null,
689+
0,
650690
);
651691

652692
yield 'It deprecates value depending on other option value' => array(
@@ -668,6 +708,62 @@ function (OptionsResolver $resolver) {
668708
'type' => E_USER_DEPRECATED,
669709
'message' => 'Using the "date_format" option when the "widget" option is set to "single_text" is deprecated.',
670710
),
711+
1,
712+
);
713+
714+
yield 'It triggers a deprecation for each evaluation' => array(
715+
function (OptionsResolver $resolver) {
716+
$resolver
717+
// defined by superclass
718+
->setDefined('foo')
719+
->setDeprecated('foo')
720+
// defined by subclass
721+
->setDefault('bar', function (Options $options) {
722+
return $options['foo']; // It triggers a deprecation
723+
})
724+
->setNormalizer('bar', function (Options $options, $value) {
725+
$options['foo']; // It triggers a deprecation
726+
$options['foo']; // It triggers a deprecation
727+
728+
return $value;
729+
})
730+
;
731+
},
732+
array('foo' => 'baz'), // It triggers a deprecation
733+
array(
734+
'type' => E_USER_DEPRECATED,
735+
'message' => 'The option "foo" is deprecated.',
736+
),
737+
4,
738+
);
739+
740+
yield 'It ignores a deprecation if no option is provided by the user' => array(
741+
function (OptionsResolver $resolver) {
742+
$resolver
743+
->setDefined('foo')
744+
->setDefault('bar', null)
745+
->setDeprecated('foo')
746+
->setDeprecated('bar')
747+
;
748+
},
749+
array(),
750+
null,
751+
0,
752+
);
753+
754+
yield 'It explicitly ignores a depreciation' => array(
755+
function (OptionsResolver $resolver) {
756+
$resolver
757+
->setDefault('foo', null)
758+
->setDeprecated('foo')
759+
->setDefault('bar', function (Options $options) {
760+
return $options->offsetGet('foo', false);
761+
})
762+
;
763+
},
764+
array(),
765+
null,
766+
0,
671767
);
672768
}
673769

0 commit comments

Comments
 (0)