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

Skip to content

Commit 98621f4

Browse files
committed
[Form] optimized LazyChoiceList
1 parent 86b2ff1 commit 98621f4

File tree

2 files changed

+136
-38
lines changed

2 files changed

+136
-38
lines changed

src/Symfony/Component/Form/ChoiceList/LazyChoiceList.php

Lines changed: 78 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -45,9 +45,18 @@ class LazyChoiceList implements ChoiceListInterface
4545

4646
/**
4747
* @var ChoiceListInterface|null
48+
*
49+
* @deprecated Since 3.1, to be remove in 4.0. Cache the choice list in the {@link ChoiceLoaderInterface} instead.
4850
*/
4951
private $loadedList;
5052

53+
/**
54+
* @var bool
55+
*
56+
* @deprecated Flag used for BC layer since 3.1. To be removed in 4.0.
57+
*/
58+
private $loaded = false;
59+
5160
/**
5261
* Creates a lazily-loaded list using the given loader.
5362
*
@@ -70,70 +79,125 @@ public function __construct(ChoiceLoaderInterface $loader, callable $value = nul
7079
*/
7180
public function getChoices()
7281
{
73-
if (!$this->loadedList) {
74-
$this->loadedList = $this->loader->loadChoiceList($this->value);
82+
if ($this->loaded) {
83+
// We can safely invoke the {@link ChoiceLoaderInterface} assuming it has the list
84+
// in cache when the lazy list is already loaded
85+
if ($this->loadedList !== $this->loader->loadChoiceList($this->value)) {
86+
@trigger_error(sprintf('Caching the choice list in %s is deprecated since 3.1 and will not happen in 4.0. Cache the list in the %s instead.', __CLASS__, ChoiceLoaderInterface::class));
87+
}
88+
89+
return $this->loadedList->getChoices();
7590
}
7691

92+
// BC
93+
$this->loadedList = $this->loader->loadChoiceList($this->value);
94+
$this->loaded = true;
95+
7796
return $this->loadedList->getChoices();
97+
// In 4.0 keep the following line only:
98+
// return $this->loader->loadChoiceList($this->value)->getChoices()
7899
}
79100

80101
/**
81102
* {@inheritdoc}
82103
*/
83104
public function getValues()
84105
{
85-
if (!$this->loadedList) {
86-
$this->loadedList = $this->loader->loadChoiceList($this->value);
106+
if ($this->loaded) {
107+
// Check whether the loader has the same cache
108+
if ($this->loadedList !== $this->loader->loadChoiceList($this->value)) {
109+
@trigger_error(sprintf('Caching the choice list in %s is deprecated since 3.1 and will not happen in 4.0. Cache the list in the %s instead.', __CLASS__, ChoiceLoaderInterface::class));
110+
}
111+
112+
return $this->loadedList->getValues();
87113
}
88114

115+
// BC
116+
$this->loadedList = $this->loader->loadChoiceList($this->value);
117+
$this->loaded = true;
118+
89119
return $this->loadedList->getValues();
120+
// In 4.0 keep the following line only:
121+
// return $this->loader->loadChoiceList($this->value)->getValues()
90122
}
91123

92124
/**
93125
* {@inheritdoc}
94126
*/
95127
public function getStructuredValues()
96128
{
97-
if (!$this->loadedList) {
98-
$this->loadedList = $this->loader->loadChoiceList($this->value);
129+
if ($this->loaded) {
130+
// Check whether the loader has the same cache
131+
if ($this->loadedList !== $this->loader->loadChoiceList($this->value)) {
132+
@trigger_error(sprintf('Caching the choice list in %s is deprecated since 3.1 and will not happen in 4.0. Cache the list in the %s instead.', __CLASS__, ChoiceLoaderInterface::class));
133+
}
134+
135+
return $this->loadedList->getStructuredValues();
99136
}
100137

138+
// BC
139+
$this->loadedList = $this->loader->loadChoiceList($this->value);
140+
$this->loaded = true;
141+
101142
return $this->loadedList->getStructuredValues();
143+
// In 4.0 keep the following line only:
144+
// return $this->loader->loadChoiceList($this->value)->getStructuredValues();
102145
}
103146

104147
/**
105148
* {@inheritdoc}
106149
*/
107150
public function getOriginalKeys()
108151
{
109-
if (!$this->loadedList) {
110-
$this->loadedList = $this->loader->loadChoiceList($this->value);
152+
if ($this->loaded) {
153+
// Check whether the loader has the same cache
154+
if ($this->loadedList !== $this->loader->loadChoiceList($this->value)) {
155+
@trigger_error(sprintf('Caching the choice list in %s is deprecated since 3.1 and will not happen in 4.0. Cache the list in the %s instead.', __CLASS__, ChoiceLoaderInterface::class));
156+
}
157+
158+
return $this->loadedList->getOriginalKeys();
111159
}
112160

161+
// BC
162+
$this->loadedList = $this->loader->loadChoiceList($this->value);
163+
$this->loaded = true;
164+
113165
return $this->loadedList->getOriginalKeys();
166+
// In 4.0 keep the following line only:
167+
// return $this->loader->loadChoiceList($this->value)->getOriginalKeys();
114168
}
115169

116170
/**
117171
* {@inheritdoc}
118172
*/
119173
public function getChoicesForValues(array $values)
120174
{
121-
if (!$this->loadedList) {
122-
return $this->loader->loadChoicesForValues($values, $this->value);
175+
if ($this->loaded) {
176+
// Check whether the loader has the same cache
177+
if ($this->loadedList !== $this->loader->loadChoiceList($this->value)) {
178+
@trigger_error(sprintf('Caching the choice list in %s is deprecated since 3.1 and will not happen in 4.0. Cache the list in the %s instead.', __CLASS__, ChoiceLoaderInterface::class));
179+
}
180+
181+
return $this->loadedList->getChoicesForValues($values);
123182
}
124183

125-
return $this->loadedList->getChoicesForValues($values);
184+
return $this->loader->loadChoicesForValues($values, $this->value);
126185
}
127186

128187
/**
129188
* {@inheritdoc}
130189
*/
131190
public function getValuesForChoices(array $choices)
132191
{
133-
if (!$this->loadedList) {
134-
return $this->loader->loadValuesForChoices($choices, $this->value);
192+
if ($this->loaded) {
193+
// Check whether the loader has the same cache
194+
if ($this->loadedList !== $this->loader->loadChoiceList($this->value)) {
195+
@trigger_error(sprintf('Caching the choice list in %s is deprecated since 3.1 and will not happen in 4.0. Cache the list in the %s instead.', __CLASS__, ChoiceLoaderInterface::class));
196+
}
197+
198+
return $this->loadedList->getValuesForChoices($choices);
135199
}
136200

137-
return $this->loadedList->getValuesForChoices($choices);
201+
return $this->loader->loadValuesForChoices($choices, $this->value);
138202
}
139203
}

src/Symfony/Component/Form/Tests/ChoiceList/LazyChoiceListTest.php

Lines changed: 58 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111

1212
namespace Symfony\Component\Form\Tests\ChoiceList;
1313

14+
use Symfony\Component\Form\ChoiceList\ArrayChoiceList;
1415
use Symfony\Component\Form\ChoiceList\LazyChoiceList;
1516

1617
/**
@@ -26,7 +27,7 @@ class LazyChoiceListTest extends \PHPUnit_Framework_TestCase
2627
/**
2728
* @var \PHPUnit_Framework_MockObject_MockObject
2829
*/
29-
private $innerList;
30+
private $loadedList;
3031

3132
/**
3233
* @var \PHPUnit_Framework_MockObject_MockObject
@@ -37,65 +38,93 @@ class LazyChoiceListTest extends \PHPUnit_Framework_TestCase
3738

3839
protected function setUp()
3940
{
40-
$this->innerList = $this->getMock('Symfony\Component\Form\ChoiceList\ChoiceListInterface');
41+
$this->loadedList = $this->getMock('Symfony\Component\Form\ChoiceList\ChoiceListInterface');
4142
$this->loader = $this->getMock('Symfony\Component\Form\ChoiceList\Loader\ChoiceLoaderInterface');
4243
$this->value = function () {};
4344
$this->list = new LazyChoiceList($this->loader, $this->value);
4445
}
4546

46-
public function testGetChoicesLoadsInnerListOnFirstCall()
47+
public function testGetChoiceLoadersLoadsLoadedListOnFirstCall()
4748
{
48-
$this->loader->expects($this->once())
49+
$this->loader->expects($this->exactly(2))
50+
->method('loadChoiceList')
51+
->with($this->value)
52+
->will($this->returnValue($this->loadedList));
53+
54+
// The same list is returned by the loader
55+
$this->loadedList->expects($this->exactly(2))
56+
->method('getChoices')
57+
->will($this->returnValue('RESULT'));
58+
59+
$this->assertSame('RESULT', $this->list->getChoices());
60+
$this->assertSame('RESULT', $this->list->getChoices());
61+
}
62+
63+
/**
64+
* @group legacy
65+
*/
66+
public function testGetChoicesUsesLoadedListWhenLoaderDoesNotCacheChoiceListOnFirstCall()
67+
{
68+
$this->loader->expects($this->at(0))
69+
->method('loadChoiceList')
70+
->with($this->value)
71+
->willReturn($this->loadedList);
72+
73+
$this->loader->expects($this->at(1))
4974
->method('loadChoiceList')
5075
->with($this->value)
51-
->will($this->returnValue($this->innerList));
76+
->willReturn(new ArrayChoiceList(array('a', 'b')));
5277

53-
$this->innerList->expects($this->exactly(2))
78+
// The same list is returned by the lazy choice list
79+
$this->loadedList->expects($this->exactly(2))
5480
->method('getChoices')
5581
->will($this->returnValue('RESULT'));
5682

5783
$this->assertSame('RESULT', $this->list->getChoices());
5884
$this->assertSame('RESULT', $this->list->getChoices());
5985
}
6086

61-
public function testGetValuesLoadsInnerListOnFirstCall()
87+
public function testGetValuesLoadsLoadedListOnFirstCall()
6288
{
63-
$this->loader->expects($this->once())
89+
$this->loader->expects($this->exactly(2))
6490
->method('loadChoiceList')
6591
->with($this->value)
66-
->will($this->returnValue($this->innerList));
92+
->will($this->returnValue($this->loadedList));
6793

68-
$this->innerList->expects($this->exactly(2))
94+
// The same list is returned by the loader
95+
$this->loadedList->expects($this->exactly(2))
6996
->method('getValues')
7097
->will($this->returnValue('RESULT'));
7198

7299
$this->assertSame('RESULT', $this->list->getValues());
73100
$this->assertSame('RESULT', $this->list->getValues());
74101
}
75102

76-
public function testGetStructuredValuesLoadsInnerListOnFirstCall()
103+
public function testGetStructuredValuesLoadsLoadedListOnFirstCall()
77104
{
78-
$this->loader->expects($this->once())
105+
$this->loader->expects($this->exactly(2))
79106
->method('loadChoiceList')
80107
->with($this->value)
81-
->will($this->returnValue($this->innerList));
108+
->will($this->returnValue($this->loadedList));
82109

83-
$this->innerList->expects($this->exactly(2))
110+
// The same list is returned by the loader
111+
$this->loadedList->expects($this->exactly(2))
84112
->method('getStructuredValues')
85113
->will($this->returnValue('RESULT'));
86114

87115
$this->assertSame('RESULT', $this->list->getStructuredValues());
88116
$this->assertSame('RESULT', $this->list->getStructuredValues());
89117
}
90118

91-
public function testGetOriginalKeysLoadsInnerListOnFirstCall()
119+
public function testGetOriginalKeysLoadsLoadedListOnFirstCall()
92120
{
93-
$this->loader->expects($this->once())
121+
$this->loader->expects($this->exactly(2))
94122
->method('loadChoiceList')
95123
->with($this->value)
96-
->will($this->returnValue($this->innerList));
124+
->will($this->returnValue($this->loadedList));
97125

98-
$this->innerList->expects($this->exactly(2))
126+
// The same list is returned by the loader
127+
$this->loadedList->expects($this->exactly(2))
99128
->method('getOriginalKeys')
100129
->will($this->returnValue('RESULT'));
101130

@@ -116,15 +145,17 @@ public function testGetChoicesForValuesForwardsCallIfListNotLoaded()
116145

117146
public function testGetChoicesForValuesUsesLoadedList()
118147
{
119-
$this->loader->expects($this->once())
148+
$this->loader->expects($this->exactly(3))
120149
->method('loadChoiceList')
121150
->with($this->value)
122-
->will($this->returnValue($this->innerList));
151+
// For BC, the same choice loaded list is returned 3 times
152+
// It should only twice in 4.0
153+
->will($this->returnValue($this->loadedList));
123154

124155
$this->loader->expects($this->never())
125156
->method('loadChoicesForValues');
126157

127-
$this->innerList->expects($this->exactly(2))
158+
$this->loadedList->expects($this->exactly(2))
128159
->method('getChoicesForValues')
129160
->with(array('a', 'b'))
130161
->will($this->returnValue('RESULT'));
@@ -136,6 +167,7 @@ public function testGetChoicesForValuesUsesLoadedList()
136167
$this->assertSame('RESULT', $this->list->getChoicesForValues(array('a', 'b')));
137168
}
138169

170+
// To be remove in 4.0
139171
public function testGetValuesForChoicesForwardsCallIfListNotLoaded()
140172
{
141173
$this->loader->expects($this->exactly(2))
@@ -149,15 +181,17 @@ public function testGetValuesForChoicesForwardsCallIfListNotLoaded()
149181

150182
public function testGetValuesForChoicesUsesLoadedList()
151183
{
152-
$this->loader->expects($this->once())
184+
$this->loader->expects($this->exactly(3))
153185
->method('loadChoiceList')
154186
->with($this->value)
155-
->will($this->returnValue($this->innerList));
187+
// For BC, the same choice loaded list is returned 3 times
188+
// It should only twice in 4.0
189+
->will($this->returnValue($this->loadedList));
156190

157191
$this->loader->expects($this->never())
158192
->method('loadValuesForChoices');
159193

160-
$this->innerList->expects($this->exactly(2))
194+
$this->loadedList->expects($this->exactly(2))
161195
->method('getValuesForChoices')
162196
->with(array('a', 'b'))
163197
->will($this->returnValue('RESULT'));

0 commit comments

Comments
 (0)