8000 [PropertyAccess]: Allow custom singularify class · symfony/symfony@8d95675 · GitHub
[go: up one dir, main page]

Skip to content

Commit 8d95675

Browse files
committed
[PropertyAccess]: Allow custom singularify class
| Q | A | ------------- | --- | Bug fix? | no | New feature? | yes | BC breaks? | no | Deprecations? | no | Tests pass? | yes | Fixed tickets | #13721, #13723 | License | MIT | Doc PR | WIP - [ ] Document new feature
1 parent 95a1e90 commit 8d95675

13 files changed

+215
-4
lines changed

src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -499,6 +499,7 @@ private function addPropertyAccessSection(ArrayNodeDefinition $rootNode)
499499
->children()
500500
->booleanNode('magic_call')->defaultFalse()->end()
501501
->booleanNode('throw_exception_on_invalid_index')->defaultFalse()->end()
502+
->scalarNode('property_singularify')->defaultNull()->end()
502503
->end()
503504
->end()
504505
->end()

src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -857,6 +857,7 @@ private function registerPropertyAccessConfiguration(array $config, ContainerBui
857857
->getDefinition('property_accessor')
858858
->replaceArgument(0, $config['magic_call'])
859859
->replaceArgument(1, $config['throw_exception_on_invalid_index'])
860+
->replaceArgument(2, $config['property_singularify'])
860861
;
861862
}
862863

src/Symfony/Bundle/FrameworkBundle/Resources/config/property_access.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
<service id="property_accessor" class="Symfony\Component\PropertyAccess\PropertyAccessor" >
99
<argument /> <!-- magicCall, set by the extension -->
1010
<argument /> <!-- throwExceptionOnInvalidIndex, set by the extension -->
11+
<argument /> <!-- propertySingularify, set by the extension -->
1112
</service>
1213
</services>
1314
</container>

src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/ConfigurationTest.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,7 @@ protected static function getBundleDefaultConfig()
171171
'property_access' => array(
172172
'magic_call' => false,
173173
'throw_exception_on_invalid_index' => false,
174+
'property_singularify' => null,
174175
),
175176
);
176177
}

src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/property_accessor.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,5 +4,6 @@
44
'property_access' => array(
55
'magic_call' => true,
66
'throw_exception_on_invalid_index' => true,
7+
'property_singularify' => '\Symfony\Component\PropertyAccess\Tests\Fixtures\TestSingularifyClass',
78
),
89
));

src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/property_accessor.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,4 @@ framework:
22
property_access:
33
magic_call: true
44
throw_exception_on_invalid_index: true
5+
property_singularify: \Symfony\Component\PropertyAccess\Tests\Fixtures\TestSingularifyClass

src/Symfony/Component/PropertyAccess/PropertyAccessor.php

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -36,14 +36,20 @@ class PropertyAccessor implements PropertyAccessorInterface
3636
*/
3737
private $ignoreInvalidIndices;
3838

39+
/**
40+
* @var StringSingularifyInterface
41+
*/
42+
private $propertySingularify = null;
43+
3944
/**
4045
* Should not be used by application code. Use
4146
* {@link PropertyAccess::createPropertyAccessor()} instead.
4247
*/
43-
public function __construct($magicCall = false, $throwExceptionOnInvalidIndex = false)
48+
public function __construct($magicCall = false, $throwExceptionOnInvalidIndex = false, $propertySingularify = null)
4449
{
4550
$this->magicCall = $magicCall;
4651
$this->ignoreInvalidIndices = !$throwExceptionOnInvalidIndex;
52+
$this->propertySingularify = $propertySingularify ?: new StringSingularifyEnglish();
4753
}
4854

4955
/**
@@ -389,7 +395,7 @@ private function writeProperty(&$object, $property, $value)
389395

390396
$reflClass = new \ReflectionClass($object);
391397
$camelized = $this->camelize($property);
392-
$singulars = (array) StringUtil::singularify($camelized);
398+
$singulars = (array) $this->propertySingularify->singularify($camelized);
393399

394400
if (is_array($value) || $value instanceof \Traversable) {
395401
$methods = $this->findAdderAndRemover($reflClass, $singulars);
@@ -517,7 +523,7 @@ private function isPropertyWritable($object, $property)
517523
return true;
518524
}
519525

520-
$singulars = (array) StringUtil::singularify($camelized);
526+
$singulars = (array) $this->propertySingularify->singularify($camelized);
521527

522528
// Any of the two methods is required, but not yet known
523529
if (null !== $this->findAdderAndRemover($reflClass, $singulars)) {

src/Symfony/Component/PropertyAccess/PropertyAccessorBuilder.php

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,11 @@ class PropertyAccessorBuilder
2828
*/
2929
private $throwExceptionOnInvalidIndex = false;
3030

