[Serializer] Name converter support
This commit is contained in:
parent
fef2bd4812
commit
e14854fe22
@ -59,3 +59,27 @@ Form
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Serializer
|
||||
----------
|
||||
|
||||
* The `setCamelizedAttributes()` method of the
|
||||
`Symfony\Component\Serializer\Normalizer\GetSetMethodNormalizer` and
|
||||
`Symfony\Component\Serializer\Normalizer\PropertyNormalizer` classes is marked
|
||||
as deprecated in favor of the new NameConverter system.
|
||||
|
||||
Before:
|
||||
|
||||
```php
|
||||
$normalizer->setCamelizedAttributes(array('foo_bar', 'bar_foo'));
|
||||
```
|
||||
|
||||
After:
|
||||
|
||||
```php
|
||||
use Symfony\Component\Serializer\NameConverter\CamelCaseToSnakeCaseNameConverter;
|
||||
use Symfony\Component\Serializer\Normalizer\GetSetMethodNormalizer;
|
||||
|
||||
$nameConverter = new CamelCaseToSnakeCaseNameConverter(array('fooBar', 'barFoo'));
|
||||
$normalizer = new GetSetMethodNormalizer(null, $nameConverter);
|
||||
```
|
||||
|
@ -0,0 +1,82 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Serializer\NameConverter;
|
||||
|
||||
/**
|
||||
* CamelCase to Underscore name converter.
|
||||
*
|
||||
* @author Kévin Dunglas <dunglas@gmail.com>
|
||||
*/
|
||||
class CamelCaseToSnakeCaseNameConverter implements NameConverterInterface
|
||||
{
|
||||
/**
|
||||
* @var array|null
|
||||
*/
|
||||
private $attributes;
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
private $lowerCamelCase;
|
||||
|
||||
/**
|
||||
* @param null|array $attributes The list of attributes to rename or null for all attributes.
|
||||
* @param bool $lowerCamelCase Use lowerCamelCase style.
|
||||
*/
|
||||
public function __construct(array $attributes = null, $lowerCamelCase = true)
|
||||
{
|
||||
$this->attributes = $attributes;
|
||||
$this->lowerCamelCase = $lowerCamelCase;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function normalize($propertyName)
|
||||
{
|
||||
if (null === $this->attributes || in_array($propertyName, $this->attributes)) {
|
||||
$snakeCasedName = '';
|
||||
|
||||
$len = strlen($propertyName);
|
||||
for ($i = 0; $i < $len; $i++) {
|
||||
if (ctype_upper($propertyName[$i])) {
|
||||
$snakeCasedName .= '_'.strtolower($propertyName[$i]);
|
||||
} else {
|
||||
$snakeCasedName .= strtolower($propertyName[$i]);
|
||||
}
|
||||
}
|
||||
|
||||
return $snakeCasedName;
|
||||
}
|
||||
|
||||
return $propertyName;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function denormalize($propertyName)
|
||||
{
|
||||
$camelCasedName = preg_replace_callback('/(^|_|\.)+(.)/', function ($match) {
|
||||
return ('.' === $match[1] ? '_' : '').strtoupper($match[2]);
|
||||
}, $propertyName);
|
||||
|
||||
if ($this->lowerCamelCase) {
|
||||
$camelCasedName = lcfirst($camelCasedName);
|
||||
}
|
||||
|
||||
if (null === $this->attributes || in_array($camelCasedName, $this->attributes)) {
|
||||
return $this->lowerCamelCase ? lcfirst($camelCasedName) : $camelCasedName;
|
||||
}
|
||||
|
||||
return $propertyName;
|
||||
}
|
||||
}
|
@ -0,0 +1,36 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Serializer\NameConverter;
|
||||
|
||||
/**
|
||||
* Defines the interface for property name converters.
|
||||
*
|
||||
* @author Kévin Dunglas <dunglas@gmail.com>
|
||||
*/
|
||||
interface NameConverterInterface
|
||||
{
|
||||
/**
|
||||
* Converts a property name to its normalized value.
|
||||
*
|
||||
* @param string $propertyName
|
||||
* @return string
|
||||
*/
|
||||
public function normalize($propertyName);
|
||||
|
||||
/**
|
||||
* Converts a property name to its denormalized value.
|
||||
*
|
||||
* @param string $propertyName
|
||||
* @return string
|
||||
*/
|
||||
public function denormalize($propertyName);
|
||||
}
|
@ -14,6 +14,8 @@ namespace Symfony\Component\Serializer\Normalizer;
|
||||
use Symfony\Component\Serializer\Exception\CircularReferenceException;
|
||||
use Symfony\Component\Serializer\Exception\InvalidArgumentException;
|
||||
use Symfony\Component\Serializer\Mapping\Factory\ClassMetadataFactory;
|
||||
use Symfony\Component\Serializer\NameConverter\CamelCaseToSnakeCaseNameConverter;
|
||||
use Symfony\Component\Serializer\NameConverter\NameConverterInterface;
|
||||
|
||||
/**
|
||||
* Normalizer implementation.
|
||||
@ -25,6 +27,7 @@ abstract class AbstractNormalizer extends SerializerAwareNormalizer implements N
|
||||
protected $circularReferenceLimit = 1;
|
||||
protected $circularReferenceHandler;
|
||||
protected $classMetadataFactory;
|
||||
protected $nameConverter;
|
||||
protected $callbacks = array();
|
||||
protected $ignoredAttributes = array();
|
||||
protected $camelizedAttributes = array();
|
||||
@ -32,11 +35,13 @@ abstract class AbstractNormalizer extends SerializerAwareNormalizer implements N
|
||||
/**
|
||||
* Sets the {@link ClassMetadataFactory} to use.
|
||||
*
|
||||
* @param ClassMetadataFactory $classMetadataFactory
|
||||
* @param ClassMetadataFactory|null $classMetadataFactory
|
||||
* @param NameConverterInterface|null $nameConverter
|
||||
*/
|
||||
public function __construct(ClassMetadataFactory $classMetadataFactory = null)
|
||||
public function __construct(ClassMetadataFactory $classMetadataFactory = null, NameConverterInterface $nameConverter = null)
|
||||
{
|
||||
$this->classMetadataFactory = $classMetadataFactory;
|
||||
$this->nameConverter = $nameConverter;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -114,13 +119,28 @@ abstract class AbstractNormalizer extends SerializerAwareNormalizer implements N
|
||||
/**
|
||||
* Set attributes to be camelized on denormalize.
|
||||
*
|
||||
* @deprecated Deprecated since version 2.7, to be removed in 3.0. Use Symfony\Component\Serializer\NameConverter\CamelCaseToSnakeCaseNameConverter instead.
|
||||
*
|
||||
* @param array $camelizedAttributes
|
||||
*
|
||||
* @return self
|
||||
*/
|
||||
public function setCamelizedAttributes(array $camelizedAttributes)
|
||||
{
|
||||
$this->camelizedAttributes = $camelizedAttributes;
|
||||
trigger_error(sprintf('%s is deprecated since version 2.7 and will be removed in 3.0. Use Symfony\Component\Serializer\NameConverter\CamelCaseToSnakeCaseNameConverter instead.', __METHOD__), E_USER_DEPRECATED);
|
||||
|
||||
if ($this->nameConverter && !$this->nameConverter instanceof CamelCaseToSnakeCaseNameConverter) {
|
||||
throw new \LogicException(sprintf('%s cannot be called if a custom Name Converter is defined.', __METHOD__));
|
||||
}
|
||||
|
||||
$attributes = array();
|
||||
foreach ($camelizedAttributes as $camelizedAttribute) {
|
||||
$attributes[] = lcfirst(preg_replace_callback('/(^|_|\.)+(.)/', function ($match) {
|
||||
return ('.' === $match[1] ? '_' : '').strtoupper($match[2]);
|
||||
}, $camelizedAttribute));
|
||||
}
|
||||
|
||||
$this->nameConverter = new CamelCaseToSnakeCaseNameConverter($attributes);
|
||||
|
||||
return $this;
|
||||
}
|
||||
@ -178,18 +198,17 @@ abstract class AbstractNormalizer extends SerializerAwareNormalizer implements N
|
||||
/**
|
||||
* Format an attribute name, for example to convert a snake_case name to camelCase.
|
||||
*
|
||||
* @deprecated Deprecated since version 2.7, to be removed in 3.0. Use Symfony\Component\Serializer\NameConverter\CamelCaseToSnakeCaseNameConverter instead.
|
||||
*
|
||||
* @param string $attributeName
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function formatAttribute($attributeName)
|
||||
{
|
||||
if (in_array($attributeName, $this->camelizedAttributes)) {
|
||||
return preg_replace_callback('/(^|_|\.)+(.)/', function ($match) {
|
||||
return ('.' === $match[1] ? '_' : '').strtoupper($match[2]);
|
||||
}, $attributeName);
|
||||
}
|
||||
trigger_error(sprintf('%s is deprecated since version 2.7 and will be removed in 3.0. Use Symfony\Component\Serializer\NameConverter\CamelCaseToSnakeCaseNameConverter instead.', __METHOD__), E_USER_DEPRECATED);
|
||||
|
||||
return $attributeName;
|
||||
return $this->nameConverter ? $this->nameConverter->normalize($attributeName) : $attributeName;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -272,14 +291,15 @@ abstract class AbstractNormalizer extends SerializerAwareNormalizer implements N
|
||||
|
||||
$params = array();
|
||||
foreach ($constructorParameters as $constructorParameter) {
|
||||
$paramName = lcfirst($this->formatAttribute($constructorParameter->name));
|
||||
$paramName = $constructorParameter->name;
|
||||
$key = $this->nameConverter ? $this->nameConverter->normalize($paramName) : $paramName;
|
||||
|
||||
$allowed = $allowedAttributes === false || in_array($paramName, $allowedAttributes);
|
||||
$ignored = in_array($paramName, $this->ignoredAttributes);
|
||||
if ($allowed && !$ignored && isset($data[$paramName])) {
|
||||
$params[] = $data[$paramName];
|
||||
if ($allowed && !$ignored && isset($data[$key])) {
|
||||
$params[] = $data[$key];
|
||||
// don't run set for a parameter passed to the constructor
|
||||
unset($data[$paramName]);
|
||||
unset($data[$key]);
|
||||
} elseif ($constructorParameter->isOptional()) {
|
||||
$params[] = $constructorParameter->getDefaultValue();
|
||||
} else {
|
||||
|
@ -77,6 +77,10 @@ class GetSetMethodNormalizer extends AbstractNormalizer
|
||||
$attributeValue = $this->serializer->normalize($attributeValue, $format, $context);
|
||||
}
|
||||
|
||||
if ($this->nameConverter) {
|
||||
$attributeName = $this->nameConverter->normalize($attributeName);
|
||||
}
|
||||
|
||||
$attributes[$attributeName] = $attributeValue;
|
||||
}
|
||||
}
|
||||
@ -102,7 +106,11 @@ class GetSetMethodNormalizer extends AbstractNormalizer
|
||||
$ignored = in_array($attribute, $this->ignoredAttributes);
|
||||
|
||||
if ($allowed && !$ignored) {
|
||||
$setter = 'set'.$this->formatAttribute($attribute);
|
||||
if ($this->nameConverter) {
|
||||
$attribute = $this->nameConverter->denormalize($attribute);
|
||||
}
|
||||
|
||||
$setter = 'set'.ucfirst($attribute);
|
||||
|
||||
if (method_exists($object, $setter)) {
|
||||
$object->$setter($value);
|
||||
|
@ -71,7 +71,12 @@ class PropertyNormalizer extends AbstractNormalizer
|
||||
$attributeValue = $this->serializer->normalize($attributeValue, $format, $context);
|
||||
}
|
||||
|
||||
$attributes[$property->name] = $attributeValue;
|
||||
$propertyName = $property->name;
|
||||
if ($this->nameConverter) {
|
||||
$propertyName = $this->nameConverter->normalize($propertyName);
|
||||
}
|
||||
|
||||
$attributes[$propertyName] = $attributeValue;
|
||||
}
|
||||
|
||||
return $attributes;
|
||||
@ -91,7 +96,9 @@ class PropertyNormalizer extends AbstractNormalizer
|
||||
$object = $this->instantiateObject($data, $class, $context, $reflectionClass, $allowedAttributes);
|
||||
|
||||
foreach ($data as $propertyName => $value) {
|
||||
$propertyName = lcfirst($this->formatAttribute($propertyName));
|
||||
if ($this->nameConverter) {
|
||||
$propertyName = $this->nameConverter->denormalize($propertyName);
|
||||
}
|
||||
|
||||
$allowed = $allowedAttributes === false || in_array($propertyName, $allowedAttributes);
|
||||
$ignored = in_array($propertyName, $this->ignoredAttributes);
|
||||
|
@ -0,0 +1,47 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Serializer\Tests\NameConverter;
|
||||
|
||||
use Symfony\Component\Serializer\NameConverter\CamelCaseToSnakeCaseNameConverter;
|
||||
|
||||
/**
|
||||
* @author Kévin Dunglas <dunglas@gmail.com>
|
||||
*/
|
||||
class CamelCaseToSnakeCaseNameConverterTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
/**
|
||||
* @dataProvider attributeProvider
|
||||
*/
|
||||
public function testNormalize($underscored, $lowerCamelCased)
|
||||
{
|
||||
$nameConverter = new CamelCaseToSnakeCaseNameConverter();
|
||||
$this->assertEquals($nameConverter->normalize($lowerCamelCased), $underscored);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider attributeProvider
|
||||
*/
|
||||
public function testDenormalize($underscored, $lowerCamelCased)
|
||||
{
|
||||
$nameConverter = new CamelCaseToSnakeCaseNameConverter();
|
||||
$this->assertEquals($nameConverter->denormalize($underscored), $lowerCamelCased);
|
||||
}
|
||||
|
||||
public function attributeProvider()
|
||||
{
|
||||
return array(
|
||||
array('coop_tilleuls', 'coopTilleuls'),
|
||||
array('_kevin_dunglas', '_kevinDunglas'),
|
||||
array('this_is_a_test', 'thisIsATest'),
|
||||
);
|
||||
}
|
||||
}
|
@ -102,6 +102,7 @@ class GetSetMethodNormalizerTest extends \PHPUnit_Framework_TestCase
|
||||
array('camel_case' => 'camelCase'),
|
||||
__NAMESPACE__.'\GetSetDummy'
|
||||
);
|
||||
|
||||
$this->assertEquals('camelCase', $obj->getCamelCase());
|
||||
}
|
||||
|
||||
@ -110,27 +111,46 @@ class GetSetMethodNormalizerTest extends \PHPUnit_Framework_TestCase
|
||||
$this->assertEquals(new GetSetDummy(), $this->normalizer->denormalize(null, __NAMESPACE__.'\GetSetDummy'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider attributeProvider
|
||||
*/
|
||||
public function testFormatAttribute($attribute, $camelizedAttributes, $result)
|
||||
public function testCamelizedAttributesNormalize()
|
||||
{
|
||||
$r = new \ReflectionObject($this->normalizer);
|
||||
$m = $r->getMethod('formatAttribute');
|
||||
$m->setAccessible(true);
|
||||
$obj = new GetCamelizedDummy('dunglas.fr');
|
||||
$obj->setFooBar('les-tilleuls.coop');
|
||||
$obj->setBar_foo('lostinthesupermarket.fr');
|
||||
|
||||
$this->normalizer->setCamelizedAttributes($camelizedAttributes);
|
||||
$this->assertEquals($m->invoke($this->normalizer, $attribute, $camelizedAttributes), $result);
|
||||
$this->normalizer->setCamelizedAttributes(array('kevin_dunglas'));
|
||||
$this->assertEquals($this->normalizer->normalize($obj), array(
|
||||
'kevin_dunglas' => 'dunglas.fr',
|
||||
'fooBar' => 'les-tilleuls.coop',
|
||||
'bar_foo' => 'lostinthesupermarket.fr',
|
||||
));
|
||||
|
||||
$this->normalizer->setCamelizedAttributes(array('foo_bar'));
|
||||
$this->assertEquals($this->normalizer->normalize($obj), array(
|
||||
'kevinDunglas' => 'dunglas.fr',
|
||||
'foo_bar' => 'les-tilleuls.coop',
|
||||
'bar_foo' => 'lostinthesupermarket.fr',
|
||||
));
|
||||
}
|
||||
|
||||
public function attributeProvider()
|
||||
public function testCamelizedAttributesDenormalize()
|
||||
{
|
||||
return array(
|
||||
array('attribute_test', array('attribute_test'),'AttributeTest'),
|
||||
array('attribute_test', array('any'),'attribute_test'),
|
||||
array('attribute', array('attribute'),'Attribute'),
|
||||
array('attribute', array(), 'attribute'),
|
||||
);
|
||||
$obj = new GetCamelizedDummy('dunglas.fr');
|
||||
$obj->setFooBar('les-tilleuls.coop');
|
||||
$obj->setBar_foo('lostinthesupermarket.fr');
|
||||
|
||||
$this->normalizer->setCamelizedAttributes(array('kevin_dunglas'));
|
||||
$this->assertEquals($this->normalizer->denormalize(array(
|
||||
'kevin_dunglas' => 'dunglas.fr',
|
||||
'fooBar' => 'les-tilleuls.coop',
|
||||
'bar_foo' => 'lostinthesupermarket.fr',
|
||||
), __NAMESPACE__.'\GetCamelizedDummy'), $obj);
|
||||
|
||||
$this->normalizer->setCamelizedAttributes(array('foo_bar'));
|
||||
$this->assertEquals($this->normalizer->denormalize(array(
|
||||
'kevinDunglas' => 'dunglas.fr',
|
||||
'foo_bar' => 'les-tilleuls.coop',
|
||||
'bar_foo' => 'lostinthesupermarket.fr',
|
||||
), __NAMESPACE__.'\GetCamelizedDummy'), $obj);
|
||||
}
|
||||
|
||||
public function testConstructorDenormalize()
|
||||
@ -544,3 +564,40 @@ class GetConstructorOptionalArgsDummy
|
||||
throw new \RuntimeException("Dummy::otherMethod() should not be called");
|
||||
}
|
||||
}
|
||||
|
||||
class GetCamelizedDummy
|
||||
{
|
||||
private $kevinDunglas;
|
||||
private $fooBar;
|
||||
private $bar_foo;
|
||||
|
||||
public function __construct($kevinDunglas = null)
|
||||
{
|
||||
$this->kevinDunglas = $kevinDunglas;
|
||||
}
|
||||
|
||||
public function getKevinDunglas()
|
||||
{
|
||||
return $this->kevinDunglas;
|
||||
}
|
||||
|
||||
public function setFooBar($fooBar)
|
||||
{
|
||||
$this->fooBar = $fooBar;
|
||||
}
|
||||
|
||||
public function getFooBar()
|
||||
{
|
||||
return $this->fooBar;
|
||||
}
|
||||
|
||||
public function setBar_foo($bar_foo)
|
||||
{
|
||||
$this->bar_foo = $bar_foo;
|
||||
}
|
||||
|
||||
public function getBar_foo()
|
||||
{
|
||||
return $this->bar_foo;
|
||||
}
|
||||
}
|
||||
|
@ -74,27 +74,46 @@ class PropertyNormalizerTest extends \PHPUnit_Framework_TestCase
|
||||
$this->assertEquals('value', $obj->getCamelCase());
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider attributeProvider
|
||||
*/
|
||||
public function testFormatAttribute($attribute, $camelizedAttributes, $result)
|
||||
public function testCamelizedAttributesNormalize()
|
||||
{
|
||||
$r = new \ReflectionObject($this->normalizer);
|
||||
$m = $r->getMethod('formatAttribute');
|
||||
$m->setAccessible(true);
|
||||
$obj = new PropertyCamelizedDummy('dunglas.fr');
|
||||
$obj->fooBar = 'les-tilleuls.coop';
|
||||
$obj->bar_foo = 'lostinthesupermarket.fr';
|
||||
|
||||
$this->normalizer->setCamelizedAttributes($camelizedAttributes);
|
||||
$this->assertEquals($m->invoke($this->normalizer, $attribute, $camelizedAttributes), $result);
|
||||
$this->normalizer->setCamelizedAttributes(array('kevin_dunglas'));
|
||||
$this->assertEquals($this->normalizer->normalize($obj), array(
|
||||
'kevin_dunglas' => 'dunglas.fr',
|
||||
'fooBar' => 'les-tilleuls.coop',
|
||||
'bar_foo' => 'lostinthesupermarket.fr',
|
||||
));
|
||||
|
||||
$this->normalizer->setCamelizedAttributes(array('foo_bar'));
|
||||
$this->assertEquals($this->normalizer->normalize($obj), array(
|
||||
'kevinDunglas' => 'dunglas.fr',
|
||||
'foo_bar' => 'les-tilleuls.coop',
|
||||
'bar_foo' => 'lostinthesupermarket.fr',
|
||||
));
|
||||
}
|
||||
|
||||
public function attributeProvider()
|
||||
public function testCamelizedAttributesDenormalize()
|
||||
{
|
||||
return array(
|
||||
array('attribute_test', array('attribute_test'),'AttributeTest'),
|
||||
array('attribute_test', array('any'),'attribute_test'),
|
||||
array('attribute', array('attribute'),'Attribute'),
|
||||
array('attribute', array(), 'attribute'),
|
||||
);
|
||||
$obj = new PropertyCamelizedDummy('dunglas.fr');
|
||||
$obj->fooBar = 'les-tilleuls.coop';
|
||||
$obj->bar_foo = 'lostinthesupermarket.fr';
|
||||
|
||||
$this->normalizer->setCamelizedAttributes(array('kevin_dunglas'));
|
||||
$this->assertEquals($this->normalizer->denormalize(array(
|
||||
'kevin_dunglas' => 'dunglas.fr',
|
||||
'fooBar' => 'les-tilleuls.coop',
|
||||
'bar_foo' => 'lostinthesupermarket.fr',
|
||||
), __NAMESPACE__.'\PropertyCamelizedDummy'), $obj);
|
||||
|
||||
$this->normalizer->setCamelizedAttributes(array('foo_bar'));
|
||||
$this->assertEquals($this->normalizer->denormalize(array(
|
||||
'kevinDunglas' => 'dunglas.fr',
|
||||
'foo_bar' => 'les-tilleuls.coop',
|
||||
'bar_foo' => 'lostinthesupermarket.fr',
|
||||
), __NAMESPACE__.'\PropertyCamelizedDummy'), $obj);
|
||||
}
|
||||
|
||||
public function testConstructorDenormalize()
|
||||
@ -360,3 +379,15 @@ class PropertyConstructorDummy
|
||||
return $this->bar;
|
||||
}
|
||||
}
|
||||
|
||||
class PropertyCamelizedDummy
|
||||
{
|
||||
private $kevinDunglas;
|
||||
public $fooBar;
|
||||
public $bar_foo;
|
||||
|
||||
public function __construct($kevinDunglas = null)
|
||||
{
|
||||
$this->kevinDunglas = $kevinDunglas;
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user