Skip to content

Commit

Permalink
minor #31699 [Serializer] Unified normalizers/encoders config through…
Browse files Browse the repository at this point in the history
… default context solely (ogizanagi)

This PR was squashed before being merged into the 5.0-dev branch (closes #31699).

Discussion
----------

[Serializer] Unified normalizers/encoders config through default context solely

| Q             | A
| ------------- | ---
| Branch?       | master <!-- see below -->
| Bug fix?      | no
| New feature?  | no <!-- please update src/**/CHANGELOG.md files -->
| BC breaks?    | no     <!-- see https://symfony.com/bc -->
| Deprecations? | no <!-- please update UPGRADE-*.md and src/**/CHANGELOG.md files -->
| Tests pass?   | yes    <!-- please add some, will be required by reviewers -->
| Fixed tickets | #28709   <!-- #-prefixed issue number(s), if any -->
| License       | MIT
| Doc PR        | N/A

As planned in #28709.
Split into two commits to ease review.

Commits
-------

914577e [Serializer] Unified normalizers/encoders config through default context solely
  • Loading branch information
nicolas-grekas committed May 30, 2019
2 parents 174a0a7 + 914577e commit fb865a6
Show file tree
Hide file tree
Showing 16 changed files with 81 additions and 792 deletions.
18 changes: 18 additions & 0 deletions UPGRADE-5.0.md
Expand Up @@ -383,6 +383,24 @@ Serializer
----------

* The default value of the `CsvEncoder` "as_collection" option was changed to `true`.
* Individual encoders & normalizers options as constructor arguments were removed.
Use the default context instead.
* The following method and properties:
- `AbstractNormalizer::$circularReferenceLimit`
- `AbstractNormalizer::$circularReferenceHandler`
- `AbstractNormalizer::$callbacks`
- `AbstractNormalizer::$ignoredAttributes`
- `AbstractNormalizer::$camelizedAttributes`
- `AbstractNormalizer::setCircularReferenceLimit()`
- `AbstractNormalizer::setCircularReferenceHandler()`
- `AbstractNormalizer::setCallbacks()`
- `AbstractNormalizer::setIgnoredAttributes()`
- `AbstractObjectNormalizer::$maxDepthHandler`
- `AbstractObjectNormalizer::setMaxDepthHandler()`
- `XmlEncoder::setRootNodeName()`
- `XmlEncoder::getRootNodeName()`

were removed, use the default context instead.
* The `AbstractNormalizer::handleCircularReference()` method has two new `$format` and `$context` arguments.

Translation
Expand Down
9 changes: 9 additions & 0 deletions src/Symfony/Component/Serializer/CHANGELOG.md
Expand Up @@ -7,6 +7,15 @@ CHANGELOG
* throw an exception when creating a `Serializer` with normalizers which neither implement `NormalizerInterface` nor `DenormalizerInterface`
* throw an exception when creating a `Serializer` with encoders which neither implement `EncoderInterface` nor `DecoderInterface`
* changed the default value of the `CsvEncoder` "as_collection" option to `true`
* removed `AbstractNormalizer::$circularReferenceLimit`, `AbstractNormalizer::$circularReferenceHandler`,
`AbstractNormalizer::$callbacks`, `AbstractNormalizer::$ignoredAttributes`,
`AbstractNormalizer::$camelizedAttributes`, `AbstractNormalizer::setCircularReferenceLimit()`,
`AbstractNormalizer::setCircularReferenceHandler()`, `AbstractNormalizer::setCallbacks()` and
`AbstractNormalizer::setIgnoredAttributes()`, use the default context instead.
* removed `AbstractObjectNormalizer::$maxDepthHandler` and `AbstractObjectNormalizer::setMaxDepthHandler()`,
use the default context instead.
* removed `XmlEncoder::setRootNodeName()` & `XmlEncoder::getRootNodeName()`, use the default context instead.
* removed individual encoders/normalizers options as constructor arguments.

4.3.0
-----
Expand Down
17 changes: 1 addition & 16 deletions src/Symfony/Component/Serializer/Encoder/CsvEncoder.php
Expand Up @@ -43,23 +43,8 @@ class CsvEncoder implements EncoderInterface, DecoderInterface
self::NO_HEADERS_KEY => false,
];