31+
/**
32+
* @var StringSingularifyInterface
33+
*/
34+
private $propertySingularify = null;
35+
3136
/**
3237
* Enables the use of "__call" by the PropertyAccessor.
3338
*
@@ -97,13 +102,38 @@ public function isExceptionOnInvalidIndexEnabled()
97102
return $this->throwExceptionOnInvalidIndex;
98103
}
99104

105+
/**
106+
* Set the singularify class associated to the PropertyAccessor.
107+
*
108+
* @return PropertyAccessorBuilder The builder object
109+
*/
110+
public function setPropertySingularify(StringSingularifyInterface $propertySingularify)
111+
{
112+
$this->propertySingularify = $propertySingularify;
113+
114+
return $this;
115+
}
116+
117+
/**
118+
* Get the singularify class associated to the PropertyAccessor.
119+
*
120+
* @return StringSingularifyInterface The singularify class
121+
*/
122+
public function getPropertySingularify()
123+
{
124+
if (null === $this->propertySingularify) {
125+
$this->propertySingularify = new StringSingularifyEnglish();
126+
}
127+
return $this->propertySingularify;
128+
}
129+
100130
/**
101131
* Builds and returns a new PropertyAccessor object.
102132
*
103133
* @return PropertyAccessorInterface The built PropertyAccessor
104134
*/
105135
public function getPropertyAccessor()
106136
{
107-
return new PropertyAccessor($this->magicCall, $this->throwExceptionOnInvalidIndex);
137+
return new PropertyAccessor($this->magicCall, $this->throwExceptionOnInvalidIndex, $this->propertySingularify);
108138
}
109139
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Component\PropertyAccess;
13+
14+
/**
15+
* Creates singulars from plurals.
16+
*
17+
* @author Luis-Ramón López <lrlopez@gmail.com>
18+
*/
19+
class StringSingularifyEnglish implements StringSingularifyInterface
20+
{
21+
/**
22+
* @inheritdoc
23+
*/
24+
public function singularify($plural)
25+
{
26+
return StringUtil::singularify($plural);
27+
}
28+
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Component\PropertyAccess;
13+
14+
/**
15+
* Creates singulars from plurals.
16+
*
17+
* @author Luis-Ramón López <lrlopez@gmail.com>
18+
*/
19+
interface StringSingularifyInterface
20+
{
21+
/**
22+
* Returns the singular form of a word.
23+
*
24+
* If the method can't determine the form with certainty, an array of the
25+
* possible singulars is returned.
26+
*
27+
* @param string $plural A word in plural form
28+
*
29+
* @return string|array The singular form or an array of possible singular
30+
* forms
31+
*/
32+
public function singularify($plural);
33+
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Component\PropertyAccess\Tests\Fixtures;
13+
14+
15+
use Symfony\Component\PropertyAccess\StringSingularifyInterface;
16+
17+
class TestSingularifyClass implements StringSingularifyInterface
18+
{
19+
20+
/**
21+
* @inheritdoc
22+
*/
23+
public function singularify($plural)
24+
{
25+
return array($plural.'1', $plural.'2');
26+
}
27+
}

src/Symfony/Component/PropertyAccess/Tests/PropertyAccessorBuilderTest.php

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
namespace Symfony\Component\PropertyAccess\Tests;
1313

1414
use Symfony\Component\PropertyAccess\PropertyAccessorBuilder;
15+
use Symfony\Component\PropertyAccess\Tests\Fixtures\TestSingularifyClass;
1516

1617
class PropertyAccessorBuilderTest extends \PHPUnit_Framework_TestCase
1718
{
@@ -52,4 +53,9 @@ public function testGetPropertyAccessor()
5253
$this->assertInstanceOf('Symfony\Component\PropertyAccess\PropertyAccessor', $this->builder->getPropertyAccessor());
5354
$this->assertInstanceOf('Symfony\Component\PropertyAccess\PropertyAccessor', $this->builder->enableMagicCall()->getPropertyAccessor());
5455
}
56+
57+
public function testPropertySingularify()
58+
{
59+
$this->assertInstanceOf('Symfony\Component\PropertyAccess\Tests\Fixtures\TestSingularifyClass', $this->builder->setPropertySingularify(new TestSingularifyClass())->getPropertySingularify());
60+
}
5561
}
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Component\PropertyAccess\Tests;
13+
14+
use Symfony\Component\PropertyAccess\PropertyAccessor;
15+
use Symfony\Component\PropertyAccess\Tests\Fixtures\TestSingularifyClass;
16+
17+
class PropertyAccessorCollectionTestCustomSingularify_Car
18+
{
19+
private $axes;
20+
21+
public function __construct($axes = null)
22+
{
23+
$this->axes = $axes;
24+
}
25+
26+
// In the test, use a name which is returned by our custom singularify class
27+
public function addAxes2($axis)
28+
{
29+
$this->axes[] = $axis;
30+
}
31+
32+
public function removeAxes2($axis)
33+
{
34+
foreach ($this->axes as $key => $value) {
35+
if ($value === $axis) {
36+
unset($this->axes[$key]);
37+
38+
return;
39+
}
40+
}
41+
}
42+
43+
public function getAxes()
44+
{
45+
return $this->axes;
46+
}
47+
}
48+
49+
class PropertyAccessorCollectionCustomSingularifyTest extends \PHPUnit_Framework_TestCase
50+
{
51+
/**
52+
* @var PropertyAccessor
53+
*/
54+
protected $propertyAccessor;
55+
56+
protected function setUp()
57+
{
58+
$this->propertyAccessor = new PropertyAccessor(false, false, new TestSingularifyClass());
59+
}
60+
61+
public function testSetValueCallsAdderForCollectionsWithCustomSingularify()
62+
{
63+
$axesBefore = array(1 => 'second', 3 => 'fourth', 4 => 'fifth');
64+
$axesMerged = array(1 => 'first', 2 => 'second', 3 => 'third');
65+
$axesAfter = array(1 => 'second', 5 => 'first', 6 => 'third');
66+
67+
// Don't use a mock in order to test whether the collections are
68+
// modified while iterating them
69+
$car = new PropertyAccessorCollectionTestCustomSingularify_Car($axesBefore);
70+
71+
$this->propertyAccessor->setValue($car, 'axes', $axesMerged);
72+
73+
$this->assertEquals($axesAfter, $car->getAxes());
74+
}
75+
}

0 commit comments

Comments
 (0)
0