/**
* @param array $defaultContext
*/
public function __construct($defaultContext = [], string $enclosure = '"', string $escapeChar = '\\', string $keySeparator = '.', bool $escapeFormulas = false)
public function __construct(array $defaultContext = [])
{
if (!\is_array($defaultContext)) {
@trigger_error('Passing configuration options directly to the constructor is deprecated since Symfony 4.2, use the default context instead.', E_USER_DEPRECATED);

$defaultContext = [
self::DELIMITER_KEY => (string) $defaultContext,
self::ENCLOSURE_KEY => $enclosure,
self::ESCAPE_CHAR_KEY => $escapeChar,
self::KEY_SEPARATOR_KEY => $keySeparator,
self::ESCAPE_FORMULAS_KEY => $escapeFormulas,
];
}

$this->defaultContext = array_merge($this->defaultContext, $defaultContext);
}

Expand Down
44 changes: 1 addition & 43 deletions src/Symfony/Component/Serializer/Encoder/XmlEncoder.php
Expand Up @@ -71,22 +71,8 @@ class XmlEncoder implements EncoderInterface, DecoderInterface, NormalizationAwa
private $format;
private $context;

/**
* @param array $defaultContext
*/
public function __construct($defaultContext = [], int $loadOptions = null, array $decoderIgnoredNodeTypes = [XML_PI_NODE, XML_COMMENT_NODE], array $encoderIgnoredNodeTypes = [])
public function __construct(array $defaultContext = [])
{
if (!\is_array($defaultContext)) {
@trigger_error('Passing configuration options directly to the constructor is deprecated since Symfony 4.2, use the default context instead.', E_USER_DEPRECATED);

$defaultContext = [
self::DECODER_IGNORED_NODE_TYPES => $decoderIgnoredNodeTypes,
self::ENCODER_IGNORED_NODE_TYPES => $encoderIgnoredNodeTypes,
self::LOAD_OPTIONS => $loadOptions ?? LIBXML_NONET | LIBXML_NOBLANKS,
self::ROOT_NODE_NAME => (string) $defaultContext,
];
}

$this->defaultContext = array_merge($this->defaultContext, $defaultContext);
}

Expand Down Expand Up @@ -203,34 +189,6 @@ public function supportsDecoding($format)
return self::FORMAT === $format;
}

/**
* Sets the root node name.
*
* @deprecated since Symfony 4.2
*
* @param string $name Root node name
*/
public function setRootNodeName($name)
{
@trigger_error(sprintf('The "%s()" method is deprecated since Symfony 4.2, use the context instead.', __METHOD__), E_USER_DEPRECATED);

$this->defaultContext[self::ROOT_NODE_NAME] = $name;
}

/**
* Returns the root node name.
*
* @deprecated since Symfony 4.2
*
* @return string
*/
public function getRootNodeName()
{
@trigger_error(sprintf('The "%s()" method is deprecated since Symfony 4.2, use the context instead.', __METHOD__), E_USER_DEPRECATED);

return $this->defaultContext[self::ROOT_NODE_NAME];
}

final protected function appendXMLString(\DOMNode $node, string $val): bool
{
if ('' !== $val) {
Expand Down
113 changes: 5 additions & 108 deletions src/Symfony/Component/Serializer/Normalizer/AbstractNormalizer.php
Expand Up @@ -118,22 +118,11 @@ abstract class AbstractNormalizer implements NormalizerInterface, DenormalizerIn

protected $defaultContext = [
self::ALLOW_EXTRA_ATTRIBUTES => true,
self::CIRCULAR_REFERENCE_HANDLER => null,
self::CIRCULAR_REFERENCE_LIMIT => 1,
self::IGNORED_ATTRIBUTES => [],
];

/**
* @deprecated since Symfony 4.2
*/
protected $circularReferenceLimit = 1;

/**
* @deprecated since Symfony 4.2
*
* @var callable|null
*/
protected $circularReferenceHandler;

/**
* @var ClassMetadataFactoryInterface|null
*/
Expand All @@ -144,21 +133,6 @@ abstract class AbstractNormalizer implements NormalizerInterface, DenormalizerIn
*/
protected $nameConverter;

/**
* @deprecated since Symfony 4.2
*/
protected $callbacks = [];

/**
* @deprecated since Symfony 4.2
*/
protected $ignoredAttributes = [];

/**
* @deprecated since Symfony 4.2
*/
protected $camelizedAttributes = [];

/**
* Sets the {@link ClassMetadataFactoryInterface} to use.
*/
Expand All @@ -185,83 +159,6 @@ public function __construct(ClassMetadataFactoryInterface $classMetadataFactory
}
}

/**
* Sets circular reference limit.
*
* @deprecated since Symfony 4.2
*
* @param int $circularReferenceLimit Limit of iterations for the same object
*
* @return self
*/
public function setCircularReferenceLimit($circularReferenceLimit)
{
@trigger_error(sprintf('The "%s()" method is deprecated since Symfony 4.2, use the "circular_reference_limit" key of the context instead.', __METHOD__), E_USER_DEPRECATED);

$this->defaultContext[self::CIRCULAR_REFERENCE_LIMIT] = $this->circularReferenceLimit = $circularReferenceLimit;

return $this;
}

/**
* Sets circular reference handler.
*
* @deprecated since Symfony 4.2
*
* @param callable $circularReferenceHandler
*
* @return self
*/
public function setCircularReferenceHandler(callable $circularReferenceHandler)
{
@trigger_error(sprintf('The "%s()" method is deprecated since Symfony 4.2, use the "circular_reference_handler" key of the context instead.', __METHOD__), E_USER_DEPRECATED);

$this->defaultContext[self::CIRCULAR_REFERENCE_HANDLER] = $this->circularReferenceHandler = $circularReferenceHandler;

return $this;
}

/**
* Sets normalization callbacks.
*
* @deprecated since Symfony 4.2
*
* @param callable[] $callbacks Help normalize the result
*
* @return self
*
* @throws InvalidArgumentException if a non-callable callback is set
*/
public function setCallbacks(array $callbacks)
{
@trigger_error(sprintf('The "%s()" method is deprecated since Symfony 4.2, use the "callbacks" key of the context instead.', __METHOD__), E_USER_DEPRECATED);

foreach ($callbacks as $attribute => $callback) {
if (!\is_callable($callback)) {
throw new InvalidArgumentException(sprintf('The given callback for attribute "%s" is not callable.', $attribute));
}
}
$this->defaultContext[self::CALLBACKS] = $this->callbacks = $callbacks;

return $this;
}

/**
* Sets ignored attributes for normalization and denormalization.
*
* @deprecated since Symfony 4.2
*
* @return self
*/
public function setIgnoredAttributes(array $ignoredAttributes)
{
@trigger_error(sprintf('The "%s()" method is deprecated since Symfony 4.2, use the "ignored_attributes" key of the context instead.', __METHOD__), E_USER_DEPRECATED);

$this->defaultContext[self::IGNORED_ATTRIBUTES] = $this->ignoredAttributes = $ignoredAttributes;

return $this;
}

/**
* {@inheritdoc}
*/
Expand All @@ -284,7 +181,7 @@ protected function isCircularReference($object, &$context)
{
$objectHash = spl_object_hash($object);

$circularReferenceLimit = $context[self::CIRCULAR_REFERENCE_LIMIT] ?? $this->defaultContext[self::CIRCULAR_REFERENCE_LIMIT] ?? $this->circularReferenceLimit;
$circularReferenceLimit = $context[self::CIRCULAR_REFERENCE_LIMIT] ?? $this->defaultContext[self::CIRCULAR_REFERENCE_LIMIT];
if (isset($context[self::CIRCULAR_REFERENCE_LIMIT_COUNTERS][$objectHash])) {
if ($context[self::CIRCULAR_REFERENCE_LIMIT_COUNTERS][$objectHash] >= $circularReferenceLimit) {
unset($context[self::CIRCULAR_REFERENCE_LIMIT_COUNTERS][$objectHash]);
Expand Down Expand Up @@ -324,12 +221,12 @@ protected function handleCircularReference($object/*, string $format = null, arr
$format = \func_num_args() > 1 ? func_get_arg(1) : null;
$context = \func_num_args() > 2 ? func_get_arg(2) : [];

$circularReferenceHandler = $context[self::CIRCULAR_REFERENCE_HANDLER] ?? $this->defaultContext[self::CIRCULAR_REFERENCE_HANDLER] ?? $this->circularReferenceHandler;
$circularReferenceHandler = $context[self::CIRCULAR_REFERENCE_HANDLER] ?? $this->defaultContext[self::CIRCULAR_REFERENCE_HANDLER];
if ($circularReferenceHandler) {
return $circularReferenceHandler($object, $format, $context);
}

throw new CircularReferenceException(sprintf('A circular reference has been detected when serializing the object of class "%s" (configured limit: %d)', \get_class($object), $this->circularReferenceLimit));
throw new CircularReferenceException(sprintf('A circular reference has been detected when serializing the object of class "%s" (configured limit: %d)', \get_class($object), $context[self::CIRCULAR_REFERENCE_LIMIT] ?? $this->defaultContext[self::CIRCULAR_REFERENCE_LIMIT]));
}

/**
Expand Down Expand Up @@ -387,7 +284,7 @@ protected function getAllowedAttributes($classOrObject, array $context, $attribu
*/
protected function isAllowedAttribute($classOrObject, $attribute, $format = null, array $context = [])
{
$ignoredAttributes = $context[self::IGNORED_ATTRIBUTES] ?? $this->defaultContext[self::IGNORED_ATTRIBUTES] ?? $this->ignoredAttributes;
$ignoredAttributes = $context[self::IGNORED_ATTRIBUTES] ?? $this->defaultContext[self::IGNORED_ATTRIBUTES];
if (\in_array($attribute, $ignoredAttributes)) {
return false;
}
Expand Down
Expand Up @@ -92,12 +92,6 @@ abstract class AbstractObjectNormalizer extends AbstractNormalizer
private $typesCache = [];
private $attributesCache = [];

/**
* @deprecated since Symfony 4.2
*
* @var callable|null
*/
private $maxDepthHandler;
private $objectClassResolver;

/**
Expand Down Expand Up @@ -168,8 +162,7 @@ public function normalize($object, $format = null, array $context = [])
throw new InvalidArgumentException(sprintf('The "%s" given in the context is not callable.', self::MAX_DEPTH_HANDLER));
}
} else {
// already validated in constructor resp by type declaration of setMaxDepthHandler
$maxDepthHandler = $this->defaultContext[self::MAX_DEPTH_HANDLER] ?? $this->maxDepthHandler;
$maxDepthHandler = null;
}

foreach ($attributes as $attribute) {
Expand All @@ -186,7 +179,7 @@ public function normalize($object, $format = null, array $context = [])
/**
* @var callable|null
*/
$callback = $context[self::CALLBACKS][$attribute] ?? $this->defaultContext[self::CALLBACKS][$attribute] ?? $this->callbacks[$attribute] ?? null;
$callback = $context[self::CALLBACKS][$attribute] ?? $this->defaultContext[self::CALLBACKS][$attribute] ?? null;
if ($callback) {
$attributeValue = $callback($attributeValue, $object, $attribute, $format, $context);
}
Expand Down Expand Up @@ -295,18 +288,6 @@ abstract protected function extractAttributes($object, $format = null, array $co
*/
abstract protected function getAttributeValue($object, $attribute, $format = null, array $context = []);

/**
* Sets a handler function that will be called when the max depth is reached.
*
* @deprecated since Symfony 4.2
*/
public function setMaxDepthHandler(?callable $handler): void
{
@trigger_error(sprintf('The "%s()" method is deprecated since Symfony 4.2, use the "max_depth_handler" key of the context instead.', __METHOD__), E_USER_DEPRECATED);

$this->maxDepthHandler = $handler;
}

/**
* {@inheritdoc}
*/
Expand Down Expand Up @@ -595,8 +576,7 @@ private function getCacheKey(?string $format, array $context)
try {
return md5($format.serialize([
'context' => $context,
'ignored' => $this->ignoredAttributes,
'camelized' => $this->camelizedAttributes,
'ignored' => $context[self::IGNORED_ATTRIBUTES] ?? $this->defaultContext[self::IGNORED_ATTRIBUTES],
]));
} catch (\Exception $exception) {
// The context cannot be serialized, skip the cache
Expand Down
Expand Up @@ -28,17 +28,8 @@ class DateIntervalNormalizer implements NormalizerInterface, DenormalizerInterfa
self::FORMAT_KEY => 'P%yY%mM%dDT%hH%iM%sS',
];

/**
* @param array $defaultContext
*/
public function __construct($defaultContext = [])
public function __construct(array $defaultContext = [])
{
if (!\is_array($defaultContext)) {
@trigger_error(sprintf('The "format" parameter is deprecated since Symfony 4.2, use the "%s" key of the context instead.', self::FORMAT_KEY), E_USER_DEPRECATED);

$defaultContext = [self::FORMAT_KEY => (string) $defaultContext];
}

$this->defaultContext = array_merge($this->defaultContext, $defaultContext);
}

Expand Down

0 comments on commit fb865a6

Please sign in to comment.