Server IP : 213.176.29.180  /  Your IP : 18.224.38.165
Web Server : Apache
System : Linux 213.176.29.180.hostiran.name 4.18.0-553.22.1.el8_10.x86_64 #1 SMP Tue Sep 24 05:16:59 EDT 2024 x86_64
User : webtaragh ( 1001)
PHP Version : 7.4.33
Disable Function : NONE
MySQL : OFF  |  cURL : ON  |  WGET : ON  |  Perl : ON  |  Python : ON
Directory (0750) :  /home/webtaragh/public_html/webtaragh.ir/../webtaragh.ir/../

[  Home  ][  C0mmand  ][  Upload File  ]

Current File : /home/webtaragh/public_html/webtaragh.ir/../webtaragh.ir/../jms.tar
serializer/UPGRADING.md000064400000001760147361032420010565 0ustar00From 0.13 to ???
================

- If you have implemented your own ObjectConstructor, you need to add the DeserializationContext as an additional
  parameter for the ``construct`` method.


From 0.11 to 0.12
=================

- GraphNavigator::detachObject has been removed, you can directly use Context::stopVisiting instead.
- VisitorInterface::getNavigator was deprecated, instead use Context::accept
- Serializer::setGroups, Serializer::setExclusionStrategy and Serializer::setVersion were removed, these settings must
  now be passed as part of a new Context object.

    Before:

        $serializer->setVersion(1);
        $serializer->serialize($data, 'json');

    After:

        $serializer->serialize($data, 'json', SerializationContext::create()->setVersion(1));

- All visit??? methods of the VisitorInterface, now require a third argument, the Context; the context is for example
  passed as an additional argument to handlers, exclusion strategies, and also available in event listeners.
serializer/src/JMS/Serializer/Naming/IdenticalPropertyNamingStrategy.php000064400000000427147361032420022513 0ustar00<?php

namespace JMS\Serializer\Naming;

use JMS\Serializer\Metadata\PropertyMetadata;

class IdenticalPropertyNamingStrategy implements PropertyNamingStrategyInterface
{
    public function translateName(PropertyMetadata $property)
    {
        return $property->name;
    }
}
serializer/src/JMS/Serializer/Naming/PropertyNamingStrategyInterface.php000064400000001063147361032420022514 0ustar00<?php

namespace JMS\Serializer\Naming;

use JMS\Serializer\Metadata\PropertyMetadata;

/**
 * Interface for property naming strategies.
 *
 * Implementations translate the property name to a serialized name that is
 * displayed.
 *
 * @author Johannes M. Schmitt <schmittjoh@gmail.com>
 */
interface PropertyNamingStrategyInterface
{
    /**
     * Translates the name of the property to the serialized version.
     *
     * @param PropertyMetadata $property
     *
     * @return string
     */
    public function translateName(PropertyMetadata $property);
}
serializer/src/JMS/Serializer/Naming/SerializedNameAnnotationStrategy.php000064400000001344147361032420022646 0ustar00<?php

namespace JMS\Serializer\Naming;

use JMS\Serializer\Metadata\PropertyMetadata;

/**
 * Naming strategy which uses an annotation to translate the property name.
 *
 * @author Johannes M. Schmitt <schmittjoh@gmail.com>
 */
class SerializedNameAnnotationStrategy implements PropertyNamingStrategyInterface
{
    private $delegate;

    public function __construct(PropertyNamingStrategyInterface $namingStrategy)
    {
        $this->delegate = $namingStrategy;
    }

    /**
     * {@inheritDoc}
     */
    public function translateName(PropertyMetadata $property)
    {
        if (null !== $name = $property->serializedName) {
            return $name;
        }

        return $this->delegate->translateName($property);
    }
}
serializer/src/JMS/Serializer/Naming/CamelCaseNamingStrategy.php000064400000001464147361032420020671 0ustar00<?php

namespace JMS\Serializer\Naming;

use JMS\Serializer\Metadata\PropertyMetadata;

/**
 * Generic naming strategy which translates a camel-cased property name.
 *
 * @author Johannes M. Schmitt <schmittjoh@gmail.com>
 */
class CamelCaseNamingStrategy implements PropertyNamingStrategyInterface
{
    private $separator;
    private $lowerCase;

    public function __construct($separator = '_', $lowerCase = true)
    {
        $this->separator = $separator;
        $this->lowerCase = $lowerCase;
    }

    /**
     * {@inheritDoc}
     */
    public function translateName(PropertyMetadata $property)
    {
        $name = preg_replace('/[A-Z]/', $this->separator . '\\0', $property->name);

        if ($this->lowerCase) {
            return strtolower($name);
        }

        return ucfirst($name);
    }
}
serializer/src/JMS/Serializer/Naming/CacheNamingStrategy.php000064400000001175147361032420020056 0ustar00<?php

namespace JMS\Serializer\Naming;

use JMS\Serializer\Metadata\PropertyMetadata;

class CacheNamingStrategy implements PropertyNamingStrategyInterface
{
    private $delegate;
    private $cache;

    public function __construct(PropertyNamingStrategyInterface $delegate)
    {
        $this->delegate = $delegate;
        $this->cache = new \SplObjectStorage();
    }

    public function translateName(PropertyMetadata $property)
    {
        if (isset($this->cache[$property])) {
            return $this->cache[$property];
        }

        return $this->cache[$property] = $this->delegate->translateName($property);
    }
}
serializer/src/JMS/Serializer/Naming/AdvancedNamingStrategyInterface.php000064400000001303147361032420022372 0ustar00<?php

namespace JMS\Serializer\Naming;

use JMS\Serializer\Context;
use JMS\Serializer\Metadata\PropertyMetadata;

/**
 * Interface for advanced property naming strategies.
 *
 * Implementations translate the property name to a serialized name that is
 * displayed. It allows advanced strategy thanks to context parameter.
 *
 * @author Vincent Rasquier <vincent.rsbs@gmail.com>
 */
interface AdvancedNamingStrategyInterface
{
    /**
     * Translates the name of the property to the serialized version.
     *
     * @param PropertyMetadata $property
     * @param Context $context
     *
     * @return string
     */
    public function getPropertyName(PropertyMetadata $property, Context $context);
}
serializer/src/JMS/Serializer/Exclusion/ExpressionLanguageExclusionStrategy.php000064400000002552147361032420024156 0ustar00<?php

namespace JMS\Serializer\Exclusion;

use JMS\Serializer\Context;
use JMS\Serializer\Expression\ExpressionEvaluatorInterface;
use JMS\Serializer\Metadata\PropertyMetadata;
use JMS\Serializer\SerializationContext;

/**
 * Exposes an exclusion strategy based on the Symfony's expression language.
 * This is not a standard exclusion strategy and can not be used in user applications.
 *
 * @internal
 *
 * @author Asmir Mustafic <goetas@gmail.com>
 */
class ExpressionLanguageExclusionStrategy
{
    /**
     * @var ExpressionEvaluatorInterface
     */
    private $expressionEvaluator;

    public function __construct(ExpressionEvaluatorInterface $expressionEvaluator)
    {
        $this->expressionEvaluator = $expressionEvaluator;
    }

    /**
     * {@inheritDoc}
     */
    public function shouldSkipProperty(PropertyMetadata $property, Context $navigatorContext)
    {
        if (null === $property->excludeIf) {
            return false;
        }

        $variables = [
            'context' => $navigatorContext,
            'property_metadata' => $property,
        ];
        if ($navigatorContext instanceof SerializationContext) {
            $variables['object'] = $navigatorContext->getObject();
        } else {
            $variables['object'] = null;
        }

        return $this->expressionEvaluator->evaluate($property->excludeIf, $variables);
    }
}
serializer/src/JMS/Serializer/Exclusion/ExclusionStrategyInterface.php000064400000001356147361032420022254 0ustar00<?php

namespace JMS\Serializer\Exclusion;

use JMS\Serializer\Context;
use JMS\Serializer\Metadata\ClassMetadata;
use JMS\Serializer\Metadata\PropertyMetadata;

/**
 * Interface for exclusion strategies.
 *
 * @author Johannes M. Schmitt <schmittjoh@gmail.com>
 */
interface ExclusionStrategyInterface
{
    /**
     * Whether the class should be skipped.
     *
     * @param ClassMetadata $metadata
     *
     * @return boolean
     */
    public function shouldSkipClass(ClassMetadata $metadata, Context $context);

    /**
     * Whether the property should be skipped.
     *
     * @param PropertyMetadata $property
     *
     * @return boolean
     */
    public function shouldSkipProperty(PropertyMetadata $property, Context $context);
}
serializer/src/JMS/Serializer/Exclusion/DepthExclusionStrategy.php000064400000002456147361032420021422 0ustar00<?php

namespace JMS\Serializer\Exclusion;

use JMS\Serializer\Context;
use JMS\Serializer\Metadata\ClassMetadata;
use JMS\Serializer\Metadata\PropertyMetadata;

/**
 * @author Adrien Brault <adrien.brault@gmail.com>
 */
class DepthExclusionStrategy implements ExclusionStrategyInterface
{
    /**
     * {@inheritDoc}
     */
    public function shouldSkipClass(ClassMetadata $metadata, Context $context)
    {
        return $this->isTooDeep($context);
    }

    /**
     * {@inheritDoc}
     */
    public function shouldSkipProperty(PropertyMetadata $property, Context $context)
    {
        return $this->isTooDeep($context);
    }

    private function isTooDeep(Context $context)
    {
        $depth = $context->getDepth();
        $metadataStack = $context->getMetadataStack();

        $nthProperty = 0;
        // iterate from the first added items to the lasts
        for ($i = $metadataStack->count() - 1; $i > 0; $i--) {
            $metadata = $metadataStack[$i];
            if ($metadata instanceof PropertyMetadata) {
                $nthProperty++;
                $relativeDepth = $depth - $nthProperty;

                if (null !== $metadata->maxDepth && $relativeDepth > $metadata->maxDepth) {
                    return true;
                }
            }
        }

        return false;
    }
}
serializer/src/JMS/Serializer/Exclusion/GroupsExclusionStrategy.php000064400000005412147361032420021630 0ustar00<?php

namespace JMS\Serializer\Exclusion;

use JMS\Serializer\Context;
use JMS\Serializer\Metadata\ClassMetadata;
use JMS\Serializer\Metadata\PropertyMetadata;

class GroupsExclusionStrategy implements ExclusionStrategyInterface
{
    const DEFAULT_GROUP = 'Default';

    private $groups = array();
    private $nestedGroups = false;

    public function __construct(array $groups)
    {
        if (empty($groups)) {
            $groups = array(self::DEFAULT_GROUP);
        }

        foreach ($groups as $group) {
            if (is_array($group)) {
                $this->nestedGroups = true;
                break;
            }
        }

        if ($this->nestedGroups) {
            $this->groups = $groups;
        } else {
            foreach ($groups as $group) {
                $this->groups[$group] = true;
            }
        }
    }

    /**
     * {@inheritDoc}
     */
    public function shouldSkipClass(ClassMetadata $metadata, Context $navigatorContext)
    {
        return false;
    }

    /**
     * {@inheritDoc}
     */
    public function shouldSkipProperty(PropertyMetadata $property, Context $navigatorContext)
    {
        if ($this->nestedGroups) {
            $groups = $this->getGroupsFor($navigatorContext);

            if (!$property->groups) {
                return !in_array(self::DEFAULT_GROUP, $groups);
            }

            return $this->shouldSkipUsingGroups($property, $groups);
        } else {

            if (!$property->groups) {
                return !isset($this->groups[self::DEFAULT_GROUP]);
            }

            foreach ($property->groups as $group) {
                if (isset($this->groups[$group])) {
                    return false;
                }
            }
            return true;
        }
    }

    private function shouldSkipUsingGroups(PropertyMetadata $property, $groups)
    {
        foreach ($property->groups as $group) {
            if (in_array($group, $groups)) {
                return false;
            }
        }

        return true;
    }

    /**
     * @param Context $navigatorContext
     * @return array
     */
    public function getGroupsFor(Context $navigatorContext)
    {
        if (!$this->nestedGroups) {
            return array_keys($this->groups);
        }

        $paths = $navigatorContext->getCurrentPath();

        $groups = $this->groups;
        foreach ($paths as $index => $path) {
            if (!array_key_exists($path, $groups)) {
                if ($index > 0) {
                    $groups = array(self::DEFAULT_GROUP);
                }

                break;
            }

            $groups = $groups[$path];

            if (!array_filter($groups, 'is_string')) {
                $groups += array(self::DEFAULT_GROUP);
            }
        }

        return $groups;
    }
}
serializer/src/JMS/Serializer/Exclusion/VersionExclusionStrategy.php000064400000001707147361032420022001 0ustar00<?php

namespace JMS\Serializer\Exclusion;

use JMS\Serializer\Context;
use JMS\Serializer\Metadata\ClassMetadata;
use JMS\Serializer\Metadata\PropertyMetadata;

class VersionExclusionStrategy implements ExclusionStrategyInterface
{
    private $version;

    public function __construct($version)
    {
        $this->version = $version;
    }

    /**
     * {@inheritDoc}
     */
    public function shouldSkipClass(ClassMetadata $metadata, Context $navigatorContext)
    {
        return false;
    }

    /**
     * {@inheritDoc}
     */
    public function shouldSkipProperty(PropertyMetadata $property, Context $navigatorContext)
    {
        if ((null !== $version = $property->sinceVersion) && version_compare($this->version, $version, '<')) {
            return true;
        }

        if ((null !== $version = $property->untilVersion) && version_compare($this->version, $version, '>')) {
            return true;
        }

        return false;
    }
}
serializer/src/JMS/Serializer/Exclusion/DisjunctExclusionStrategy.php000064400000003710147361032420022133 0ustar00<?php

namespace JMS\Serializer\Exclusion;

use JMS\Serializer\Context;
use JMS\Serializer\Metadata\ClassMetadata;
use JMS\Serializer\Metadata\PropertyMetadata;
use PhpCollection\Sequence;
use PhpCollection\SequenceInterface;

/**
 * Disjunct Exclusion Strategy.
 *
 * This strategy is short-circuiting and will skip a class, or property as soon as one of the delegates skips it.
 *
 * @author Johannes M. Schmitt <schmittjoh@gmail.com>
 */
class DisjunctExclusionStrategy implements ExclusionStrategyInterface
{
    /** @var \PhpCollection\SequenceInterface */
    private $delegates;

    /**
     * @param ExclusionStrategyInterface[]|SequenceInterface $delegates
     */
    public function __construct($delegates)
    {
        if (!$delegates instanceof SequenceInterface) {
            $delegates = new Sequence($delegates);
        }

        $this->delegates = $delegates;
    }

    public function addStrategy(ExclusionStrategyInterface $strategy)
    {
        $this->delegates->add($strategy);
    }

    /**
     * Whether the class should be skipped.
     *
     * @param ClassMetadata $metadata
     *
     * @return boolean
     */
    public function shouldSkipClass(ClassMetadata $metadata, Context $context)
    {
        foreach ($this->delegates as $delegate) {
            /** @var $delegate ExclusionStrategyInterface */
            if ($delegate->shouldSkipClass($metadata, $context)) {
                return true;
            }
        }

        return false;
    }

    /**
     * Whether the property should be skipped.
     *
     * @param PropertyMetadata $property
     *
     * @return boolean
     */
    public function shouldSkipProperty(PropertyMetadata $property, Context $context)
    {
        foreach ($this->delegates as $delegate) {
            /** @var $delegate ExclusionStrategyInterface */
            if ($delegate->shouldSkipProperty($property, $context)) {
                return true;
            }
        }

        return false;
    }
}
serializer/src/JMS/Serializer/AbstractVisitor.php000064400000002257147361032420016112 0ustar00<?php

namespace JMS\Serializer;

use JMS\Serializer\Accessor\AccessorStrategyInterface;
use JMS\Serializer\Accessor\DefaultAccessorStrategy;

abstract class AbstractVisitor implements VisitorInterface
{
    protected $namingStrategy;

    /**
     * @var AccessorStrategyInterface
     */
    protected $accessor;

    public function __construct($namingStrategy, AccessorStrategyInterface $accessorStrategy = null)
    {
        $this->namingStrategy = $namingStrategy;
        $this->accessor = $accessorStrategy ?: new DefaultAccessorStrategy();
    }

    /**
     * @deprecated Will be removed in 2.0
     * @return mixed
     */
    public function getNamingStrategy()
    {
        return $this->namingStrategy;
    }

    public function prepare($data)
    {
        return $data;
    }

    /**
     * @param array $typeArray
     */
    protected function getElementType($typeArray)
    {
        if (false === isset($typeArray['params'][0])) {
            return null;
        }

        if (isset($typeArray['params'][1]) && \is_array($typeArray['params'][1])) {
            return $typeArray['params'][1];
        } else {
            return $typeArray['params'][0];
        }
    }
}
serializer/src/JMS/Serializer/GraphNavigator.php000064400000036512147361032420015704 0ustar00<?php

namespace JMS\Serializer;

use JMS\Serializer\Construction\ObjectConstructorInterface;
use JMS\Serializer\EventDispatcher\EventDispatcherInterface;
use JMS\Serializer\EventDispatcher\ObjectEvent;
use JMS\Serializer\EventDispatcher\PreDeserializeEvent;
use JMS\Serializer\EventDispatcher\PreSerializeEvent;
use JMS\Serializer\Exception\ExpressionLanguageRequiredException;
use JMS\Serializer\Exception\InvalidArgumentException;
use JMS\Serializer\Exception\RuntimeException;
use JMS\Serializer\Exclusion\ExpressionLanguageExclusionStrategy;
use JMS\Serializer\Expression\ExpressionEvaluatorInterface;
use JMS\Serializer\Handler\HandlerRegistryInterface;
use JMS\Serializer\Metadata\ClassMetadata;
use Metadata\MetadataFactoryInterface;

/**
 * Handles traversal along the object graph.
 *
 * This class handles traversal along the graph, and calls different methods
 * on visitors, or custom handlers to process its nodes.
 *
 * @author Johannes M. Schmitt <schmittjoh@gmail.com>
 */
final class GraphNavigator implements GraphNavigatorInterface
{
    /**
     * @var ExpressionLanguageExclusionStrategy
     */
    private $expressionExclusionStrategy;

    private $dispatcher;
    private $metadataFactory;
    private $handlerRegistry;
    private $objectConstructor;

    /**
     * Parses a direction string to one of the direction constants.
     *
     * @param string $dirStr
     *
     * @return integer
     */
    public static function parseDirection($dirStr)
    {
        switch (strtolower($dirStr)) {
            case 'serialization':
                return self::DIRECTION_SERIALIZATION;

            case 'deserialization':
                return self::DIRECTION_DESERIALIZATION;

            default:
                throw new InvalidArgumentException(sprintf('The direction "%s" does not exist.', $dirStr));
        }
    }

    public function __construct(
        MetadataFactoryInterface $metadataFactory,
        HandlerRegistryInterface $handlerRegistry,
        ObjectConstructorInterface $objectConstructor,
        EventDispatcherInterface $dispatcher = null,
        ExpressionEvaluatorInterface $expressionEvaluator = null
    )
    {
        $this->dispatcher = $dispatcher;
        $this->metadataFactory = $metadataFactory;
        $this->handlerRegistry = $handlerRegistry;
        $this->objectConstructor = $objectConstructor;
        if ($expressionEvaluator) {
            $this->expressionExclusionStrategy = new ExpressionLanguageExclusionStrategy($expressionEvaluator);
        }
    }

    /**
     * Called for each node of the graph that is being traversed.
     *
     * @param mixed $data the data depends on the direction, and type of visitor
     * @param null|array $type array has the format ["name" => string, "params" => array]
     * @param Context $context
     * @return mixed the return value depends on the direction, and type of visitor
     */
    public function accept($data, array $type = null, Context $context)
    {
        $visitor = $context->getVisitor();

        // If the type was not given, we infer the most specific type from the
        // input data in serialization mode.
        if (null === $type) {
            if ($context instanceof DeserializationContext) {
                throw new RuntimeException('The type must be given for all properties when deserializing.');
            }

            $typeName = \gettype($data);
            if ('object' === $typeName) {
                $typeName = \get_class($data);
            }

            $type = array('name' => $typeName, 'params' => array());
        }
        // If the data is null, we have to force the type to null regardless of the input in order to
        // guarantee correct handling of null values, and not have any internal auto-casting behavior.
        else if ($context instanceof SerializationContext && null === $data) {
            $type = array('name' => 'NULL', 'params' => array());
        }
        // Sometimes data can convey null but is not of a null type.
        // Visitors can have the power to add this custom null evaluation
        if ($visitor instanceof NullAwareVisitorInterface && $visitor->isNull($data) === true) {
            $type = array('name' => 'NULL', 'params' => array());
        }

        switch ($type['name']) {
            case 'NULL':
                return $visitor->visitNull($data, $type, $context);

            case 'string':
                return $visitor->visitString($data, $type, $context);

            case 'int':
            case 'integer':
                return $visitor->visitInteger($data, $type, $context);

            case 'bool':
            case 'boolean':
                return $visitor->visitBoolean($data, $type, $context);

            case 'double':
            case 'float':
                return $visitor->visitDouble($data, $type, $context);

            case 'array':
                return $visitor->visitArray($data, $type, $context);

            case 'resource':
                $msg = 'Resources are not supported in serialized data.';
                if ($context instanceof SerializationContext && null !== $path = $context->getPath()) {
                    $msg .= ' Path: ' . $path;
                }

                throw new RuntimeException($msg);

            default:
                // TODO: The rest of this method needs some refactoring.
                if ($context instanceof SerializationContext) {
                    if (null !== $data) {
                        if ($context->isVisiting($data)) {
                            return null;
                        }
                        $context->startVisiting($data);
                    }

                    // If we're serializing a polymorphic type, then we'll be interested in the
                    // metadata for the actual type of the object, not the base class.
                    if (class_exists($type['name'], false) || interface_exists($type['name'], false)) {
                        if (is_subclass_of($data, $type['name'], false)) {
                            $type = array('name' => \get_class($data), 'params' => array());
                        }
                    }
                } elseif ($context instanceof DeserializationContext) {
                    $context->increaseDepth();
                }

                // Trigger pre-serialization callbacks, and listeners if they exist.
                // Dispatch pre-serialization event before handling data to have ability change type in listener
                if ($context instanceof SerializationContext) {
                    if (null !== $this->dispatcher && $this->dispatcher->hasListeners('serializer.pre_serialize', $type['name'], $context->getFormat())) {
                        $this->dispatcher->dispatch('serializer.pre_serialize', $type['name'], $context->getFormat(), $event = new PreSerializeEvent($context, $data, $type));
                        $type = $event->getType();
                    }
                } elseif ($context instanceof DeserializationContext) {
                    if (null !== $this->dispatcher && $this->dispatcher->hasListeners('serializer.pre_deserialize', $type['name'], $context->getFormat())) {
                        $this->dispatcher->dispatch('serializer.pre_deserialize', $type['name'], $context->getFormat(), $event = new PreDeserializeEvent($context, $data, $type));
                        $type = $event->getType();
                        $data = $event->getData();
                    }
                }

                // First, try whether a custom handler exists for the given type. This is done
                // before loading metadata because the type name might not be a class, but
                // could also simply be an artifical type.
                if (null !== $handler = $this->handlerRegistry->getHandler($context->getDirection(), $type['name'], $context->getFormat())) {
                    $rs = \call_user_func($handler, $visitor, $data, $type, $context);
                    $this->leaveScope($context, $data);

                    return $rs;
                }

                $exclusionStrategy = $context->getExclusionStrategy();

                /** @var $metadata ClassMetadata */
                $metadata = $this->metadataFactory->getMetadataForClass($type['name']);

                if ($metadata->usingExpression && !$this->expressionExclusionStrategy) {
                    throw new ExpressionLanguageRequiredException("To use conditional exclude/expose in {$metadata->name} you must configure the expression language.");
                }

                if ($context instanceof DeserializationContext && !empty($metadata->discriminatorMap) && $type['name'] === $metadata->discriminatorBaseClass) {
                    $metadata = $this->resolveMetadata($data, $metadata);
                }

                if (null !== $exclusionStrategy && $exclusionStrategy->shouldSkipClass($metadata, $context)) {
                    $this->leaveScope($context, $data);

                    return null;
                }

                $context->pushClassMetadata($metadata);

                if ($context instanceof SerializationContext) {
                    foreach ($metadata->preSerializeMethods as $method) {
                        $method->invoke($data);
                    }
                }

                $object = $data;
                if ($context instanceof DeserializationContext) {
                    $object = $this->objectConstructor->construct($visitor, $metadata, $data, $type, $context);
                }

                if (isset($metadata->handlerCallbacks[$context->getDirection()][$context->getFormat()])) {
                    $rs = $object->{$metadata->handlerCallbacks[$context->getDirection()][$context->getFormat()]}(
                        $visitor,
                        $context instanceof SerializationContext ? null : $data,
                        $context
                    );
                    $this->afterVisitingObject($metadata, $object, $type, $context);

                    return $context instanceof SerializationContext ? $rs : $object;
                }

                $visitor->startVisitingObject($metadata, $object, $type, $context);
                foreach ($metadata->propertyMetadata as $propertyMetadata) {
                    if (null !== $exclusionStrategy && $exclusionStrategy->shouldSkipProperty($propertyMetadata, $context)) {
                        continue;
                    }

                    if (null !== $this->expressionExclusionStrategy && $this->expressionExclusionStrategy->shouldSkipProperty($propertyMetadata, $context)) {
                        continue;
                    }

                    if ($context instanceof DeserializationContext && $propertyMetadata->readOnly) {
                        continue;
                    }

                    $context->pushPropertyMetadata($propertyMetadata);
                    $visitor->visitProperty($propertyMetadata, $data, $context);
                    $context->popPropertyMetadata();
                }

                if ($context instanceof SerializationContext) {
                    $this->afterVisitingObject($metadata, $data, $type, $context);

                    return $visitor->endVisitingObject($metadata, $data, $type, $context);
                }

                $rs = $visitor->endVisitingObject($metadata, $data, $type, $context);
                $this->afterVisitingObject($metadata, $rs, $type, $context);

                return $rs;
        }
    }

    private function resolveMetadata($data, ClassMetadata $metadata)
    {
        switch (true) {
            case \is_array($data) && isset($data[$metadata->discriminatorFieldName]):
                $typeValue = (string)$data[$metadata->discriminatorFieldName];
                break;

            // Check XML attribute without namespace for discriminatorFieldName
            case \is_object($data) && $metadata->xmlDiscriminatorAttribute && null === $metadata->xmlDiscriminatorNamespace && isset($data->attributes()->{$metadata->discriminatorFieldName}):
                $typeValue = (string)$data->attributes()->{$metadata->discriminatorFieldName};
                break;

            // Check XML attribute with namespace for discriminatorFieldName
            case \is_object($data) && $metadata->xmlDiscriminatorAttribute && null !== $metadata->xmlDiscriminatorNamespace && isset($data->attributes($metadata->xmlDiscriminatorNamespace)->{$metadata->discriminatorFieldName}):
                $typeValue = (string)$data->attributes($metadata->xmlDiscriminatorNamespace)->{$metadata->discriminatorFieldName};
                break;

            // Check XML element with namespace for discriminatorFieldName
            case \is_object($data) && !$metadata->xmlDiscriminatorAttribute && null !== $metadata->xmlDiscriminatorNamespace && isset($data->children($metadata->xmlDiscriminatorNamespace)->{$metadata->discriminatorFieldName}):
                $typeValue = (string)$data->children($metadata->xmlDiscriminatorNamespace)->{$metadata->discriminatorFieldName};
                break;

            // Check XML element for discriminatorFieldName
            case \is_object($data) && isset($data->{$metadata->discriminatorFieldName}):
                $typeValue = (string)$data->{$metadata->discriminatorFieldName};
                break;

            default:
                throw new \LogicException(sprintf(
                    'The discriminator field name "%s" for base-class "%s" was not found in input data.',
                    $metadata->discriminatorFieldName,
                    $metadata->name
                ));
        }

        if (!isset($metadata->discriminatorMap[$typeValue])) {
            throw new \LogicException(sprintf(
                'The type value "%s" does not exist in the discriminator map of class "%s". Available types: %s',
                $typeValue,
                $metadata->name,
                implode(', ', array_keys($metadata->discriminatorMap))
            ));
        }

        return $this->metadataFactory->getMetadataForClass($metadata->discriminatorMap[$typeValue]);
    }

    private function leaveScope(Context $context, $data)
    {
        if ($context instanceof SerializationContext) {
            $context->stopVisiting($data);
        } elseif ($context instanceof DeserializationContext) {
            $context->decreaseDepth();
        }
    }

    private function afterVisitingObject(ClassMetadata $metadata, $object, array $type, Context $context)
    {
        $this->leaveScope($context, $object);
        $context->popClassMetadata();

        if ($context instanceof SerializationContext) {
            foreach ($metadata->postSerializeMethods as $method) {
                $method->invoke($object);
            }

            if (null !== $this->dispatcher && $this->dispatcher->hasListeners('serializer.post_serialize', $metadata->name, $context->getFormat())) {
                $this->dispatcher->dispatch('serializer.post_serialize', $metadata->name, $context->getFormat(), new ObjectEvent($context, $object, $type));
            }

            return;
        }

        foreach ($metadata->postDeserializeMethods as $method) {
            $method->invoke($object);
        }

        if (null !== $this->dispatcher && $this->dispatcher->hasListeners('serializer.post_deserialize', $metadata->name, $context->getFormat())) {
            $this->dispatcher->dispatch('serializer.post_deserialize', $metadata->name, $context->getFormat(), new ObjectEvent($context, $object, $type));
        }
    }
}
serializer/src/JMS/Serializer/Metadata/Driver/DoctrinePHPCRTypeDriver.php000064400000003745147361032420022327 0ustar00<?php

namespace JMS\Serializer\Metadata\Driver;

use Doctrine\Common\Persistence\Mapping\ClassMetadata as DoctrineClassMetadata;
use JMS\Serializer\Metadata\PropertyMetadata;

/**
 * This class decorates any other driver. If the inner driver does not provide a
 * a property type, the decorator will guess based on Doctrine 2 metadata.
 */
class DoctrinePHPCRTypeDriver extends AbstractDoctrineTypeDriver
{
    /**
     * @param DoctrineClassMetadata $doctrineMetadata
     * @param PropertyMetadata $propertyMetadata
     */
    protected function hideProperty(DoctrineClassMetadata $doctrineMetadata, PropertyMetadata $propertyMetadata)
    {
        return 'lazyPropertiesDefaults' === $propertyMetadata->name
            || $doctrineMetadata->parentMapping === $propertyMetadata->name
            || $doctrineMetadata->node === $propertyMetadata->name;
    }

    protected function setPropertyType(DoctrineClassMetadata $doctrineMetadata, PropertyMetadata $propertyMetadata)
    {
        $propertyName = $propertyMetadata->name;
        if ($doctrineMetadata->hasField($propertyName) && $fieldType = $this->normalizeFieldType($doctrineMetadata->getTypeOfField($propertyName))) {
            $field = $doctrineMetadata->getFieldMapping($propertyName);
            if (!empty($field['multivalue'])) {
                $fieldType = 'array';
            }

            $propertyMetadata->setType($fieldType);
        } elseif ($doctrineMetadata->hasAssociation($propertyName)) {
            try {
                $targetEntity = $doctrineMetadata->getAssociationTargetClass($propertyName);
            } catch (\Exception $e) {
                return;
            }

            if (null === $this->tryLoadingDoctrineMetadata($targetEntity)) {
                return;
            }

            if (!$doctrineMetadata->isSingleValuedAssociation($propertyName)) {
                $targetEntity = "ArrayCollection<{$targetEntity}>";
            }

            $propertyMetadata->setType($targetEntity);
        }
    }
}
serializer/src/JMS/Serializer/Metadata/Driver/AnnotationDriver.php000064400000027075147361032420021235 0ustar00<?php

namespace JMS\Serializer\Metadata\Driver;

use Doctrine\Common\Annotations\Reader;
use JMS\Serializer\Annotation\Accessor;
use JMS\Serializer\Annotation\AccessorOrder;
use JMS\Serializer\Annotation\AccessType;
use JMS\Serializer\Annotation\Discriminator;
use JMS\Serializer\Annotation\Exclude;
use JMS\Serializer\Annotation\ExcludeIf;
use JMS\Serializer\Annotation\ExclusionPolicy;
use JMS\Serializer\Annotation\Expose;
use JMS\Serializer\Annotation\Groups;
use JMS\Serializer\Annotation\HandlerCallback;
use JMS\Serializer\Annotation\Inline;
use JMS\Serializer\Annotation\MaxDepth;
use JMS\Serializer\Annotation\PostDeserialize;
use JMS\Serializer\Annotation\PostSerialize;
use JMS\Serializer\Annotation\PreSerialize;
use JMS\Serializer\Annotation\ReadOnlyProperty;
use JMS\Serializer\Annotation\SerializedName;
use JMS\Serializer\Annotation\Since;
use JMS\Serializer\Annotation\SkipWhenEmpty;
use JMS\Serializer\Annotation\Type;
use JMS\Serializer\Annotation\Until;
use JMS\Serializer\Annotation\VirtualProperty;
use JMS\Serializer\Annotation\XmlAttribute;
use JMS\Serializer\Annotation\XmlAttributeMap;
use JMS\Serializer\Annotation\XmlDiscriminator;
use JMS\Serializer\Annotation\XmlElement;
use JMS\Serializer\Annotation\XmlKeyValuePairs;
use JMS\Serializer\Annotation\XmlList;
use JMS\Serializer\Annotation\XmlMap;
use JMS\Serializer\Annotation\XmlNamespace;
use JMS\Serializer\Annotation\XmlRoot;
use JMS\Serializer\Annotation\XmlValue;
use JMS\Serializer\Exception\InvalidArgumentException;
use JMS\Serializer\GraphNavigator;
use JMS\Serializer\Metadata\ClassMetadata;
use JMS\Serializer\Metadata\ExpressionPropertyMetadata;
use JMS\Serializer\Metadata\PropertyMetadata;
use JMS\Serializer\Metadata\VirtualPropertyMetadata;
use Metadata\Driver\DriverInterface;
use Metadata\MethodMetadata;

class AnnotationDriver implements DriverInterface
{
    private $reader;

    public function __construct(Reader $reader)
    {
        $this->reader = $reader;
    }

    public function loadMetadataForClass(\ReflectionClass $class)
    {
        $classMetadata = new ClassMetadata($name = $class->name);
        $classMetadata->fileResources[] = $class->getFilename();

        $propertiesMetadata = array();
        $propertiesAnnotations = array();

        $exclusionPolicy = 'NONE';
        $excludeAll = false;
        $classAccessType = PropertyMetadata::ACCESS_TYPE_PROPERTY;
        $readOnlyClass = false;
        foreach ($this->reader->getClassAnnotations($class) as $annot) {
            if ($annot instanceof ExclusionPolicy) {
                $exclusionPolicy = $annot->policy;
            } elseif ($annot instanceof XmlRoot) {
                $classMetadata->xmlRootName = $annot->name;
                $classMetadata->xmlRootNamespace = $annot->namespace;
            } elseif ($annot instanceof XmlNamespace) {
                $classMetadata->registerNamespace($annot->uri, $annot->prefix);
            } elseif ($annot instanceof Exclude) {
                $excludeAll = true;
            } elseif ($annot instanceof AccessType) {
                $classAccessType = $annot->type;
            } elseif ($annot instanceof ReadOnlyProperty) {
                $readOnlyClass = true;
            } elseif ($annot instanceof AccessorOrder) {
                $classMetadata->setAccessorOrder($annot->order, $annot->custom);
            } elseif ($annot instanceof Discriminator) {
                if ($annot->disabled) {
                    $classMetadata->discriminatorDisabled = true;
                } else {
                    $classMetadata->setDiscriminator($annot->field, $annot->map, $annot->groups);
                }
            } elseif ($annot instanceof XmlDiscriminator) {
                $classMetadata->xmlDiscriminatorAttribute = (bool)$annot->attribute;
                $classMetadata->xmlDiscriminatorCData = (bool)$annot->cdata;
                $classMetadata->xmlDiscriminatorNamespace = $annot->namespace ? (string)$annot->namespace : null;
            } elseif ($annot instanceof VirtualProperty) {
                $virtualPropertyMetadata = new ExpressionPropertyMetadata($name, $annot->name, $annot->exp);
                $propertiesMetadata[] = $virtualPropertyMetadata;
                $propertiesAnnotations[] = $annot->options;
            }
        }

        foreach ($class->getMethods() as $method) {
            if ($method->class !== $name) {
                continue;
            }

            $methodAnnotations = $this->reader->getMethodAnnotations($method);

            foreach ($methodAnnotations as $annot) {
                if ($annot instanceof PreSerialize) {
                    $classMetadata->addPreSerializeMethod(new MethodMetadata($name, $method->name));
                    continue 2;
                } elseif ($annot instanceof PostDeserialize) {
                    $classMetadata->addPostDeserializeMethod(new MethodMetadata($name, $method->name));
                    continue 2;
                } elseif ($annot instanceof PostSerialize) {
                    $classMetadata->addPostSerializeMethod(new MethodMetadata($name, $method->name));
                    continue 2;
                } elseif ($annot instanceof VirtualProperty) {
                    $virtualPropertyMetadata = new VirtualPropertyMetadata($name, $method->name);
                    $propertiesMetadata[] = $virtualPropertyMetadata;
                    $propertiesAnnotations[] = $methodAnnotations;
                    continue 2;
                } elseif ($annot instanceof HandlerCallback) {
                    $classMetadata->addHandlerCallback(GraphNavigator::parseDirection($annot->direction), $annot->format, $method->name);
                    continue 2;
                }
            }
        }

        if (!$excludeAll) {
            foreach ($class->getProperties() as $property) {
                if ($property->class !== $name || (isset($property->info) && $property->info['class'] !== $name)) {
                    continue;
                }
                $propertiesMetadata[] = new PropertyMetadata($name, $property->getName());
                $propertiesAnnotations[] = $this->reader->getPropertyAnnotations($property);
            }

            foreach ($propertiesMetadata as $propertyKey => $propertyMetadata) {
                $isExclude = false;
                $isExpose = $propertyMetadata instanceof VirtualPropertyMetadata
                    || $propertyMetadata instanceof ExpressionPropertyMetadata;
                $propertyMetadata->readOnly = $propertyMetadata->readOnly || $readOnlyClass;
                $accessType = $classAccessType;
                $accessor = array(null, null);

                $propertyAnnotations = $propertiesAnnotations[$propertyKey];

                foreach ($propertyAnnotations as $annot) {
                    if ($annot instanceof Since) {
                        $propertyMetadata->sinceVersion = $annot->version;
                    } elseif ($annot instanceof Until) {
                        $propertyMetadata->untilVersion = $annot->version;
                    } elseif ($annot instanceof SerializedName) {
                        $propertyMetadata->serializedName = $annot->name;
                    } elseif ($annot instanceof SkipWhenEmpty) {
                        $propertyMetadata->skipWhenEmpty = true;
                    } elseif ($annot instanceof Expose) {
                        $isExpose = true;
                        if (null !== $annot->if) {
                            $propertyMetadata->excludeIf = "!(" . $annot->if . ")";
                        }
                    } elseif ($annot instanceof Exclude) {
                        if (null !== $annot->if) {
                            $propertyMetadata->excludeIf = $annot->if;
                        } else {
                            $isExclude = true;
                        }
                    } elseif ($annot instanceof Type) {
                        $propertyMetadata->setType($annot->name);
                    } elseif ($annot instanceof XmlElement) {
                        $propertyMetadata->xmlAttribute = false;
                        $propertyMetadata->xmlElementCData = $annot->cdata;
                        $propertyMetadata->xmlNamespace = $annot->namespace;
                    } elseif ($annot instanceof XmlList) {
                        $propertyMetadata->xmlCollection = true;
                        $propertyMetadata->xmlCollectionInline = $annot->inline;
                        $propertyMetadata->xmlEntryName = $annot->entry;
                        $propertyMetadata->xmlEntryNamespace = $annot->namespace;
                        $propertyMetadata->xmlCollectionSkipWhenEmpty = $annot->skipWhenEmpty;
                    } elseif ($annot instanceof XmlMap) {
                        $propertyMetadata->xmlCollection = true;
                        $propertyMetadata->xmlCollectionInline = $annot->inline;
                        $propertyMetadata->xmlEntryName = $annot->entry;
                        $propertyMetadata->xmlEntryNamespace = $annot->namespace;
                        $propertyMetadata->xmlKeyAttribute = $annot->keyAttribute;
                    } elseif ($annot instanceof XmlKeyValuePairs) {
                        $propertyMetadata->xmlKeyValuePairs = true;
                    } elseif ($annot instanceof XmlAttribute) {
                        $propertyMetadata->xmlAttribute = true;
                        $propertyMetadata->xmlNamespace = $annot->namespace;
                    } elseif ($annot instanceof XmlValue) {
                        $propertyMetadata->xmlValue = true;
                        $propertyMetadata->xmlElementCData = $annot->cdata;
                    } elseif ($annot instanceof XmlElement) {
                        $propertyMetadata->xmlElementCData = $annot->cdata;
                    } elseif ($annot instanceof AccessType) {
                        $accessType = $annot->type;
                    } elseif ($annot instanceof ReadOnlyProperty) {
                        $propertyMetadata->readOnly = $annot->readOnly;
                    } elseif ($annot instanceof Accessor) {
                        $accessor = array($annot->getter, $annot->setter);
                    } elseif ($annot instanceof Groups) {
                        $propertyMetadata->groups = $annot->groups;
                        foreach ((array)$propertyMetadata->groups as $groupName) {
                            if (false !== strpos($groupName, ',')) {
                                throw new InvalidArgumentException(sprintf(
                                    'Invalid group name "%s" on "%s", did you mean to create multiple groups?',
                                    implode(', ', $propertyMetadata->groups),
                                    $propertyMetadata->class . '->' . $propertyMetadata->name
                                ));
                            }
                        }
                    } elseif ($annot instanceof Inline) {
                        $propertyMetadata->inline = true;
                    } elseif ($annot instanceof XmlAttributeMap) {
                        $propertyMetadata->xmlAttributeMap = true;
                    } elseif ($annot instanceof MaxDepth) {
                        $propertyMetadata->maxDepth = $annot->depth;
                    }
                }


                if ((ExclusionPolicy::NONE === $exclusionPolicy && !$isExclude)
                    || (ExclusionPolicy::ALL === $exclusionPolicy && $isExpose)
                ) {
                    $propertyMetadata->setAccessor($accessType, $accessor[0], $accessor[1]);
                    $classMetadata->addPropertyMetadata($propertyMetadata);
                }
            }
        }

        return $classMetadata;
    }
}
serializer/src/JMS/Serializer/Metadata/Driver/NullDriver.php000064400000000644147361032420020026 0ustar00<?php

namespace JMS\Serializer\Metadata\Driver;

use JMS\Serializer\Metadata\ClassMetadata;
use Metadata\Driver\DriverInterface;

class NullDriver implements DriverInterface
{
    public function loadMetadataForClass(\ReflectionClass $class)
    {
        $classMetadata = new ClassMetadata($name = $class->name);
        $classMetadata->fileResources[] = $class->getFilename();

        return $classMetadata;
    }
}
serializer/src/JMS/Serializer/Metadata/Driver/AbstractDoctrineTypeDriver.php000064400000011052147361032420023204 0ustar00<?php

namespace JMS\Serializer\Metadata\Driver;

use Doctrine\Common\Persistence\ManagerRegistry;
use Doctrine\Common\Persistence\Mapping\ClassMetadata as DoctrineClassMetadata;
use JMS\Serializer\Metadata\ClassMetadata;
use JMS\Serializer\Metadata\ExpressionPropertyMetadata;
use JMS\Serializer\Metadata\PropertyMetadata;
use JMS\Serializer\Metadata\StaticPropertyMetadata;
use JMS\Serializer\Metadata\VirtualPropertyMetadata;
use Metadata\Driver\DriverInterface;

/**
 * This class decorates any other driver. If the inner driver does not provide a
 * a property type, the decorator will guess based on Doctrine 2 metadata.
 */
abstract class AbstractDoctrineTypeDriver implements DriverInterface
{
    /**
     * Map of doctrine 2 field types to JMS\Serializer types
     * @var array
     */
    protected $fieldMapping = array(
        'string' => 'string',
        'text' => 'string',
        'blob' => 'string',
        'guid' => 'string',

        'integer' => 'integer',
        'smallint' => 'integer',
        'bigint' => 'integer',

        'datetime' => 'DateTime',
        'datetimetz' => 'DateTime',
        'time' => 'DateTime',
        'date' => 'DateTime',

        'float' => 'float',
        'decimal' => 'float',

        'boolean' => 'boolean',

        'array' => 'array',
        'json_array' => 'array',
        'simple_array' => 'array<string>',
    );

    /**
     * @var DriverInterface
     */
    protected $delegate;

    /**
     * @var ManagerRegistry
     */
    protected $registry;

    public function __construct(DriverInterface $delegate, ManagerRegistry $registry)
    {
        $this->delegate = $delegate;
        $this->registry = $registry;
    }

    public function loadMetadataForClass(\ReflectionClass $class)
    {
        /** @var $classMetadata ClassMetadata */
        $classMetadata = $this->delegate->loadMetadataForClass($class);

        // Abort if the given class is not a mapped entity
        if (!$doctrineMetadata = $this->tryLoadingDoctrineMetadata($class->name)) {
            return $classMetadata;
        }

        $this->setDiscriminator($doctrineMetadata, $classMetadata);

        // We base our scan on the internal driver's property list so that we
        // respect any internal white/blacklisting like in the AnnotationDriver
        foreach ($classMetadata->propertyMetadata as $key => $propertyMetadata) {
            /** @var $propertyMetadata PropertyMetadata */

            // If the inner driver provides a type, don't guess anymore.
            if ($propertyMetadata->type || $this->isVirtualProperty($propertyMetadata)) {
                continue;
            }

            if ($this->hideProperty($doctrineMetadata, $propertyMetadata)) {
                unset($classMetadata->propertyMetadata[$key]);
            }

            $this->setPropertyType($doctrineMetadata, $propertyMetadata);
        }

        return $classMetadata;
    }

    private function isVirtualProperty(PropertyMetadata $propertyMetadata)
    {
        return $propertyMetadata instanceof VirtualPropertyMetadata
            || $propertyMetadata instanceof StaticPropertyMetadata
            || $propertyMetadata instanceof ExpressionPropertyMetadata;
    }

    /**
     * @param DoctrineClassMetadata $doctrineMetadata
     * @param ClassMetadata $classMetadata
     */
    protected function setDiscriminator(DoctrineClassMetadata $doctrineMetadata, ClassMetadata $classMetadata)
    {
    }

    /**
     * @param DoctrineClassMetadata $doctrineMetadata
     * @param PropertyMetadata $propertyMetadata
     */
    protected function hideProperty(DoctrineClassMetadata $doctrineMetadata, PropertyMetadata $propertyMetadata)
    {
        return false;
    }

    /**
     * @param DoctrineClassMetadata $doctrineMetadata
     * @param PropertyMetadata $propertyMetadata
     */
    protected function setPropertyType(DoctrineClassMetadata $doctrineMetadata, PropertyMetadata $propertyMetadata)
    {
    }

    /**
     * @param string $className
     *
     * @return null|DoctrineClassMetadata
     */
    protected function tryLoadingDoctrineMetadata($className)
    {
        if (!$manager = $this->registry->getManagerForClass($className)) {
            return null;
        }

        if ($manager->getMetadataFactory()->isTransient($className)) {
            return null;
        }

        return $manager->getClassMetadata($className);
    }

    /**
     * @param string $type
     */
    protected function normalizeFieldType($type)
    {
        if (!isset($this->fieldMapping[$type])) {
            return;
        }

        return $this->fieldMapping[$type];
    }
}
serializer/src/JMS/Serializer/Metadata/Driver/PhpDriver.php000064400000001631147361032420017640 0ustar00<?php

namespace JMS\Serializer\Metadata\Driver;

use JMS\Serializer\Exception\RuntimeException;
use JMS\Serializer\Metadata\ClassMetadata;
use Metadata\Driver\AbstractFileDriver;

class PhpDriver extends AbstractFileDriver
{
    protected function loadMetadataFromFile(\ReflectionClass $class, $file)
    {
        $metadata = require $file;

        if (!$metadata instanceof ClassMetadata) {
            throw new RuntimeException(sprintf('The file %s was expected to return an instance of ClassMetadata, but returned %s.', $file, json_encode($metadata)));
        }
        if ($metadata->name !== $class->name) {
            throw new RuntimeException(sprintf('The file %s was expected to return metadata for class %s, but instead returned metadata for class %s.', $class->name, $metadata->name));
        }

        return $metadata;
    }

    protected function getExtension()
    {
        return 'php';
    }
}
serializer/src/JMS/Serializer/Metadata/Driver/XmlDriver.php000064400000036402147361032420017655 0ustar00<?php

namespace JMS\Serializer\Metadata\Driver;

use JMS\Serializer\Annotation\ExclusionPolicy;
use JMS\Serializer\Exception\RuntimeException;
use JMS\Serializer\Exception\XmlErrorException;
use JMS\Serializer\GraphNavigator;
use JMS\Serializer\Metadata\ClassMetadata;
use JMS\Serializer\Metadata\ExpressionPropertyMetadata;
use JMS\Serializer\Metadata\PropertyMetadata;
use JMS\Serializer\Metadata\VirtualPropertyMetadata;
use Metadata\Driver\AbstractFileDriver;
use Metadata\MethodMetadata;

class XmlDriver extends AbstractFileDriver
{
    protected function loadMetadataFromFile(\ReflectionClass $class, $path)
    {
        $previous = libxml_use_internal_errors(true);
        libxml_clear_errors();

        $elem = simplexml_load_file($path);
        libxml_use_internal_errors($previous);

        if (false === $elem) {
            throw new XmlErrorException(libxml_get_last_error());
        }

        $metadata = new ClassMetadata($name = $class->name);
        if (!$elems = $elem->xpath("./class[@name = '" . $name . "']")) {
            throw new RuntimeException(sprintf('Could not find class %s inside XML element.', $name));
        }
        $elem = reset($elems);

        $metadata->fileResources[] = $path;
        $metadata->fileResources[] = $class->getFileName();
        $exclusionPolicy = strtoupper($elem->attributes()->{'exclusion-policy'}) ?: 'NONE';
        $excludeAll = null !== ($exclude = $elem->attributes()->exclude) ? 'true' === strtolower($exclude) : false;
        $classAccessType = (string)($elem->attributes()->{'access-type'} ?: PropertyMetadata::ACCESS_TYPE_PROPERTY);

        $propertiesMetadata = array();
        $propertiesNodes = array();

        if (null !== $accessorOrder = $elem->attributes()->{'accessor-order'}) {
            $metadata->setAccessorOrder((string)$accessorOrder, preg_split('/\s*,\s*/', (string)$elem->attributes()->{'custom-accessor-order'}));
        }

        if (null !== $xmlRootName = $elem->attributes()->{'xml-root-name'}) {
            $metadata->xmlRootName = (string)$xmlRootName;
        }

        if (null !== $xmlRootNamespace = $elem->attributes()->{'xml-root-namespace'}) {
            $metadata->xmlRootNamespace = (string)$xmlRootNamespace;
        }

        $readOnlyClass = 'true' === strtolower($elem->attributes()->{'read-only'});

        $discriminatorFieldName = (string)$elem->attributes()->{'discriminator-field-name'};
        $discriminatorMap = array();
        foreach ($elem->xpath('./discriminator-class') as $entry) {
            if (!isset($entry->attributes()->value)) {
                throw new RuntimeException('Each discriminator-class element must have a "value" attribute.');
            }

            $discriminatorMap[(string)$entry->attributes()->value] = (string)$entry;
        }

        if ('true' === (string)$elem->attributes()->{'discriminator-disabled'}) {
            $metadata->discriminatorDisabled = true;
        } elseif (!empty($discriminatorFieldName) || !empty($discriminatorMap)) {

            $discriminatorGroups = array();
            foreach ($elem->xpath('./discriminator-groups/group') as $entry) {
                $discriminatorGroups[] = (string)$entry;
            }
            $metadata->setDiscriminator($discriminatorFieldName, $discriminatorMap, $discriminatorGroups);
        }

        foreach ($elem->xpath('./xml-namespace') as $xmlNamespace) {
            if (!isset($xmlNamespace->attributes()->uri)) {
                throw new RuntimeException('The prefix attribute must be set for all xml-namespace elements.');
            }

            if (isset($xmlNamespace->attributes()->prefix)) {
                $prefix = (string)$xmlNamespace->attributes()->prefix;
            } else {
                $prefix = null;
            }

            $metadata->registerNamespace((string)$xmlNamespace->attributes()->uri, $prefix);
        }

        foreach ($elem->xpath('./xml-discriminator') as $xmlDiscriminator) {
            if (isset($xmlDiscriminator->attributes()->attribute)) {
                $metadata->xmlDiscriminatorAttribute = (string)$xmlDiscriminator->attributes()->attribute === 'true';
            }
            if (isset($xmlDiscriminator->attributes()->cdata)) {
                $metadata->xmlDiscriminatorCData = (string)$xmlDiscriminator->attributes()->cdata === 'true';
            }
            if (isset($xmlDiscriminator->attributes()->namespace)) {
                $metadata->xmlDiscriminatorNamespace = (string)$xmlDiscriminator->attributes()->namespace;
            }
        }

        foreach ($elem->xpath('./virtual-property') as $method) {

            if (isset($method->attributes()->expression)) {
                $virtualPropertyMetadata = new ExpressionPropertyMetadata($name, (string)$method->attributes()->name, (string)$method->attributes()->expression);
            } else {
                if (!isset($method->attributes()->method)) {
                    throw new RuntimeException('The method attribute must be set for all virtual-property elements.');
                }
                $virtualPropertyMetadata = new VirtualPropertyMetadata($name, (string)$method->attributes()->method);
            }

            $propertiesMetadata[] = $virtualPropertyMetadata;
            $propertiesNodes[] = $method;
        }

        if (!$excludeAll) {

            foreach ($class->getProperties() as $property) {
                if ($property->class !== $name || (isset($property->info) && $property->info['class'] !== $name)) {
                    continue;
                }

                $propertiesMetadata[] = new PropertyMetadata($name, $pName = $property->getName());
                $pElems = $elem->xpath("./property[@name = '" . $pName . "']");

                $propertiesNodes[] = $pElems ? reset($pElems) : null;
            }

            foreach ($propertiesMetadata as $propertyKey => $pMetadata) {

                $isExclude = false;
                $isExpose = $pMetadata instanceof VirtualPropertyMetadata
                    || $pMetadata instanceof ExpressionPropertyMetadata;

                $pElem = $propertiesNodes[$propertyKey];
                if (!empty($pElem)) {

                    if (null !== $exclude = $pElem->attributes()->exclude) {
                        $isExclude = 'true' === strtolower($exclude);
                    }

                    if ($isExclude) {
                        continue;
                    }

                    if (null !== $expose = $pElem->attributes()->expose) {
                        $isExpose = 'true' === strtolower($expose);
                    }

                    if (null !== $excludeIf = $pElem->attributes()->{'exclude-if'}) {
                        $pMetadata->excludeIf = (string)$excludeIf;
                    }

                    if (null !== $skip = $pElem->attributes()->{'skip-when-empty'}) {
                        $pMetadata->skipWhenEmpty = 'true' === strtolower($skip);
                    }

                    if (null !== $excludeIf = $pElem->attributes()->{'expose-if'}) {
                        $pMetadata->excludeIf = "!(" . $excludeIf . ")";
                        $isExpose = true;
                    }

                    if (null !== $version = $pElem->attributes()->{'since-version'}) {
                        $pMetadata->sinceVersion = (string)$version;
                    }

                    if (null !== $version = $pElem->attributes()->{'until-version'}) {
                        $pMetadata->untilVersion = (string)$version;
                    }

                    if (null !== $serializedName = $pElem->attributes()->{'serialized-name'}) {
                        $pMetadata->serializedName = (string)$serializedName;
                    }

                    if (null !== $type = $pElem->attributes()->type) {
                        $pMetadata->setType((string)$type);
                    } elseif (isset($pElem->type)) {
                        $pMetadata->setType((string)$pElem->type);
                    }

                    if (null !== $groups = $pElem->attributes()->groups) {
                        $pMetadata->groups = preg_split('/\s*,\s*/', (string) trim($groups));
                    } elseif (isset($pElem->groups)) {
                        $pMetadata->groups = (array) $pElem->groups->value;
                    }

                    if (isset($pElem->{'xml-list'})) {

                        $pMetadata->xmlCollection = true;

                        $colConfig = $pElem->{'xml-list'};
                        if (isset($colConfig->attributes()->inline)) {
                            $pMetadata->xmlCollectionInline = 'true' === (string)$colConfig->attributes()->inline;
                        }

                        if (isset($colConfig->attributes()->{'entry-name'})) {
                            $pMetadata->xmlEntryName = (string)$colConfig->attributes()->{'entry-name'};
                        }

                        if (isset($colConfig->attributes()->{'skip-when-empty'})) {
                            $pMetadata->xmlCollectionSkipWhenEmpty = 'true' === (string)$colConfig->attributes()->{'skip-when-empty'};
                        } else {
                            $pMetadata->xmlCollectionSkipWhenEmpty = true;
                        }

                        if (isset($colConfig->attributes()->namespace)) {
                            $pMetadata->xmlEntryNamespace = (string)$colConfig->attributes()->namespace;
                        }
                    }

                    if (isset($pElem->{'xml-map'})) {
                        $pMetadata->xmlCollection = true;

                        $colConfig = $pElem->{'xml-map'};
                        if (isset($colConfig->attributes()->inline)) {
                            $pMetadata->xmlCollectionInline = 'true' === (string)$colConfig->attributes()->inline;
                        }

                        if (isset($colConfig->attributes()->{'entry-name'})) {
                            $pMetadata->xmlEntryName = (string)$colConfig->attributes()->{'entry-name'};
                        }

                        if (isset($colConfig->attributes()->namespace)) {
                            $pMetadata->xmlEntryNamespace = (string)$colConfig->attributes()->namespace;
                        }

                        if (isset($colConfig->attributes()->{'key-attribute-name'})) {
                            $pMetadata->xmlKeyAttribute = (string)$colConfig->attributes()->{'key-attribute-name'};
                        }
                    }

                    if (isset($pElem->{'xml-element'})) {
                        $colConfig = $pElem->{'xml-element'};
                        if (isset($colConfig->attributes()->cdata)) {
                            $pMetadata->xmlElementCData = 'true' === (string)$colConfig->attributes()->cdata;
                        }

                        if (isset($colConfig->attributes()->namespace)) {
                            $pMetadata->xmlNamespace = (string)$colConfig->attributes()->namespace;
                        }
                    }

                    if (isset($pElem->attributes()->{'xml-attribute'})) {
                        $pMetadata->xmlAttribute = 'true' === (string)$pElem->attributes()->{'xml-attribute'};
                    }

                    if (isset($pElem->attributes()->{'xml-attribute-map'})) {
                        $pMetadata->xmlAttributeMap = 'true' === (string)$pElem->attributes()->{'xml-attribute-map'};
                    }

                    if (isset($pElem->attributes()->{'xml-value'})) {
                        $pMetadata->xmlValue = 'true' === (string)$pElem->attributes()->{'xml-value'};
                    }

                    if (isset($pElem->attributes()->{'xml-key-value-pairs'})) {
                        $pMetadata->xmlKeyValuePairs = 'true' === (string)$pElem->attributes()->{'xml-key-value-pairs'};
                    }

                    if (isset($pElem->attributes()->{'max-depth'})) {
                        $pMetadata->maxDepth = (int)$pElem->attributes()->{'max-depth'};
                    }

                    //we need read-only before setter and getter set, because that method depends on flag being set
                    if (null !== $readOnly = $pElem->attributes()->{'read-only'}) {
                        $pMetadata->readOnly = 'true' === strtolower($readOnly);
                    } else {
                        $pMetadata->readOnly = $pMetadata->readOnly || $readOnlyClass;
                    }

                    $getter = $pElem->attributes()->{'accessor-getter'};
                    $setter = $pElem->attributes()->{'accessor-setter'};
                    $pMetadata->setAccessor(
                        (string)($pElem->attributes()->{'access-type'} ?: $classAccessType),
                        $getter ? (string)$getter : null,
                        $setter ? (string)$setter : null
                    );

                    if (null !== $inline = $pElem->attributes()->inline) {
                        $pMetadata->inline = 'true' === strtolower($inline);
                    }

                }

                if ((ExclusionPolicy::NONE === (string)$exclusionPolicy && !$isExclude)
                    || (ExclusionPolicy::ALL === (string)$exclusionPolicy && $isExpose)
                ) {

                    $metadata->addPropertyMetadata($pMetadata);
                }
            }
        }

        foreach ($elem->xpath('./callback-method') as $method) {
            if (!isset($method->attributes()->type)) {
                throw new RuntimeException('The type attribute must be set for all callback-method elements.');
            }
            if (!isset($method->attributes()->name)) {
                throw new RuntimeException('The name attribute must be set for all callback-method elements.');
            }

            switch ((string)$method->attributes()->type) {
                case 'pre-serialize':
                    $metadata->addPreSerializeMethod(new MethodMetadata($name, (string)$method->attributes()->name));
                    break;

                case 'post-serialize':
                    $metadata->addPostSerializeMethod(new MethodMetadata($name, (string)$method->attributes()->name));
                    break;

                case 'post-deserialize':
                    $metadata->addPostDeserializeMethod(new MethodMetadata($name, (string)$method->attributes()->name));
                    break;

                case 'handler':
                    if (!isset($method->attributes()->format)) {
                        throw new RuntimeException('The format attribute must be set for "handler" callback methods.');
                    }
                    if (!isset($method->attributes()->direction)) {
                        throw new RuntimeException('The direction attribute must be set for "handler" callback methods.');
                    }

                    $direction = GraphNavigator::parseDirection((string)$method->attributes()->direction);
                    $format = (string)$method->attributes()->format;
                    $metadata->addHandlerCallback($direction, $format, (string)$method->attributes()->name);

                    break;

                default:
                    throw new RuntimeException(sprintf('The type "%s" is not supported.', $method->attributes()->name));
            }
        }

        return $metadata;
    }

    protected function getExtension()
    {
        return 'xml';
    }
}
serializer/src/JMS/Serializer/Metadata/Driver/DoctrineTypeDriver.php000064400000004345147361032420021527 0ustar00<?php

namespace JMS\Serializer\Metadata\Driver;

use Doctrine\Common\Persistence\Mapping\ClassMetadata as DoctrineClassMetadata;
use JMS\Serializer\Metadata\ClassMetadata;
use JMS\Serializer\Metadata\PropertyMetadata;

/**
 * This class decorates any other driver. If the inner driver does not provide a
 * a property type, the decorator will guess based on Doctrine 2 metadata.
 */
class DoctrineTypeDriver extends AbstractDoctrineTypeDriver
{
    protected function setDiscriminator(DoctrineClassMetadata $doctrineMetadata, ClassMetadata $classMetadata)
    {
        if (empty($classMetadata->discriminatorMap) && !$classMetadata->discriminatorDisabled
            && !empty($doctrineMetadata->discriminatorMap) && $doctrineMetadata->isRootEntity()
        ) {
            $classMetadata->setDiscriminator(
                $doctrineMetadata->discriminatorColumn['name'],
                $doctrineMetadata->discriminatorMap
            );
        }
    }

    protected function setPropertyType(DoctrineClassMetadata $doctrineMetadata, PropertyMetadata $propertyMetadata)
    {
        $propertyName = $propertyMetadata->name;
        if ($doctrineMetadata->hasField($propertyName) && $fieldType = $this->normalizeFieldType($doctrineMetadata->getTypeOfField($propertyName))) {
            $propertyMetadata->setType($fieldType);
        } elseif ($doctrineMetadata->hasAssociation($propertyName)) {
            $targetEntity = $doctrineMetadata->getAssociationTargetClass($propertyName);

            if (null === $targetMetadata = $this->tryLoadingDoctrineMetadata($targetEntity)) {
                return;
            }

            // For inheritance schemes, we cannot add any type as we would only add the super-type of the hierarchy.
            // On serialization, this would lead to only the supertype being serialized, and properties of subtypes
            // being ignored.
            if ($targetMetadata instanceof DoctrineClassMetadata && !$targetMetadata->isInheritanceTypeNone()) {
                return;
            }

            if (!$doctrineMetadata->isSingleValuedAssociation($propertyName)) {
                $targetEntity = "ArrayCollection<{$targetEntity}>";
            }

            $propertyMetadata->setType($targetEntity);
        }
    }
}
serializer/src/JMS/Serializer/Metadata/Driver/YamlDriver.php000064400000033426147361032420020022 0ustar00<?php

namespace JMS\Serializer\Metadata\Driver;

use JMS\Serializer\Annotation\ExclusionPolicy;
use JMS\Serializer\Exception\RuntimeException;
use JMS\Serializer\GraphNavigator;
use JMS\Serializer\Metadata\ClassMetadata;
use JMS\Serializer\Metadata\ExpressionPropertyMetadata;
use JMS\Serializer\Metadata\PropertyMetadata;
use JMS\Serializer\Metadata\VirtualPropertyMetadata;
use Metadata\Driver\AbstractFileDriver;
use Metadata\MethodMetadata;
use Symfony\Component\Yaml\Yaml;

class YamlDriver extends AbstractFileDriver
{
    protected function loadMetadataFromFile(\ReflectionClass $class, $file)
    {
        $config = Yaml::parse(file_get_contents($file));

        if (!isset($config[$name = $class->name])) {
            throw new RuntimeException(sprintf('Expected metadata for class %s to be defined in %s.', $class->name, $file));
        }

        $config = $config[$name];
        $metadata = new ClassMetadata($name);
        $metadata->fileResources[] = $file;
        $metadata->fileResources[] = $class->getFileName();
        $exclusionPolicy = isset($config['exclusion_policy']) ? strtoupper($config['exclusion_policy']) : 'NONE';
        $excludeAll = isset($config['exclude']) ? (Boolean)$config['exclude'] : false;
        $classAccessType = isset($config['access_type']) ? $config['access_type'] : PropertyMetadata::ACCESS_TYPE_PROPERTY;
        $readOnlyClass = isset($config['read_only']) ? (Boolean)$config['read_only'] : false;
        $this->addClassProperties($metadata, $config);

        $propertiesMetadata = array();
        if (array_key_exists('virtual_properties', $config)) {
            foreach ($config['virtual_properties'] as $methodName => $propertySettings) {
                if (isset($propertySettings['exp'])) {
                    $virtualPropertyMetadata = new ExpressionPropertyMetadata($name, $methodName, $propertySettings['exp']);
                    unset($propertySettings['exp']);

                } else {

                    if (!$class->hasMethod($methodName)) {
                        throw new RuntimeException('The method ' . $methodName . ' not found in class ' . $class->name);
                    }
                    $virtualPropertyMetadata = new VirtualPropertyMetadata($name, $methodName);
                }
                $propertiesMetadata[$methodName] = $virtualPropertyMetadata;
                $config['properties'][$methodName] = $propertySettings;
            }
        }

        if (!$excludeAll) {
            foreach ($class->getProperties() as $property) {
                if ($property->class !== $name || (isset($property->info) && $property->info['class'] !== $name)) {
                    continue;
                }

                $pName = $property->getName();
                $propertiesMetadata[$pName] = new PropertyMetadata($name, $pName);
            }

            foreach ($propertiesMetadata as $pName => $pMetadata) {
                $isExclude = false;
                $isExpose = $pMetadata instanceof VirtualPropertyMetadata
                    || $pMetadata instanceof ExpressionPropertyMetadata
                    || (isset($config['properties']) && array_key_exists($pName, $config['properties']));

                if (isset($config['properties'][$pName])) {
                    $pConfig = $config['properties'][$pName];

                    if (isset($pConfig['exclude'])) {
                        $isExclude = (Boolean)$pConfig['exclude'];
                    }

                    if ($isExclude) {
                        continue;
                    }

                    if (isset($pConfig['expose'])) {
                        $isExpose = (Boolean)$pConfig['expose'];
                    }

                    if (isset($pConfig['skip_when_empty'])) {
                        $pMetadata->skipWhenEmpty = (Boolean)$pConfig['skip_when_empty'];
                    }

                    if (isset($pConfig['since_version'])) {
                        $pMetadata->sinceVersion = (string)$pConfig['since_version'];
                    }

                    if (isset($pConfig['until_version'])) {
                        $pMetadata->untilVersion = (string)$pConfig['until_version'];
                    }

                    if (isset($pConfig['exclude_if'])) {
                        $pMetadata->excludeIf = (string)$pConfig['exclude_if'];
                    }

                    if (isset($pConfig['expose_if'])) {
                        $pMetadata->excludeIf = "!(" . $pConfig['expose_if'] . ")";
                    }

                    if (isset($pConfig['serialized_name'])) {
                        $pMetadata->serializedName = (string)$pConfig['serialized_name'];
                    }

                    if (isset($pConfig['type'])) {
                        $pMetadata->setType((string)$pConfig['type']);
                    }

                    if (isset($pConfig['groups'])) {
                        $pMetadata->groups = $pConfig['groups'];
                    }

                    if (isset($pConfig['xml_list'])) {
                        $pMetadata->xmlCollection = true;

                        $colConfig = $pConfig['xml_list'];
                        if (isset($colConfig['inline'])) {
                            $pMetadata->xmlCollectionInline = (Boolean)$colConfig['inline'];
                        }

                        if (isset($colConfig['entry_name'])) {
                            $pMetadata->xmlEntryName = (string)$colConfig['entry_name'];
                        }

                        if (isset($colConfig['skip_when_empty'])) {
                            $pMetadata->xmlCollectionSkipWhenEmpty = (Boolean)$colConfig['skip_when_empty'];
                        } else {
                            $pMetadata->xmlCollectionSkipWhenEmpty = true;
                        }

                        if (isset($colConfig['namespace'])) {
                            $pMetadata->xmlEntryNamespace = (string)$colConfig['namespace'];
                        }
                    }

                    if (isset($pConfig['xml_map'])) {
                        $pMetadata->xmlCollection = true;

                        $colConfig = $pConfig['xml_map'];
                        if (isset($colConfig['inline'])) {
                            $pMetadata->xmlCollectionInline = (Boolean)$colConfig['inline'];
                        }

                        if (isset($colConfig['entry_name'])) {
                            $pMetadata->xmlEntryName = (string)$colConfig['entry_name'];
                        }

                        if (isset($colConfig['namespace'])) {
                            $pMetadata->xmlEntryNamespace = (string)$colConfig['namespace'];
                        }

                        if (isset($colConfig['key_attribute_name'])) {
                            $pMetadata->xmlKeyAttribute = $colConfig['key_attribute_name'];
                        }

                    }

                    if (isset($pConfig['xml_element'])) {
                        $colConfig = $pConfig['xml_element'];
                        if (isset($colConfig['cdata'])) {
                            $pMetadata->xmlElementCData = (Boolean)$colConfig['cdata'];
                        }

                        if (isset($colConfig['namespace'])) {
                            $pMetadata->xmlNamespace = (string)$colConfig['namespace'];
                        }
                    }

                    if (isset($pConfig['xml_attribute'])) {
                        $pMetadata->xmlAttribute = (Boolean)$pConfig['xml_attribute'];
                    }

                    if (isset($pConfig['xml_attribute_map'])) {
                        $pMetadata->xmlAttributeMap = (Boolean)$pConfig['xml_attribute_map'];
                    }

                    if (isset($pConfig['xml_value'])) {
                        $pMetadata->xmlValue = (Boolean)$pConfig['xml_value'];
                    }

                    if (isset($pConfig['xml_key_value_pairs'])) {
                        $pMetadata->xmlKeyValuePairs = (Boolean)$pConfig['xml_key_value_pairs'];
                    }

                    //we need read_only before setter and getter set, because that method depends on flag being set
                    if (isset($pConfig['read_only'])) {
                        $pMetadata->readOnly = (Boolean)$pConfig['read_only'];
                    } else {
                        $pMetadata->readOnly = $pMetadata->readOnly || $readOnlyClass;
                    }

                    $pMetadata->setAccessor(
                        isset($pConfig['access_type']) ? $pConfig['access_type'] : $classAccessType,
                        isset($pConfig['accessor']['getter']) ? $pConfig['accessor']['getter'] : null,
                        isset($pConfig['accessor']['setter']) ? $pConfig['accessor']['setter'] : null
                    );

                    if (isset($pConfig['inline'])) {
                        $pMetadata->inline = (Boolean)$pConfig['inline'];
                    }

                    if (isset($pConfig['max_depth'])) {
                        $pMetadata->maxDepth = (int)$pConfig['max_depth'];
                    }
                }
                if ((ExclusionPolicy::NONE === $exclusionPolicy && !$isExclude)
                    || (ExclusionPolicy::ALL === $exclusionPolicy && $isExpose)
                ) {
                    $metadata->addPropertyMetadata($pMetadata);
                }
            }
        }

        if (isset($config['handler_callbacks'])) {
            foreach ($config['handler_callbacks'] as $directionName => $formats) {
                $direction = GraphNavigator::parseDirection($directionName);
                foreach ($formats as $format => $methodName) {
                    $metadata->addHandlerCallback($direction, $format, $methodName);
                }
            }
        }

        if (isset($config['callback_methods'])) {
            $cConfig = $config['callback_methods'];

            if (isset($cConfig['pre_serialize'])) {
                $metadata->preSerializeMethods = $this->getCallbackMetadata($class, $cConfig['pre_serialize']);
            }
            if (isset($cConfig['post_serialize'])) {
                $metadata->postSerializeMethods = $this->getCallbackMetadata($class, $cConfig['post_serialize']);
            }
            if (isset($cConfig['post_deserialize'])) {
                $metadata->postDeserializeMethods = $this->getCallbackMetadata($class, $cConfig['post_deserialize']);
            }
        }

        return $metadata;
    }

    protected function getExtension()
    {
        return 'yml';
    }

    private function addClassProperties(ClassMetadata $metadata, array $config)
    {
        if (isset($config['custom_accessor_order']) && !isset($config['accessor_order'])) {
            $config['accessor_order'] = 'custom';
        }

        if (isset($config['accessor_order'])) {
            $metadata->setAccessorOrder($config['accessor_order'], isset($config['custom_accessor_order']) ? $config['custom_accessor_order'] : array());
        }

        if (isset($config['xml_root_name'])) {
            $metadata->xmlRootName = (string)$config['xml_root_name'];
        }

        if (isset($config['xml_root_namespace'])) {
            $metadata->xmlRootNamespace = (string)$config['xml_root_namespace'];
        }

        if (array_key_exists('xml_namespaces', $config)) {

            foreach ($config['xml_namespaces'] as $prefix => $uri) {
                $metadata->registerNamespace($uri, $prefix);
            }

        }

        if (isset($config['discriminator'])) {
            if (isset($config['discriminator']['disabled']) && true === $config['discriminator']['disabled']) {
                $metadata->discriminatorDisabled = true;
            } else {
                if (!isset($config['discriminator']['field_name'])) {
                    throw new RuntimeException('The "field_name" attribute must be set for discriminators.');
                }

                if (!isset($config['discriminator']['map']) || !\is_array($config['discriminator']['map'])) {
                    throw new RuntimeException('The "map" attribute must be set, and be an array for discriminators.');
                }
                $groups = isset($config['discriminator']['groups']) ? $config['discriminator']['groups'] : array();
                $metadata->setDiscriminator($config['discriminator']['field_name'], $config['discriminator']['map'], $groups);

                if (isset($config['discriminator']['xml_attribute'])) {
                    $metadata->xmlDiscriminatorAttribute = (bool)$config['discriminator']['xml_attribute'];
                }
                if (isset($config['discriminator']['xml_element'])) {
                    if (isset($config['discriminator']['xml_element']['cdata'])) {
                        $metadata->xmlDiscriminatorCData = (bool)$config['discriminator']['xml_element']['cdata'];
                    }
                    if (isset($config['discriminator']['xml_element']['namespace'])) {
                        $metadata->xmlDiscriminatorNamespace = (string)$config['discriminator']['xml_element']['namespace'];
                    }
                }

            }
        }
    }

    private function getCallbackMetadata(\ReflectionClass $class, $config)
    {
        if (\is_string($config)) {
            $config = array($config);
        } elseif (!\is_array($config)) {
            throw new RuntimeException(sprintf('callback methods expects a string, or an array of strings that represent method names, but got %s.', json_encode($config['pre_serialize'])));
        }

        $methods = array();
        foreach ($config as $name) {
            if (!$class->hasMethod($name)) {
                throw new RuntimeException(sprintf('The method %s does not exist in class %s.', $name, $class->name));
            }

            $methods[] = new MethodMetadata($class->name, $name);
        }

        return $methods;
    }
}
serializer/src/JMS/Serializer/Metadata/ExpressionPropertyMetadata.php000064400000003100147361032420022040 0ustar00<?php

namespace JMS\Serializer\Metadata;

use JMS\Serializer\Exception\ExpressionLanguageRequiredException;

/**
 * @Annotation
 * @Target("METHOD")
 *
 * @author Asmir Mustafic <goetas@gmail.com>
 */
class ExpressionPropertyMetadata extends PropertyMetadata
{
    /**
     * @var string
     */
    public $expression;

    public function __construct($class, $fieldName, $expression)
    {
        $this->class = $class;
        $this->name = $fieldName;
        $this->expression = $expression;
        $this->readOnly = true;
    }

    public function setAccessor($type, $getter = null, $setter = null)
    {
    }

    /**
     * @param object $object
     * @return mixed
     */
    public function getValue($object)
    {
        throw new ExpressionLanguageRequiredException(sprintf('The property %s on %s requires the expression accessor strategy to be enabled.', $this->name, $this->class));
    }

    public function setValue($obj, $value)
    {
        throw new \LogicException('ExpressionPropertyMetadata is immutable.');
    }

    public function serialize()
    {
        return serialize(array(
            $this->expression,
            parent::serialize()
        ));
    }

    public function unserialize($str)
    {
        $parentStr = $this->unserializeProperties($str);
        list($this->class, $this->name) = unserialize($parentStr);
    }

    protected function unserializeProperties($str)
    {
        list(
            $this->expression,
            $parentStr
            ) = unserialize($str);
        return parent::unserializeProperties($parentStr);
    }
}
serializer/src/JMS/Serializer/Metadata/PropertyMetadata.php000064400000015346147361032420017777 0ustar00<?php

namespace JMS\Serializer\Metadata;

use JMS\Serializer\Exception\RuntimeException;
use JMS\Serializer\TypeParser;
use Metadata\PropertyMetadata as BasePropertyMetadata;

class PropertyMetadata extends BasePropertyMetadata
{
    const ACCESS_TYPE_PROPERTY = 'property';
    const ACCESS_TYPE_PUBLIC_METHOD = 'public_method';

    public $sinceVersion;
    public $untilVersion;
    public $groups;
    public $serializedName;
    public $type;
    public $xmlCollection = false;
    public $xmlCollectionInline = false;
    public $xmlCollectionSkipWhenEmpty = true;
    public $xmlEntryName;
    public $xmlEntryNamespace;
    public $xmlKeyAttribute;
    public $xmlAttribute = false;
    public $xmlValue = false;
    public $xmlNamespace;
    public $xmlKeyValuePairs = false;
    public $xmlElementCData = true;
    public $getter;
    public $setter;
    public $inline = false;
    public $skipWhenEmpty = false;
    public $readOnly = false;
    public $xmlAttributeMap = false;
    public $maxDepth = null;
    public $excludeIf = null;

    private $closureAccessor;

    private static $typeParser;

    public function __construct($class, $name)
    {
        parent::__construct($class, $name);
        $this->initAccessor();
    }

    private function initAccessor()
    {
        $classRef = $this->reflection->getDeclaringClass();
        if ($classRef->isInternal() || $classRef->getProperty($this->name)->isStatic()) {
            $this->closureAccessor = function ($o) {
                return $this->reflection->getValue($o);
            };
        } else {
            $this->closureAccessor = \Closure::bind(function ($o, $name) {
                return $o->$name;
            }, null, $this->reflection->class);
        }
    }

    public function setAccessor($type, $getter = null, $setter = null)
    {
        if (self::ACCESS_TYPE_PUBLIC_METHOD === $type) {
            $class = $this->reflection->getDeclaringClass();

            if (empty($getter)) {
                if ($class->hasMethod('get' . $this->name) && $class->getMethod('get' . $this->name)->isPublic()) {
                    $getter = 'get' . $this->name;
                } elseif ($class->hasMethod('is' . $this->name) && $class->getMethod('is' . $this->name)->isPublic()) {
                    $getter = 'is' . $this->name;
                } elseif ($class->hasMethod('has' . $this->name) && $class->getMethod('has' . $this->name)->isPublic()) {
                    $getter = 'has' . $this->name;
                } else {
                    throw new RuntimeException(sprintf('There is neither a public %s method, nor a public %s method, nor a public %s method in class %s. Please specify which public method should be used for retrieving the value of the property %s.', 'get' . ucfirst($this->name), 'is' . ucfirst($this->name), 'has' . ucfirst($this->name), $this->class, $this->name));
                }
            }

            if (empty($setter) && !$this->readOnly) {
                if ($class->hasMethod('set' . $this->name) && $class->getMethod('set' . $this->name)->isPublic()) {
                    $setter = 'set' . $this->name;
                } else {
                    throw new RuntimeException(sprintf('There is no public %s method in class %s. Please specify which public method should be used for setting the value of the property %s.', 'set' . ucfirst($this->name), $this->class, $this->name));
                }
            }
        }

        $this->getter = $getter;
        $this->setter = $setter;
    }

    public function getValue($obj)
    {
        if (null === $this->getter) {
            if (null !== $this->closureAccessor) {
                $accessor = $this->closureAccessor;
                return $accessor($obj, $this->name);
            }

            return parent::getValue($obj);
        }

        return $obj->{$this->getter}();
    }

    public function setValue($obj, $value)
    {
        if (null === $this->setter) {
            parent::setValue($obj, $value);
            return;
        }

        $obj->{$this->setter}($value);
    }

    public function setType($type)
    {
        if (null === self::$typeParser) {
            self::$typeParser = new TypeParser();
        }

        $this->type = self::$typeParser->parse($type);
    }

    public function serialize()
    {
        return serialize(array(
            $this->sinceVersion,
            $this->untilVersion,
            $this->groups,
            $this->serializedName,
            $this->type,
            $this->xmlCollection,
            $this->xmlCollectionInline,
            $this->xmlEntryName,
            $this->xmlKeyAttribute,
            $this->xmlAttribute,
            $this->xmlValue,
            $this->xmlNamespace,
            $this->xmlKeyValuePairs,
            $this->xmlElementCData,
            $this->getter,
            $this->setter,
            $this->inline,
            $this->readOnly,
            $this->xmlAttributeMap,
            $this->maxDepth,
            parent::serialize(),
            'xmlEntryNamespace' => $this->xmlEntryNamespace,
            'xmlCollectionSkipWhenEmpty' => $this->xmlCollectionSkipWhenEmpty,
            'excludeIf' => $this->excludeIf,
            'skipWhenEmpty' => $this->skipWhenEmpty,
        ));
    }

    public function unserialize($str)
    {
        $parentStr = $this->unserializeProperties($str);
        parent::unserialize($parentStr);

        $this->initAccessor();
    }

    protected function unserializeProperties($str)
    {
        $unserialized = unserialize($str);
        list(
            $this->sinceVersion,
            $this->untilVersion,
            $this->groups,
            $this->serializedName,
            $this->type,
            $this->xmlCollection,
            $this->xmlCollectionInline,
            $this->xmlEntryName,
            $this->xmlKeyAttribute,
            $this->xmlAttribute,
            $this->xmlValue,
            $this->xmlNamespace,
            $this->xmlKeyValuePairs,
            $this->xmlElementCData,
            $this->getter,
            $this->setter,
            $this->inline,
            $this->readOnly,
            $this->xmlAttributeMap,
            $this->maxDepth,
            $parentStr
            ) = $unserialized;

        if (isset($unserialized['xmlEntryNamespace'])) {
            $this->xmlEntryNamespace = $unserialized['xmlEntryNamespace'];
        }
        if (isset($unserialized['xmlCollectionSkipWhenEmpty'])) {
            $this->xmlCollectionSkipWhenEmpty = $unserialized['xmlCollectionSkipWhenEmpty'];
        }
        if (isset($unserialized['excludeIf'])) {
            $this->excludeIf = $unserialized['excludeIf'];
        }
        if (isset($unserialized['skipWhenEmpty'])) {
            $this->skipWhenEmpty = $unserialized['skipWhenEmpty'];
        }

        return $parentStr;
    }
}
serializer/src/JMS/Serializer/Metadata/VirtualPropertyMetadata.php000064400000001540147361032420021335 0ustar00<?php

namespace JMS\Serializer\Metadata;

class VirtualPropertyMetadata extends PropertyMetadata
{
    public function __construct($class, $methodName)
    {
        if (0 === strpos($methodName, 'get')) {
            $fieldName = lcfirst(substr($methodName, 3));
        } else {
            $fieldName = $methodName;
        }

        $this->class = $class;
        $this->name = $fieldName;
        $this->getter = $methodName;
        $this->readOnly = true;
    }

    public function setValue($obj, $value)
    {
        throw new \LogicException('VirtualPropertyMetadata is immutable.');
    }

    public function setAccessor($type, $getter = null, $setter = null)
    {
    }

    public function unserialize($str)
    {
        $parentStr = $this->unserializeProperties($str);
        list($this->class, $this->name) = unserialize($parentStr);
    }
}
serializer/src/JMS/Serializer/Metadata/ClassMetadata.php000064400000031246147361032420017215 0ustar00<?php

namespace JMS\Serializer\Metadata;

use JMS\Serializer\Exception\InvalidArgumentException;
use Metadata\MergeableClassMetadata;
use Metadata\MergeableInterface;
use Metadata\MethodMetadata;
use Metadata\PropertyMetadata as BasePropertyMetadata;

/**
 * Class Metadata used to customize the serialization process.
 *
 * @author Johannes M. Schmitt <schmittjoh@gmail.com>
 */
class ClassMetadata extends MergeableClassMetadata
{
    const ACCESSOR_ORDER_UNDEFINED = 'undefined';
    const ACCESSOR_ORDER_ALPHABETICAL = 'alphabetical';
    const ACCESSOR_ORDER_CUSTOM = 'custom';

    /** @var \ReflectionMethod[] */
    public $preSerializeMethods = array();

    /** @var \ReflectionMethod[] */
    public $postSerializeMethods = array();

    /** @var \ReflectionMethod[] */
    public $postDeserializeMethods = array();

    public $xmlRootName;
    public $xmlRootNamespace;
    public $xmlNamespaces = array();
    public $accessorOrder;
    public $customOrder;
    public $usingExpression = false;
    public $handlerCallbacks = array();

    public $discriminatorDisabled = false;
    public $discriminatorBaseClass;
    public $discriminatorFieldName;
    public $discriminatorValue;
    public $discriminatorMap = array();
    public $discriminatorGroups = array();

    public $xmlDiscriminatorAttribute = false;
    public $xmlDiscriminatorCData = true;
    public $xmlDiscriminatorNamespace;

    public function setDiscriminator($fieldName, array $map, array $groups = array())
    {
        if (empty($fieldName)) {
            throw new \InvalidArgumentException('The $fieldName cannot be empty.');
        }

        if (empty($map)) {
            throw new \InvalidArgumentException('The discriminator map cannot be empty.');
        }

        $this->discriminatorBaseClass = $this->name;
        $this->discriminatorFieldName = $fieldName;
        $this->discriminatorMap = $map;
        $this->discriminatorGroups = $groups;

        $this->handleDiscriminatorProperty();
    }

    /**
     * Sets the order of properties in the class.
     *
     * @param string $order
     * @param array $customOrder
     *
     * @throws InvalidArgumentException When the accessor order is not valid
     * @throws InvalidArgumentException When the custom order is not valid
     */
    public function setAccessorOrder($order, array $customOrder = array())
    {
        if (!in_array($order, array(self::ACCESSOR_ORDER_UNDEFINED, self::ACCESSOR_ORDER_ALPHABETICAL, self::ACCESSOR_ORDER_CUSTOM), true)) {
            throw new InvalidArgumentException(sprintf('The accessor order "%s" is invalid.', $order));
        }

        foreach ($customOrder as $name) {
            if (!\is_string($name)) {
                throw new InvalidArgumentException(sprintf('$customOrder is expected to be a list of strings, but got element of value %s.', json_encode($name)));
            }
        }

        $this->accessorOrder = $order;
        $this->customOrder = array_flip($customOrder);
        $this->sortProperties();
    }

    public function addPropertyMetadata(BasePropertyMetadata $metadata)
    {
        parent::addPropertyMetadata($metadata);
        $this->sortProperties();
        if ($metadata instanceof PropertyMetadata && $metadata->excludeIf) {
            $this->usingExpression = true;
        }
    }

    public function addPreSerializeMethod(MethodMetadata $method)
    {
        $this->preSerializeMethods[] = $method;
    }

    public function addPostSerializeMethod(MethodMetadata $method)
    {
        $this->postSerializeMethods[] = $method;
    }

    public function addPostDeserializeMethod(MethodMetadata $method)
    {
        $this->postDeserializeMethods[] = $method;
    }

    /**
     * @param integer $direction
     * @param string|integer $format
     * @param string $methodName
     */
    public function addHandlerCallback($direction, $format, $methodName)
    {
        $this->handlerCallbacks[$direction][$format] = $methodName;
    }

    public function merge(MergeableInterface $object)
    {
        if (!$object instanceof ClassMetadata) {
            throw new InvalidArgumentException('$object must be an instance of ClassMetadata.');
        }
        parent::merge($object);

        $this->preSerializeMethods = array_merge($this->preSerializeMethods, $object->preSerializeMethods);
        $this->postSerializeMethods = array_merge($this->postSerializeMethods, $object->postSerializeMethods);
        $this->postDeserializeMethods = array_merge($this->postDeserializeMethods, $object->postDeserializeMethods);
        $this->xmlRootName = $object->xmlRootName;
        $this->xmlRootNamespace = $object->xmlRootNamespace;
        $this->xmlNamespaces = array_merge($this->xmlNamespaces, $object->xmlNamespaces);

        // Handler methods are taken from the outer class completely.
        $this->handlerCallbacks = $object->handlerCallbacks;

        if ($object->accessorOrder) {
            $this->accessorOrder = $object->accessorOrder;
            $this->customOrder = $object->customOrder;
        }

        if ($object->discriminatorFieldName && $this->discriminatorFieldName) {
            throw new \LogicException(sprintf(
                'The discriminator of class "%s" would overwrite the discriminator of the parent class "%s". Please define all possible sub-classes in the discriminator of %s.',
                $object->name,
                $this->discriminatorBaseClass,
                $this->discriminatorBaseClass
            ));
        } elseif (!$this->discriminatorFieldName && $object->discriminatorFieldName) {
            $this->discriminatorFieldName = $object->discriminatorFieldName;
            $this->discriminatorMap = $object->discriminatorMap;
        }

        if ($object->discriminatorDisabled !== null) {
            $this->discriminatorDisabled = $object->discriminatorDisabled;
        }

        if ($object->discriminatorMap) {
            $this->discriminatorFieldName = $object->discriminatorFieldName;
            $this->discriminatorMap = $object->discriminatorMap;
            $this->discriminatorBaseClass = $object->discriminatorBaseClass;
        }

        $this->handleDiscriminatorProperty();

        $this->sortProperties();
    }

    public function registerNamespace($uri, $prefix = null)
    {
        if (!\is_string($uri)) {
            throw new InvalidArgumentException(sprintf('$uri is expected to be a strings, but got value %s.', json_encode($uri)));
        }

        if ($prefix !== null) {
            if (!\is_string($prefix)) {
                throw new InvalidArgumentException(sprintf('$prefix is expected to be a strings, but got value %s.', json_encode($prefix)));
            }
        } else {
            $prefix = "";
        }

        $this->xmlNamespaces[$prefix] = $uri;

    }

    public function serialize()
    {
        $this->sortProperties();

        return serialize(array(
            $this->preSerializeMethods,
            $this->postSerializeMethods,
            $this->postDeserializeMethods,
            $this->xmlRootName,
            $this->xmlRootNamespace,
            $this->xmlNamespaces,
            $this->accessorOrder,
            $this->customOrder,
            $this->handlerCallbacks,
            $this->discriminatorDisabled,
            $this->discriminatorBaseClass,
            $this->discriminatorFieldName,
            $this->discriminatorValue,
            $this->discriminatorMap,
            $this->discriminatorGroups,
            parent::serialize(),
            'discriminatorGroups' => $this->discriminatorGroups,
            'xmlDiscriminatorAttribute' => $this->xmlDiscriminatorAttribute,
            'xmlDiscriminatorCData' => $this->xmlDiscriminatorCData,
            'usingExpression' => $this->usingExpression,
            'xmlDiscriminatorNamespace' => $this->xmlDiscriminatorNamespace,
        ));
    }

    public function unserialize($str)
    {
        $unserialized = unserialize($str);

        list(
            $this->preSerializeMethods,
            $this->postSerializeMethods,
            $this->postDeserializeMethods,
            $this->xmlRootName,
            $this->xmlRootNamespace,
            $this->xmlNamespaces,
            $this->accessorOrder,
            $this->customOrder,
            $this->handlerCallbacks,
            $this->discriminatorDisabled,
            $this->discriminatorBaseClass,
            $this->discriminatorFieldName,
            $this->discriminatorValue,
            $this->discriminatorMap,
            $this->discriminatorGroups,
            $parentStr
            ) = $unserialized;

        if (isset($unserialized['discriminatorGroups'])) {
            $this->discriminatorGroups = $unserialized['discriminatorGroups'];
        }
        if (isset($unserialized['usingExpression'])) {
            $this->usingExpression = $unserialized['usingExpression'];
        }

        if (isset($unserialized['xmlDiscriminatorAttribute'])) {
            $this->xmlDiscriminatorAttribute = $unserialized['xmlDiscriminatorAttribute'];
        }

        if (isset($unserialized['xmlDiscriminatorNamespace'])) {
            $this->xmlDiscriminatorNamespace = $unserialized['xmlDiscriminatorNamespace'];
        }

        if (isset($unserialized['xmlDiscriminatorCData'])) {
            $this->xmlDiscriminatorCData = $unserialized['xmlDiscriminatorCData'];
        }

        parent::unserialize($parentStr);
    }

    private function handleDiscriminatorProperty()
    {
        if ($this->discriminatorMap && !$this->reflection->isAbstract() && !$this->reflection->isInterface()) {
            if (false === $typeValue = array_search($this->name, $this->discriminatorMap, true)) {
                if ($this->discriminatorBaseClass === $this->name) {
                    @trigger_error(
                        'Discriminator map was configured on non-abstract parent class but parent class'
                        .' was not included into discriminator map. It will throw exception in next major version.'
                        .' Either declare parent as abstract class or add it into discriminator map.',
                        E_USER_DEPRECATED
                    );
                } else {
                    throw new \LogicException(sprintf(
                        'The sub-class "%s" is not listed in the discriminator of the base class "%s".',
                        $this->name,
                        $this->discriminatorBaseClass
                    ));
                }
            }

            $this->discriminatorValue = $typeValue;

            if (isset($this->propertyMetadata[$this->discriminatorFieldName])
                && !$this->propertyMetadata[$this->discriminatorFieldName] instanceof StaticPropertyMetadata
            ) {
                throw new \LogicException(sprintf(
                    'The discriminator field name "%s" of the base-class "%s" conflicts with a regular property of the sub-class "%s".',
                    $this->discriminatorFieldName,
                    $this->discriminatorBaseClass,
                    $this->name
                ));
            }

            $discriminatorProperty = new StaticPropertyMetadata(
                $this->name,
                $this->discriminatorFieldName,
                $typeValue,
                $this->discriminatorGroups
            );
            $discriminatorProperty->serializedName = $this->discriminatorFieldName;
            $discriminatorProperty->xmlAttribute = $this->xmlDiscriminatorAttribute;
            $discriminatorProperty->xmlElementCData = $this->xmlDiscriminatorCData;
            $discriminatorProperty->xmlNamespace = $this->xmlDiscriminatorNamespace;
            $this->propertyMetadata[$this->discriminatorFieldName] = $discriminatorProperty;
        }
    }

    private function sortProperties()
    {
        switch ($this->accessorOrder) {
            case self::ACCESSOR_ORDER_ALPHABETICAL:
                ksort($this->propertyMetadata);
                break;

            case self::ACCESSOR_ORDER_CUSTOM:
                $order = $this->customOrder;
                $currentSorting = $this->propertyMetadata ? array_combine(array_keys($this->propertyMetadata), range(1, \count($this->propertyMetadata))) : [];
                uksort($this->propertyMetadata, function ($a, $b) use ($order, $currentSorting) {
                    $existsA = isset($order[$a]);
                    $existsB = isset($order[$b]);

                    if (!$existsA && !$existsB) {
                        return $currentSorting[$a] - $currentSorting[$b];
                    }

                    if (!$existsA) {
                        return 1;
                    }

                    if (!$existsB) {
                        return -1;
                    }

                    return $order[$a] < $order[$b] ? -1 : 1;
                });
                break;
        }
    }
}
serializer/src/JMS/Serializer/Metadata/StaticPropertyMetadata.php000064400000002320147361032420021133 0ustar00<?php

namespace JMS\Serializer\Metadata;

class StaticPropertyMetadata extends PropertyMetadata
{
    private $value;

    public function __construct($className, $fieldName, $fieldValue, array $groups = array())
    {
        $this->class = $className;
        $this->name = $fieldName;
        $this->value = $fieldValue;
        $this->readOnly = true;
        $this->groups = $groups;
    }

    public function getValue($obj)
    {
        return $this->value;
    }

    public function setValue($obj, $value)
    {
        throw new \LogicException('StaticPropertyMetadata is immutable.');
    }

    public function setAccessor($type, $getter = null, $setter = null)
    {
    }

    public function serialize()
    {
        return serialize(array(
            $this->value,
            parent::serialize()
        ));
    }

    public function unserialize($str)
    {
        $parentStr = $this->unserializeProperties($str);
        list($this->class, $this->name) = unserialize($parentStr);
    }

    protected function unserializeProperties($str)
    {
        list(
            $this->value,
            $parentStr
            ) = unserialize($str);
        return parent::unserializeProperties($parentStr);
    }
}
serializer/src/JMS/Serializer/JsonSerializationVisitor.php000064400000014752147361032420020021 0ustar00<?php

namespace JMS\Serializer;

use JMS\Serializer\Exception\InvalidArgumentException;
use JMS\Serializer\Metadata\ClassMetadata;
use JMS\Serializer\Metadata\PropertyMetadata;
use JMS\Serializer\Naming\AdvancedNamingStrategyInterface;

class JsonSerializationVisitor extends GenericSerializationVisitor
{
    private $options = 0;

    private $navigator;
    private $root;
    private $dataStack;
    private $data;

    public function setNavigator(GraphNavigator $navigator)
    {
        $this->navigator = $navigator;
        $this->root = null;
        $this->dataStack = new \SplStack;
    }

    /**
     * @return GraphNavigator
     */
    public function getNavigator()
    {
        return $this->navigator;
    }

    public function visitNull($data, array $type, Context $context)
    {
        return null;
    }

    public function visitString($data, array $type, Context $context)
    {
        if (null === $this->root) {
            $this->root = $data;
        }

        return (string)$data;
    }

    public function visitBoolean($data, array $type, Context $context)
    {
        if (null === $this->root) {
            $this->root = $data;
        }

        return (boolean)$data;
    }

    public function visitInteger($data, array $type, Context $context)
    {
        if (null === $this->root) {
            $this->root = $data;
        }

        return (int)$data;
    }

    public function visitDouble($data, array $type, Context $context)
    {
        if (null === $this->root) {
            $this->root = $data;
        }

        return (float)$data;
    }

    /**
     * @param array $data
     * @param array $type
     * @param Context $context
     * @return mixed
     */
    public function visitArray($data, array $type, Context $context)
    {
        $this->dataStack->push($data);

        $isHash = isset($type['params'][1]);

        if (null === $this->root) {
            $this->root = $isHash ? new \ArrayObject() : array();
            $rs = &$this->root;
        } else {
            $rs = $isHash ? new \ArrayObject() : array();
        }

        $isList = isset($type['params'][0]) && !isset($type['params'][1]);

        foreach ($data as $k => $v) {
            $v = $this->navigator->accept($v, $this->getElementType($type), $context);

            if (null === $v && $context->shouldSerializeNull() !== true) {
                continue;
            }

            if ($isList) {
                $rs[] = $v;
            } else {
                $rs[$k] = $v;
            }
        }

        $this->dataStack->pop();
        return $rs;
    }

    public function startVisitingObject(ClassMetadata $metadata, $data, array $type, Context $context)
    {
        if (null === $this->root) {
            $this->root = new \stdClass;
        }

        $this->dataStack->push($this->data);
        $this->data = array();
    }

    public function endVisitingObject(ClassMetadata $metadata, $data, array $type, Context $context)
    {
        $rs = $this->data;
        $this->data = $this->dataStack->pop();

        // Force JSON output to "{}" instead of "[]" if it contains either no properties or all properties are null.
        if (empty($rs)) {
            $rs = new \ArrayObject();
        }

        if ($this->root instanceof \stdClass && 0 === $this->dataStack->count()) {
            $this->root = $rs;
        }

        return $rs;
    }

    public function visitProperty(PropertyMetadata $metadata, $data, Context $context)
    {
        $v = $this->accessor->getValue($data, $metadata);

        $v = $this->navigator->accept($v, $metadata->type, $context);
        if ((null === $v && $context->shouldSerializeNull() !== true)
            || (true === $metadata->skipWhenEmpty && ($v instanceof \ArrayObject || \is_array($v)) && 0 === count($v))
        ) {
            return;
        }

        if ($this->namingStrategy instanceof AdvancedNamingStrategyInterface) {
            $k = $this->namingStrategy->getPropertyName($metadata, $context);
        } else {
            $k = $this->namingStrategy->translateName($metadata);
        }

        if ($metadata->inline) {
            if (\is_array($v) || ($v instanceof \ArrayObject)) {
                $this->data = array_merge($this->data, (array) $v);
            }
        } else {
            $this->data[$k] = $v;
        }
    }

    /**
     * Allows you to add additional data to the current object/root element.
     * @deprecated use setData instead
     * @param string $key
     * @param integer|float|boolean|string|array|null $value This value must either be a regular scalar, or an array.
     *                                                       It must not contain any objects anymore.
     */
    public function addData($key, $value)
    {
        if (isset($this->data[$key])) {
            throw new InvalidArgumentException(sprintf('There is already data for "%s".', $key));
        }

        $this->data[$key] = $value;
    }

    /**
     * Checks if some data key exists.
     *
     * @param string $key
     * @return boolean
     */
    public function hasData($key)
    {
        return isset($this->data[$key]);
    }

    /**
     * Allows you to replace existing data on the current object/root element.
     *
     * @param string $key
     * @param integer|float|boolean|string|array|null $value This value must either be a regular scalar, or an array.
     *                                                       It must not contain any objects anymore.
     */
    public function setData($key, $value)
    {
        $this->data[$key] = $value;
    }

    public function getRoot()
    {
        return $this->root;
    }

    /**
     * @param array|\ArrayObject $data the passed data must be understood by whatever encoding function is applied later.
     */
    public function setRoot($data)
    {
        $this->root = $data;
    }


    public function getResult()
    {
        $result = @json_encode($this->getRoot(), $this->options);

        switch (json_last_error()) {
            case JSON_ERROR_NONE:
                return $result;

            case JSON_ERROR_UTF8:
                throw new \RuntimeException('Your data could not be encoded because it contains invalid UTF8 characters.');

            default:
                throw new \RuntimeException(sprintf('An error occurred while encoding your data (error code %d).', json_last_error()));
        }
    }

    public function getOptions()
    {
        return $this->options;
    }

    public function setOptions($options)
    {
        $this->options = (integer)$options;
    }
}
serializer/src/JMS/Serializer/Serializer.php000064400000020604147361032420015074 0ustar00<?php

namespace JMS\Serializer;

use JMS\Serializer\Construction\ObjectConstructorInterface;
use JMS\Serializer\ContextFactory\DefaultDeserializationContextFactory;
use JMS\Serializer\ContextFactory\DefaultSerializationContextFactory;
use JMS\Serializer\ContextFactory\DeserializationContextFactoryInterface;
use JMS\Serializer\ContextFactory\SerializationContextFactoryInterface;
use JMS\Serializer\EventDispatcher\EventDispatcherInterface;
use JMS\Serializer\Exception\RuntimeException;
use JMS\Serializer\Exception\UnsupportedFormatException;
use JMS\Serializer\Expression\ExpressionEvaluatorInterface;
use JMS\Serializer\Handler\HandlerRegistryInterface;
use Metadata\MetadataFactoryInterface;
use PhpCollection\MapInterface;

/**
 * Serializer Implementation.
 *
 * @author Johannes M. Schmitt <schmittjoh@gmail.com>
 */
class Serializer implements SerializerInterface, ArrayTransformerInterface
{
    private $factory;
    private $handlerRegistry;
    private $objectConstructor;
    private $dispatcher;
    private $typeParser;

    /** @var \PhpCollection\MapInterface */
    private $serializationVisitors;

    /** @var \PhpCollection\MapInterface */
    private $deserializationVisitors;

    private $navigator;

    /**
     * @var SerializationContextFactoryInterface
     */
    private $serializationContextFactory;

    /**
     * @var DeserializationContextFactoryInterface
     */
    private $deserializationContextFactory;

    /**
     * Constructor.
     *
     * @param \Metadata\MetadataFactoryInterface $factory
     * @param Handler\HandlerRegistryInterface $handlerRegistry
     * @param Construction\ObjectConstructorInterface $objectConstructor
     * @param \PhpCollection\MapInterface $serializationVisitors of VisitorInterface
     * @param \PhpCollection\MapInterface $deserializationVisitors of VisitorInterface
     * @param EventDispatcher\EventDispatcherInterface $dispatcher
     * @param TypeParser $typeParser
     * @param ExpressionEvaluatorInterface|null $expressionEvaluator
     */
    public function __construct(
        MetadataFactoryInterface $factory,
        HandlerRegistryInterface $handlerRegistry,
        ObjectConstructorInterface $objectConstructor,
        MapInterface $serializationVisitors,
        MapInterface $deserializationVisitors,
        EventDispatcherInterface $dispatcher = null,
        TypeParser $typeParser = null,
        ExpressionEvaluatorInterface $expressionEvaluator = null
    )
    {
        $this->factory = $factory;
        $this->handlerRegistry = $handlerRegistry;
        $this->objectConstructor = $objectConstructor;
        $this->dispatcher = $dispatcher;
        $this->typeParser = $typeParser ?: new TypeParser();
        $this->serializationVisitors = $serializationVisitors;
        $this->deserializationVisitors = $deserializationVisitors;

        $this->navigator = new GraphNavigator($this->factory, $this->handlerRegistry, $this->objectConstructor, $this->dispatcher, $expressionEvaluator);

        $this->serializationContextFactory = new DefaultSerializationContextFactory();
        $this->deserializationContextFactory = new DefaultDeserializationContextFactory();
    }

    public function serialize($data, $format, SerializationContext $context = null)
    {
        if (null === $context) {
            $context = $this->serializationContextFactory->createSerializationContext();
        }

        return $this->serializationVisitors->get($format)
            ->map(function (VisitorInterface $visitor) use ($context, $data, $format) {
                $type = $context->getInitialType() !== null ? $this->typeParser->parse($context->getInitialType()) : null;

                $this->visit($visitor, $context, $visitor->prepare($data), $format, $type);

                return $visitor->getResult();
            })
            ->getOrThrow(new UnsupportedFormatException(sprintf('The format "%s" is not supported for serialization.', $format)));
    }

    public function deserialize($data, $type, $format, DeserializationContext $context = null)
    {
        if (null === $context) {
            $context = $this->deserializationContextFactory->createDeserializationContext();
        }

        return $this->deserializationVisitors->get($format)
            ->map(function (VisitorInterface $visitor) use ($context, $data, $format, $type) {
                $preparedData = $visitor->prepare($data);
                $navigatorResult = $this->visit($visitor, $context, $preparedData, $format, $this->typeParser->parse($type));

                return $this->handleDeserializeResult($visitor->getResult(), $navigatorResult);
            })
            ->getOrThrow(new UnsupportedFormatException(sprintf('The format "%s" is not supported for deserialization.', $format)));
    }

    /**
     * {@InheritDoc}
     */
    public function toArray($data, SerializationContext $context = null)
    {
        if (null === $context) {
            $context = $this->serializationContextFactory->createSerializationContext();
        }

        return $this->serializationVisitors->get('json')
            ->map(function (JsonSerializationVisitor $visitor) use ($context, $data) {
                $type = $context->getInitialType() !== null ? $this->typeParser->parse($context->getInitialType()) : null;

                $this->visit($visitor, $context, $data, 'json', $type);
                $result = $this->convertArrayObjects($visitor->getRoot());

                if (!\is_array($result)) {
                    throw new RuntimeException(sprintf(
                        'The input data of type "%s" did not convert to an array, but got a result of type "%s".',
                        \is_object($data) ? \get_class($data) : \gettype($data),
                        \is_object($result) ? \get_class($result) : \gettype($result)
                    ));
                }

                return $result;
            })
            ->get();
    }

    /**
     * {@InheritDoc}
     */
    public function fromArray(array $data, $type, DeserializationContext $context = null)
    {
        if (null === $context) {
            $context = $this->deserializationContextFactory->createDeserializationContext();
        }

        return $this->deserializationVisitors->get('json')
            ->map(function (JsonDeserializationVisitor $visitor) use ($data, $type, $context) {
                $navigatorResult = $this->visit($visitor, $context, $data, 'json', $this->typeParser->parse($type));

                return $this->handleDeserializeResult($visitor->getResult(), $navigatorResult);
            })
            ->get();
    }

    private function visit(VisitorInterface $visitor, Context $context, $data, $format, array $type = null)
    {
        $context->initialize(
            $format,
            $visitor,
            $this->navigator,
            $this->factory
        );

        $visitor->setNavigator($this->navigator);

        return $this->navigator->accept($data, $type, $context);
    }

    private function handleDeserializeResult($visitorResult, $navigatorResult)
    {
        // This is a special case if the root is handled by a callback on the object itself.
        if (null === $visitorResult && null !== $navigatorResult) {
            return $navigatorResult;
        }

        return $visitorResult;
    }

    private function convertArrayObjects($data)
    {
        if ($data instanceof \ArrayObject || $data instanceof \stdClass) {
            $data = (array)$data;
        }
        if (\is_array($data)) {
            foreach ($data as $k => $v) {
                $data[$k] = $this->convertArrayObjects($v);
            }
        }

        return $data;
    }

    /**
     * @return MetadataFactoryInterface
     */
    public function getMetadataFactory()
    {
        return $this->factory;
    }

    /**
     * @param SerializationContextFactoryInterface $serializationContextFactory
     *
     * @return self
     */
    public function setSerializationContextFactory(SerializationContextFactoryInterface $serializationContextFactory)
    {
        $this->serializationContextFactory = $serializationContextFactory;

        return $this;
    }

    /**
     * @param DeserializationContextFactoryInterface $deserializationContextFactory
     *
     * @return self
     */
    public function setDeserializationContextFactory(DeserializationContextFactoryInterface $deserializationContextFactory)
    {
        $this->deserializationContextFactory = $deserializationContextFactory;

        return $this;
    }
}
serializer/src/JMS/Serializer/Builder/CallbackDriverFactory.php000064400000001267147361032420020555 0ustar00<?php

namespace JMS\Serializer\Builder;

use Doctrine\Common\Annotations\Reader;
use Metadata\Driver\DriverInterface;

class CallbackDriverFactory implements DriverFactoryInterface
{
    private $callback;

    /**
     * @param callable $callable
     */
    public function __construct($callable)
    {
        $this->callback = $callable;
    }

    public function createDriver(array $metadataDirs, Reader $reader)
    {
        $driver = \call_user_func($this->callback, $metadataDirs, $reader);
        if (!$driver instanceof DriverInterface) {
            throw new \LogicException('The callback must return an instance of DriverInterface.');
        }

        return $driver;
    }
}
serializer/src/JMS/Serializer/Builder/DefaultDriverFactory.php000064400000001466147361032420020446 0ustar00<?php

namespace JMS\Serializer\Builder;

use Doctrine\Common\Annotations\Reader;
use JMS\Serializer\Metadata\Driver\AnnotationDriver;
use JMS\Serializer\Metadata\Driver\XmlDriver;
use JMS\Serializer\Metadata\Driver\YamlDriver;
use Metadata\Driver\DriverChain;
use Metadata\Driver\FileLocator;

class DefaultDriverFactory implements DriverFactoryInterface
{
    public function createDriver(array $metadataDirs, Reader $annotationReader)
    {
        if (!empty($metadataDirs)) {
            $fileLocator = new FileLocator($metadataDirs);

            return new DriverChain(array(
                new YamlDriver($fileLocator),
                new XmlDriver($fileLocator),
                new AnnotationDriver($annotationReader),
            ));
        }

        return new AnnotationDriver($annotationReader);
    }
}
serializer/src/JMS/Serializer/Builder/DriverFactoryInterface.php000064400000000554147361032420020757 0ustar00<?php

namespace JMS\Serializer\Builder;

use Doctrine\Common\Annotations\Reader;
use Metadata\Driver\DriverInterface;

interface DriverFactoryInterface
{
    /**
     * @param array $metadataDirs
     * @param Reader $annotationReader
     *
     * @return DriverInterface
     */
    public function createDriver(array $metadataDirs, Reader $annotationReader);
}serializer/src/JMS/Serializer/XmlSerializationVisitor.php000064400000042363147361032420017647 0ustar00<?php

namespace JMS\Serializer;

use JMS\Serializer\Accessor\AccessorStrategyInterface;
use JMS\Serializer\Exception\RuntimeException;
use JMS\Serializer\Metadata\ClassMetadata;
use JMS\Serializer\Metadata\PropertyMetadata;
use JMS\Serializer\Naming\AdvancedNamingStrategyInterface;
use JMS\Serializer\Naming\PropertyNamingStrategyInterface;

/**
 * XmlSerializationVisitor.
 *
 * @author Johannes M. Schmitt <schmittjoh@gmail.com>
 */
class XmlSerializationVisitor extends AbstractVisitor
{
    public $document;

    private $navigator;
    private $defaultRootName = 'result';
    private $defaultRootNamespace;
    private $defaultVersion = '1.0';
    private $defaultEncoding = 'UTF-8';
    private $stack;
    private $metadataStack;
    private $currentNode;
    private $currentMetadata;
    private $hasValue;
    private $nullWasVisited;
    private $objectMetadataStack;

    /** @var boolean */
    private $formatOutput;

    public function __construct($namingStrategy, AccessorStrategyInterface $accessorStrategy = null)
    {
        parent::__construct($namingStrategy, $accessorStrategy);
        $this->objectMetadataStack = new \SplStack;
        $this->formatOutput = true;
    }

    public function setDefaultRootName($name, $namespace = null)
    {
        $this->defaultRootName = $name;
        $this->defaultRootNamespace = $namespace;
    }

    /**
     * @return boolean
     */
    public function hasDefaultRootName()
    {
        return 'result' === $this->defaultRootName;
    }

    public function setDefaultVersion($version)
    {
        $this->defaultVersion = $version;
    }

    public function setDefaultEncoding($encoding)
    {
        $this->defaultEncoding = $encoding;
    }

    public function setNavigator(GraphNavigator $navigator)
    {
        $this->navigator = $navigator;
        $this->document = null;
        $this->stack = new \SplStack;
        $this->metadataStack = new \SplStack;
    }

    public function getNavigator()
    {
        return $this->navigator;
    }

    public function visitNull($data, array $type, Context $context)
    {
        if (null === $this->document) {
            $this->document = $this->createDocument(null, null, true);
            $node = $this->document->createAttribute('xsi:nil');
            $node->value = 'true';
            $this->currentNode->appendChild($node);

            $this->attachNullNamespace();

            return;
        }

        $node = $this->document->createAttribute('xsi:nil');
        $node->value = 'true';
        $this->attachNullNamespace();

        return $node;
    }

    public function visitString($data, array $type, Context $context)
    {

        if (null !== $this->currentMetadata) {
            $doCData = $this->currentMetadata->xmlElementCData;
        } else {
            $doCData = true;
        }

        if (null === $this->document) {
            $this->document = $this->createDocument(null, null, true);
            $this->currentNode->appendChild($doCData ? $this->document->createCDATASection($data) : $this->document->createTextNode((string)$data));

            return;
        }

        return $doCData ? $this->document->createCDATASection($data) : $this->document->createTextNode((string)$data);
    }

    public function visitSimpleString($data, array $type, Context $context)
    {
        if (null === $this->document) {
            $this->document = $this->createDocument(null, null, true);
            $this->currentNode->appendChild($this->document->createTextNode((string)$data));

            return;
        }

        return $this->document->createTextNode((string)$data);
    }

    public function visitBoolean($data, array $type, Context $context)
    {
        if (null === $this->document) {
            $this->document = $this->createDocument(null, null, true);
            $this->currentNode->appendChild($this->document->createTextNode($data ? 'true' : 'false'));

            return;
        }

        return $this->document->createTextNode($data ? 'true' : 'false');
    }

    public function visitInteger($data, array $type, Context $context)
    {
        return $this->visitNumeric($data, $type);
    }

    public function visitDouble($data, array $type, Context $context)
    {
        return $this->visitNumeric($data, $type);
    }

    public function visitArray($data, array $type, Context $context)
    {
        if (null === $this->document) {
            $this->document = $this->createDocument(null, null, true);
        }

        $entryName = (null !== $this->currentMetadata && null !== $this->currentMetadata->xmlEntryName) ? $this->currentMetadata->xmlEntryName : 'entry';
        $keyAttributeName = (null !== $this->currentMetadata && null !== $this->currentMetadata->xmlKeyAttribute) ? $this->currentMetadata->xmlKeyAttribute : null;
        $namespace = (null !== $this->currentMetadata && null !== $this->currentMetadata->xmlEntryNamespace) ? $this->currentMetadata->xmlEntryNamespace : null;

        foreach ($data as $k => $v) {

            if (null === $v && $context->shouldSerializeNull() !== true) {
                continue;
            }

            $tagName = (null !== $this->currentMetadata && $this->currentMetadata->xmlKeyValuePairs && $this->isElementNameValid($k)) ? $k : $entryName;

            $entryNode = $this->createElement($tagName, $namespace);
            $this->currentNode->appendChild($entryNode);
            $this->setCurrentNode($entryNode);

            if (null !== $keyAttributeName) {
                $entryNode->setAttribute($keyAttributeName, (string)$k);
            }

            if (null !== $node = $this->navigator->accept($v, $this->getElementType($type), $context)) {
                $this->currentNode->appendChild($node);
            }

            $this->revertCurrentNode();
        }
    }

    public function startVisitingObject(ClassMetadata $metadata, $data, array $type, Context $context)
    {
        $this->objectMetadataStack->push($metadata);

        if (null === $this->document) {
            $this->document = $this->createDocument(null, null, false);
            if ($metadata->xmlRootName) {
                $rootName = $metadata->xmlRootName;
                $rootNamespace = $metadata->xmlRootNamespace ?: $this->getClassDefaultNamespace($metadata);
            } else {
                $rootName = $this->defaultRootName;
                $rootNamespace = $this->defaultRootNamespace;
            }

            if ($rootNamespace) {
                $this->currentNode = $this->document->createElementNS($rootNamespace, $rootName);
            } else {
                $this->currentNode = $this->document->createElement($rootName);
            }

            $this->document->appendChild($this->currentNode);
        }

        $this->addNamespaceAttributes($metadata, $this->currentNode);

        $this->hasValue = false;
    }

    public function visitProperty(PropertyMetadata $metadata, $object, Context $context)
    {
        $v = $this->accessor->getValue($object, $metadata);

        if (null === $v && $context->shouldSerializeNull() !== true) {
            return;
        }

        if ($metadata->xmlAttribute) {
            $this->setCurrentMetadata($metadata);
            $node = $this->navigator->accept($v, $metadata->type, $context);
            $this->revertCurrentMetadata();

            if (!$node instanceof \DOMCharacterData) {
                throw new RuntimeException(sprintf('Unsupported value for XML attribute for %s. Expected character data, but got %s.', $metadata->name, json_encode($v)));
            }
            if ($this->namingStrategy instanceof AdvancedNamingStrategyInterface) {
                $attributeName = $this->namingStrategy->getPropertyName($metadata, $context);
            } else {
                $attributeName = $this->namingStrategy->translateName($metadata);
            }
            $this->setAttributeOnNode($this->currentNode, $attributeName, $node->nodeValue, $metadata->xmlNamespace);

            return;
        }

        if (($metadata->xmlValue && $this->currentNode->childNodes->length > 0)
            || (!$metadata->xmlValue && $this->hasValue)
        ) {
            throw new RuntimeException(sprintf('If you make use of @XmlValue, all other properties in the class must have the @XmlAttribute annotation. Invalid usage detected in class %s.', $metadata->class));
        }

        if ($metadata->xmlValue) {
            $this->hasValue = true;

            $this->setCurrentMetadata($metadata);
            $node = $this->navigator->accept($v, $metadata->type, $context);
            $this->revertCurrentMetadata();

            if (!$node instanceof \DOMCharacterData) {
                throw new RuntimeException(sprintf('Unsupported value for property %s::$%s. Expected character data, but got %s.', $metadata->reflection->class, $metadata->reflection->name, \is_object($node) ? \get_class($node) : \gettype($node)));
            }

            $this->currentNode->appendChild($node);

            return;
        }

        if ($metadata->xmlAttributeMap) {
            if (!\is_array($v)) {
                throw new RuntimeException(sprintf('Unsupported value type for XML attribute map. Expected array but got %s.', \gettype($v)));
            }

            foreach ($v as $key => $value) {
                $this->setCurrentMetadata($metadata);
                $node = $this->navigator->accept($value, null, $context);
                $this->revertCurrentMetadata();

                if (!$node instanceof \DOMCharacterData) {
                    throw new RuntimeException(sprintf('Unsupported value for a XML attribute map value. Expected character data, but got %s.', json_encode($v)));
                }

                $this->setAttributeOnNode($this->currentNode, $key, $node->nodeValue, $metadata->xmlNamespace);
            }

            return;
        }

        if ($addEnclosingElement = !$this->isInLineCollection($metadata) && !$metadata->inline) {
            if ($this->namingStrategy instanceof AdvancedNamingStrategyInterface) {
                $elementName = $this->namingStrategy->getPropertyName($metadata, $context);
            } else {
                $elementName = $this->namingStrategy->translateName($metadata);
            }

            $namespace = null !== $metadata->xmlNamespace
                ? $metadata->xmlNamespace
                : $this->getClassDefaultNamespace($this->objectMetadataStack->top());

            $element = $this->createElement($elementName, $namespace);
            $this->currentNode->appendChild($element);
            $this->setCurrentNode($element);
        }

        $this->setCurrentMetadata($metadata);

        if (null !== $node = $this->navigator->accept($v, $metadata->type, $context)) {
            $this->currentNode->appendChild($node);
        }

        $this->revertCurrentMetadata();

        if ($addEnclosingElement) {
            $this->revertCurrentNode();

            if ($this->isElementEmpty($element) && ($v === null || $this->isSkippableCollection($metadata) || $this->isSkippableEmptyObject($node, $metadata) || $this->isCircularRef($context, $v))) {
                $this->currentNode->removeChild($element);
            }
        }

        $this->hasValue = false;
    }

    private function isInLineCollection(PropertyMetadata $metadata)
    {
        return $metadata->xmlCollection && $metadata->xmlCollectionInline;
    }

    private function isCircularRef(SerializationContext $context, $v)
    {
        return $context->isVisiting($v);
    }

    private function isSkippableEmptyObject($node, PropertyMetadata $metadata)
    {
        return $node === null && !$metadata->xmlCollection && $metadata->skipWhenEmpty;
    }

    private function isSkippableCollection(PropertyMetadata $metadata)
    {
        return $metadata->xmlCollection && $metadata->xmlCollectionSkipWhenEmpty;
    }

    private function isElementEmpty(\DOMElement $element)
    {
        return !$element->hasChildNodes() && !$element->hasAttributes();
    }

    public function endVisitingObject(ClassMetadata $metadata, $data, array $type, Context $context)
    {
        $this->objectMetadataStack->pop();
    }

    public function getResult()
    {
        return $this->document->saveXML();
    }

    public function getCurrentNode()
    {
        return $this->currentNode;
    }

    public function getCurrentMetadata()
    {
        return $this->currentMetadata;
    }

    /**
     * @param bool $create (default = false)
     * @return \DOMDocument
     */
    public function getDocument()
    {
        if (func_num_args() === 1) {
            if (null === $this->document && func_get_arg(0) === true) {
                $this->document = $this->createDocument();
            }
        }

        return $this->document;
    }

    public function setCurrentMetadata(PropertyMetadata $metadata)
    {
        $this->metadataStack->push($this->currentMetadata);
        $this->currentMetadata = $metadata;
    }

    public function setCurrentNode(\DOMNode $node)
    {
        $this->stack->push($this->currentNode);
        $this->currentNode = $node;
    }

    public function revertCurrentNode()
    {
        return $this->currentNode = $this->stack->pop();
    }

    public function revertCurrentMetadata()
    {
        return $this->currentMetadata = $this->metadataStack->pop();
    }

    /**
     * @deprecated Use $this->getDocument(true) instead
     * @param null $version
     * @param null $encoding
     * @param bool $addRoot
     * @return \DOMDocument
     */
    public function createDocument($version = null, $encoding = null, $addRoot = true)
    {
        $doc = new \DOMDocument($version ?: $this->defaultVersion, $encoding ?: $this->defaultEncoding);
        $doc->formatOutput = $this->isFormatOutput();

        if ($addRoot) {
            if ($this->defaultRootNamespace) {
                $rootNode = $doc->createElementNS($this->defaultRootNamespace, $this->defaultRootName);
            } else {
                $rootNode = $doc->createElement($this->defaultRootName);
            }
            $this->setCurrentNode($rootNode);
            $doc->appendChild($rootNode);
        }

        return $doc;
    }

    public function prepare($data)
    {
        $this->nullWasVisited = false;

        return $data;
    }

    private function visitNumeric($data, array $type)
    {
        if (null === $this->document) {
            $this->document = $this->createDocument(null, null, true);
            $this->currentNode->appendChild($textNode = $this->document->createTextNode((string)$data));

            return $textNode;
        }

        return $this->document->createTextNode((string)$data);
    }

    /**
     * Checks that the name is a valid XML element name.
     *
     * @param string $name
     *
     * @return boolean
     */
    private function isElementNameValid($name)
    {
        return $name && false === strpos($name, ' ') && preg_match('#^[\pL_][\pL0-9._-]*$#ui', $name);
    }

    private function attachNullNamespace()
    {
        if (!$this->nullWasVisited) {
            $this->document->documentElement->setAttributeNS(
                'http://www.w3.org/2000/xmlns/',
                'xmlns:xsi',
                'http://www.w3.org/2001/XMLSchema-instance'
            );
            $this->nullWasVisited = true;
        }
    }

    /**
     * Adds namespace attributes to the XML root element
     *
     * @param \JMS\Serializer\Metadata\ClassMetadata $metadata
     * @param \DOMElement $element
     */
    private function addNamespaceAttributes(ClassMetadata $metadata, \DOMElement $element)
    {
        foreach ($metadata->xmlNamespaces as $prefix => $uri) {
            $attribute = 'xmlns';
            if ($prefix !== '') {
                $attribute .= ':' . $prefix;
            } elseif ($element->namespaceURI === $uri) {
                continue;
            }
            $element->setAttributeNS('http://www.w3.org/2000/xmlns/', $attribute, $uri);
        }
    }

    private function createElement($tagName, $namespace = null)
    {
        if (null === $namespace) {
            return $this->document->createElement($tagName);
        }
        if ($this->currentNode->isDefaultNamespace($namespace)) {
            return $this->document->createElementNS($namespace, $tagName);
        }
        if (!($prefix = $this->currentNode->lookupPrefix($namespace)) && !($prefix = $this->document->lookupPrefix($namespace))) {
            $prefix = 'ns-' . substr(sha1($namespace), 0, 8);
        }
        return $this->document->createElementNS($namespace, $prefix . ':' . $tagName);
    }

    private function setAttributeOnNode(\DOMElement $node, $name, $value, $namespace = null)
    {
        if (null !== $namespace) {
            if (!$prefix = $node->lookupPrefix($namespace)) {
                $prefix = 'ns-' . substr(sha1($namespace), 0, 8);
            }
            $node->setAttributeNS($namespace, $prefix . ':' . $name, $value);
        } else {
            $node->setAttribute($name, $value);
        }
    }

    private function getClassDefaultNamespace(ClassMetadata $metadata)
    {
        return (isset($metadata->xmlNamespaces['']) ? $metadata->xmlNamespaces[''] : null);
    }

    /**
     * @return bool
     */
    public function isFormatOutput()
    {
        return $this->formatOutput;
    }

    /**
     * @param bool $formatOutput
     */
    public function setFormatOutput($formatOutput)
    {
        $this->formatOutput = (boolean)$formatOutput;
    }
}
serializer/src/JMS/Serializer/Util/Writer.php000064400000005020147361032420015147 0ustar00<?php

namespace JMS\Serializer\Util;

use JMS\Serializer\Exception\RuntimeException;

/**
 * A writer implementation.
 *
 * This may be used to simplify writing well-formatted code.
 *
 * @author Johannes M. Schmitt <schmittjoh@gmail.com>
 */
class Writer
{
    public $indentationSpaces = 4;
    public $indentationLevel = 0;
    public $content = '';
    public $changeCount = 0;

    private $changes = array();

    public function indent()
    {
        $this->indentationLevel += 1;

        return $this;
    }

    public function outdent()
    {
        $this->indentationLevel -= 1;

        if ($this->indentationLevel < 0) {
            throw new RuntimeException('The identation level cannot be less than zero.');
        }

        return $this;
    }

    /**
     * @param string $content
     *
     * @return Writer
     */
    public function writeln($content)
    {
        $this->write($content . "\n");

        return $this;
    }

    public function revert()
    {
        $change = array_pop($this->changes);
        $this->changeCount -= 1;
        $this->content = substr($this->content, 0, -1 * \strlen($change));
    }

    /**
     * @param string $content
     *
     * @return Writer
     */
    public function write($content)
    {
        $addition = '';

        $lines = explode("\n", $content);
        for ($i = 0, $c = \count($lines); $i < $c; $i++) {
            if ($this->indentationLevel > 0
                && !empty($lines[$i])
                && ((empty($addition) && "\n" === substr($this->content, -1)) || "\n" === substr($addition, -1))
            ) {
                $addition .= str_repeat(' ', $this->indentationLevel * $this->indentationSpaces);
            }

            $addition .= $lines[$i];

            if ($i + 1 < $c) {
                $addition .= "\n";
            }
        }

        $this->content .= $addition;
        $this->changes[] = $addition;
        $this->changeCount += 1;

        return $this;
    }

    public function rtrim($preserveNewLines = true)
    {
        if (!$preserveNewLines) {
            $this->content = rtrim($this->content);

            return $this;
        }

        $addNl = "\n" === substr($this->content, -1);
        $this->content = rtrim($this->content);

        if ($addNl) {
            $this->content .= "\n";
        }

        return $this;
    }

    public function reset()
    {
        $this->content = '';
        $this->indentationLevel = 0;

        return $this;
    }

    public function getContent()
    {
        return $this->content;
    }
}
serializer/src/JMS/Serializer/DeserializationContext.php000064400000001173147361032420017456 0ustar00<?php

namespace JMS\Serializer;

class DeserializationContext extends Context
{
    private $depth = 0;

    public static function create()
    {
        return new self();
    }

    public function getDirection()
    {
        return GraphNavigator::DIRECTION_DESERIALIZATION;
    }

    public function getDepth()
    {
        return $this->depth;
    }

    public function increaseDepth()
    {
        $this->depth += 1;
    }

    public function decreaseDepth()
    {
        if ($this->depth <= 0) {
            throw new \LogicException('Depth cannot be smaller than zero.');
        }

        $this->depth -= 1;
    }
}
serializer/src/JMS/Serializer/Twig/SerializerExtension.php000064400000002164147361032420017704 0ustar00<?php

namespace JMS\Serializer\Twig;

use JMS\Serializer\SerializationContext;
use JMS\Serializer\SerializerInterface;

/**
 * Serializer helper twig extension
 *
 * Basically provides access to JMSSerializer from Twig
 */
class SerializerExtension extends \Twig_Extension
{
    protected $serializer;

    public function getName()
    {
        return 'jms_serializer';
    }

    public function __construct(SerializerInterface $serializer)
    {
        $this->serializer = $serializer;
    }

    public function getFilters()
    {
        return array(
            new \Twig_SimpleFilter('serialize', array($this, 'serialize')),
        );
    }

    public function getFunctions()
    {
        return array(
            new \Twig_SimpleFunction('serialization_context', '\JMS\Serializer\SerializationContext::create'),
        );
    }

    /**
     * @param object $object
     * @param string $type
     * @param SerializationContext $context
     */
    public function serialize($object, $type = 'json', SerializationContext $context = null)
    {
        return $this->serializer->serialize($object, $type, $context);
    }
}
serializer/src/JMS/Serializer/Twig/SerializerRuntimeHelper.php000064400000001241147361032420020506 0ustar00<?php

namespace JMS\Serializer\Twig;

use JMS\Serializer\SerializationContext;
use JMS\Serializer\SerializerInterface;

/**
 * @author Asmir Mustafic <goetas@gmail.com>
 */
final class SerializerRuntimeHelper
{
    protected $serializer;

    public function __construct(SerializerInterface $serializer)
    {
        $this->serializer = $serializer;
    }

    /**
     * @param $object
     * @param string $type
     * @param SerializationContext|null $context
     * @return string
     */
    public function serialize($object, $type = 'json', SerializationContext $context = null)
    {
        return $this->serializer->serialize($object, $type, $context);
    }
}
serializer/src/JMS/Serializer/Twig/SerializerRuntimeExtension.php000064400000001137147361032420021247 0ustar00<?php

namespace JMS\Serializer\Twig;

/**
 * @author Asmir Mustafic <goetas@gmail.com>
 */
final class SerializerRuntimeExtension extends \Twig_Extension
{

    public function getName()
    {
        return 'jms_serializer';
    }

    public function getFilters()
    {
        return array(
            new \Twig_SimpleFilter('serialize', array(SerializerRuntimeHelper::class, 'serialize')),
        );
    }

    public function getFunctions()
    {
        return array(
            new \Twig_SimpleFunction('serialization_context', '\JMS\Serializer\SerializationContext::create'),
        );
    }
}
serializer/src/JMS/Serializer/SerializationContext.php000064400000005360147361032420017147 0ustar00<?php

namespace JMS\Serializer;

use JMS\Serializer\Exception\RuntimeException;
use Metadata\MetadataFactoryInterface;

class SerializationContext extends Context
{
    /** @var \SplObjectStorage */
    private $visitingSet;

    /** @var \SplStack */
    private $visitingStack;

    /**
     * @var string
     */
    private $initialType;

    public static function create()
    {
        return new self();
    }

    /**
     * @param string $format
     */
    public function initialize($format, VisitorInterface $visitor, GraphNavigator $navigator, MetadataFactoryInterface $factory)
    {
        parent::initialize($format, $visitor, $navigator, $factory);

        $this->visitingSet = new \SplObjectStorage();
        $this->visitingStack = new \SplStack();
    }

    public function startVisiting($object)
    {
        if (!\is_object($object)) {
            return;
        }
        $this->visitingSet->attach($object);
        $this->visitingStack->push($object);
    }

    public function stopVisiting($object)
    {
        if (!\is_object($object)) {
            return;
        }
        $this->visitingSet->detach($object);
        $poppedObject = $this->visitingStack->pop();

        if ($object !== $poppedObject) {
            throw new RuntimeException('Context visitingStack not working well');
        }
    }

    public function isVisiting($object)
    {
        if (!\is_object($object)) {
            return false;
        }

        return $this->visitingSet->contains($object);
    }

    public function getPath()
    {
        $path = array();
        foreach ($this->visitingStack as $obj) {
            $path[] = \get_class($obj);
        }

        if (!$path) {
            return null;
        }

        return implode(' -> ', $path);
    }

    public function getDirection()
    {
        return GraphNavigator::DIRECTION_SERIALIZATION;
    }

    public function getDepth()
    {
        return $this->visitingStack->count();
    }

    public function getObject()
    {
        return !$this->visitingStack->isEmpty() ? $this->visitingStack->top() : null;
    }

    public function getVisitingStack()
    {
        return $this->visitingStack;
    }

    public function getVisitingSet()
    {
        return $this->visitingSet;
    }

    /**
     * @param string $type
     * @return $this
     */
    public function setInitialType($type)
    {
        $this->initialType = $type;
        $this->attributes->set('initial_type', $type);
        return $this;
    }

    /**
     * @return string|null
     */
    public function getInitialType()
    {
        return $this->initialType
            ? $this->initialType
            : ($this->attributes->containsKey('initial_type') ? $this->attributes->get('initial_type')->get() : null);
    }
}
serializer/src/JMS/Serializer/Handler/PropelCollectionHandler.php000064400000003733147361032420021117 0ustar00<?php

namespace JMS\Serializer\Handler;

use JMS\Serializer\Context;
use JMS\Serializer\GraphNavigator;
use JMS\Serializer\VisitorInterface;
use PropelCollection;

class PropelCollectionHandler implements SubscribingHandlerInterface
{
    public static function getSubscribingMethods()
    {
        $methods = array();
        $formats = array('json', 'xml', 'yml');
        //Note: issue when handling inheritance
        $collectionTypes = array(
            'PropelCollection',
            'PropelObjectCollection',
            'PropelArrayCollection',
            'PropelOnDemandCollection'
        );

        foreach ($collectionTypes as $type) {
            foreach ($formats as $format) {
                $methods[] = array(
                    'direction' => GraphNavigator::DIRECTION_SERIALIZATION,
                    'type' => $type,
                    'format' => $format,
                    'method' => 'serializeCollection',
                );

                $methods[] = array(
                    'direction' => GraphNavigator::DIRECTION_DESERIALIZATION,
                    'type' => $type,
                    'format' => $format,
                    'method' => 'deserializeCollection',
                );
            }
        }

        return $methods;
    }

    public function serializeCollection(VisitorInterface $visitor, PropelCollection $collection, array $type, Context $context)
    {
        // We change the base type, and pass through possible parameters.
        $type['name'] = 'array';

        return $visitor->visitArray($collection->getData(), $type, $context);
    }

    public function deserializeCollection(VisitorInterface $visitor, $data, array $type, Context $context)
    {
        // See above. Set parameter type to PropelCollection<T> or PropelCollection<K,V>
        $type['name'] = 'array';

        $collection = new PropelCollection();
        $collection->setData($visitor->visitArray($data, $type, $context));

        return $collection;
    }
}
serializer/src/JMS/Serializer/Handler/FormErrorHandler.php000064400000011567147361032420017563 0ustar00<?php

namespace JMS\Serializer\Handler;

use JMS\Serializer\GraphNavigator;
use JMS\Serializer\JsonSerializationVisitor;
use JMS\Serializer\VisitorInterface;
use JMS\Serializer\XmlSerializationVisitor;
use JMS\Serializer\YamlSerializationVisitor;
use Symfony\Component\Form\Form;
use Symfony\Component\Form\FormError;
use Symfony\Component\Translation\TranslatorInterface;

class FormErrorHandler implements SubscribingHandlerInterface
{
    private $translator;

    private $translationDomain;

    public static function getSubscribingMethods()
    {
        $methods = array();
        foreach (array('xml', 'json', 'yml') as $format) {
            $methods[] = array(
                'direction' => GraphNavigator::DIRECTION_SERIALIZATION,
                'type' => 'Symfony\Component\Form\Form',
                'format' => $format,
            );
            $methods[] = array(
                'direction' => GraphNavigator::DIRECTION_SERIALIZATION,
                'type' => 'Symfony\Component\Form\FormError',
                'format' => $format,
            );
        }

        return $methods;
    }

    public function __construct(TranslatorInterface $translator = null, $translationDomain = 'validators')
    {
        $this->translator = $translator;
        $this->translationDomain = $translationDomain;
    }

    public function serializeFormToXml(XmlSerializationVisitor $visitor, Form $form, array $type)
    {
        if (null === $visitor->document) {
            $visitor->document = $visitor->createDocument(null, null, false);
            $visitor->document->appendChild($formNode = $visitor->document->createElement('form'));
            $visitor->setCurrentNode($formNode);
        } else {
            $visitor->getCurrentNode()->appendChild(
                $formNode = $visitor->document->createElement('form')
            );
        }

        $formNode->setAttribute('name', $form->getName());

        $formNode->appendChild($errorsNode = $visitor->document->createElement('errors'));
        foreach ($form->getErrors() as $error) {
            $errorNode = $visitor->document->createElement('entry');
            $errorNode->appendChild($this->serializeFormErrorToXml($visitor, $error, array()));
            $errorsNode->appendChild($errorNode);
        }

        foreach ($form->all() as $child) {
            if ($child instanceof Form) {
                if (null !== $node = $this->serializeFormToXml($visitor, $child, array())) {
                    $formNode->appendChild($node);
                }
            }
        }

        return $formNode;
    }

    public function serializeFormToJson(JsonSerializationVisitor $visitor, Form $form, array $type)
    {
        return $this->convertFormToArray($visitor, $form);
    }

    public function serializeFormToYml(YamlSerializationVisitor $visitor, Form $form, array $type)
    {
        return $this->convertFormToArray($visitor, $form);
    }

    public function serializeFormErrorToXml(XmlSerializationVisitor $visitor, FormError $formError, array $type)
    {
        if (null === $visitor->document) {
            $visitor->document = $visitor->createDocument(null, null, true);
        }

        return $visitor->document->createCDATASection($this->getErrorMessage($formError));
    }

    public function serializeFormErrorToJson(JsonSerializationVisitor $visitor, FormError $formError, array $type)
    {
        return $this->getErrorMessage($formError);
    }

    public function serializeFormErrorToYml(YamlSerializationVisitor $visitor, FormError $formError, array $type)
    {
        return $this->getErrorMessage($formError);
    }

    private function getErrorMessage(FormError $error)
    {

        if ($this->translator === null){
            return $error->getMessage();
        }

        if (null !== $error->getMessagePluralization()) {
            return $this->translator->transChoice($error->getMessageTemplate(), $error->getMessagePluralization(), $error->getMessageParameters(), $this->translationDomain);
        }

        return $this->translator->trans($error->getMessageTemplate(), $error->getMessageParameters(), $this->translationDomain);
    }

    private function convertFormToArray(VisitorInterface $visitor, Form $data)
    {
        $isRoot = null === $visitor->getRoot();

        $form = new \ArrayObject();
        $errors = array();
        foreach ($data->getErrors() as $error) {
            $errors[] = $this->getErrorMessage($error);
        }

        if ($errors) {
            $form['errors'] = $errors;
        }

        $children = array();
        foreach ($data->all() as $child) {
            if ($child instanceof Form) {
                $children[$child->getName()] = $this->convertFormToArray($visitor, $child);
            }
        }

        if ($children) {
            $form['children'] = $children;
        }

        if ($isRoot) {
            $visitor->setRoot($form);
        }

        return $form;
    }
}
serializer/src/JMS/Serializer/Handler/LazyHandlerRegistry.php000064400000003313147361032420020304 0ustar00<?php

namespace JMS\Serializer\Handler;

use Psr\Container\ContainerInterface as PsrContainerInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;

class LazyHandlerRegistry extends HandlerRegistry
{
    private $container;
    private $initializedHandlers = array();

    public function __construct($container, array $handlers = array())
    {
        if (!$container instanceof PsrContainerInterface && !$container instanceof ContainerInterface) {
            throw new \InvalidArgumentException(sprintf('The container must be an instance of %s or %s (%s given).', PsrContainerInterface::class, ContainerInterface::class, \is_object($container) ? \get_class($container) : \gettype($container)));
        }

        parent::__construct($handlers);
        $this->container = $container;
    }

    public function registerHandler($direction, $typeName, $format, $handler)
    {
        parent::registerHandler($direction, $typeName, $format, $handler);
        unset($this->initializedHandlers[$direction][$typeName][$format]);
    }

    public function getHandler($direction, $typeName, $format)
    {
        if (isset($this->initializedHandlers[$direction][$typeName][$format])) {
            return $this->initializedHandlers[$direction][$typeName][$format];
        }

        if (!isset($this->handlers[$direction][$typeName][$format])) {
            return null;
        }

        $handler = $this->handlers[$direction][$typeName][$format];
        if (\is_array($handler) && \is_string($handler[0]) && $this->container->has($handler[0])) {
            $handler[0] = $this->container->get($handler[0]);
        }

        return $this->initializedHandlers[$direction][$typeName][$format] = $handler;
    }
}
serializer/src/JMS/Serializer/Handler/PhpCollectionHandler.php000064400000004276147361032420020410 0ustar00<?php

namespace JMS\Serializer\Handler;

use JMS\Serializer\Context;
use JMS\Serializer\GraphNavigator;
use JMS\Serializer\VisitorInterface;
use PhpCollection\Map;
use PhpCollection\Sequence;

class PhpCollectionHandler implements SubscribingHandlerInterface
{
    public static function getSubscribingMethods()
    {
        $methods = array();
        $formats = array('json', 'xml', 'yml');
        $collectionTypes = array(
            'PhpCollection\Sequence' => 'Sequence',
            'PhpCollection\Map' => 'Map',
        );

        foreach ($collectionTypes as $type => $shortName) {
            foreach ($formats as $format) {
                $methods[] = array(
                    'direction' => GraphNavigator::DIRECTION_SERIALIZATION,
                    'type' => $type,
                    'format' => $format,
                    'method' => 'serialize' . $shortName,
                );

                $methods[] = array(
                    'direction' => GraphNavigator::DIRECTION_DESERIALIZATION,
                    'type' => $type,
                    'format' => $format,
                    'method' => 'deserialize' . $shortName,
                );
            }
        }

        return $methods;
    }

    public function serializeMap(VisitorInterface $visitor, Map $map, array $type, Context $context)
    {
        $type['name'] = 'array';

        return $visitor->visitArray(iterator_to_array($map), $type, $context);
    }

    public function deserializeMap(VisitorInterface $visitor, $data, array $type, Context $context)
    {
        $type['name'] = 'array';

        return new Map($visitor->visitArray($data, $type, $context));
    }

    public function serializeSequence(VisitorInterface $visitor, Sequence $sequence, array $type, Context $context)
    {
        // We change the base type, and pass through possible parameters.
        $type['name'] = 'array';

        return $visitor->visitArray($sequence->all(), $type, $context);
    }

    public function deserializeSequence(VisitorInterface $visitor, $data, array $type, Context $context)
    {
        // See above.
        $type['name'] = 'array';

        return new Sequence($visitor->visitArray($data, $type, $context));
    }
}
serializer/src/JMS/Serializer/Handler/ArrayCollectionHandler.php000064400000005027147361032420020732 0ustar00<?php

namespace JMS\Serializer\Handler;

use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use JMS\Serializer\Context;
use JMS\Serializer\GraphNavigator;
use JMS\Serializer\VisitorInterface;

class ArrayCollectionHandler implements SubscribingHandlerInterface
{
    /**
     * @var bool
     */
    private $initializeExcluded = true;

    public function __construct($initializeExcluded = true)
    {
        $this->initializeExcluded = $initializeExcluded;
    }

    public static function getSubscribingMethods()
    {
        $methods = array();
        $formats = array('json', 'xml', 'yml');
        $collectionTypes = array(
            'ArrayCollection',
            'Doctrine\Common\Collections\ArrayCollection',
            'Doctrine\ORM\PersistentCollection',
            'Doctrine\ODM\MongoDB\PersistentCollection',
            'Doctrine\ODM\PHPCR\PersistentCollection',
        );

        foreach ($collectionTypes as $type) {
            foreach ($formats as $format) {
                $methods[] = array(
                    'direction' => GraphNavigator::DIRECTION_SERIALIZATION,
                    'type' => $type,
                    'format' => $format,
                    'method' => 'serializeCollection',
                );

                $methods[] = array(
                    'direction' => GraphNavigator::DIRECTION_DESERIALIZATION,
                    'type' => $type,
                    'format' => $format,
                    'method' => 'deserializeCollection',
                );
            }
        }

        return $methods;
    }

    public function serializeCollection(VisitorInterface $visitor, Collection $collection, array $type, Context $context)
    {
        // We change the base type, and pass through possible parameters.
        $type['name'] = 'array';

        if ($this->initializeExcluded === false) {
            $exclusionStrategy = $context->getExclusionStrategy();
            if ($exclusionStrategy !== null && $exclusionStrategy->shouldSkipClass($context->getMetadataFactory()->getMetadataForClass(\get_class($collection)), $context)) {
                return $visitor->visitArray([], $type, $context);
            }
        }

        return $visitor->visitArray($collection->toArray(), $type, $context);
    }

    public function deserializeCollection(VisitorInterface $visitor, $data, array $type, Context $context)
    {
        // See above.
        $type['name'] = 'array';

        return new ArrayCollection($visitor->visitArray($data, $type, $context));
    }
}
serializer/src/JMS/Serializer/Handler/ConstraintViolationHandler.php000064400000006742147361032420021656 0ustar00<?php

namespace JMS\Serializer\Handler;

use JMS\Serializer\Context;
use JMS\Serializer\GraphNavigator;
use JMS\Serializer\JsonSerializationVisitor;
use JMS\Serializer\XmlSerializationVisitor;
use JMS\Serializer\YamlSerializationVisitor;
use Symfony\Component\Validator\ConstraintViolation;
use Symfony\Component\Validator\ConstraintViolationList;

class ConstraintViolationHandler implements SubscribingHandlerInterface
{
    public static function getSubscribingMethods()
    {
        $methods = array();
        $formats = array('xml', 'json', 'yml');
        $types = array('Symfony\Component\Validator\ConstraintViolationList' => 'serializeList', 'Symfony\Component\Validator\ConstraintViolation' => 'serializeViolation');

        foreach ($types as $type => $method) {
            foreach ($formats as $format) {
                $methods[] = array(
                    'direction' => GraphNavigator::DIRECTION_SERIALIZATION,
                    'type' => $type,
                    'format' => $format,
                    'method' => $method . 'To' . $format,
                );
            }
        }

        return $methods;
    }

    public function serializeListToXml(XmlSerializationVisitor $visitor, ConstraintViolationList $list, array $type)
    {
        if (null === $visitor->document) {
            $visitor->document = $visitor->createDocument();
        }

        foreach ($list as $violation) {
            $this->serializeViolationToXml($visitor, $violation);
        }
    }

    public function serializeListToJson(JsonSerializationVisitor $visitor, ConstraintViolationList $list, array $type, Context $context)
    {
        return $visitor->visitArray(iterator_to_array($list), $type, $context);
    }

    public function serializeListToYml(YamlSerializationVisitor $visitor, ConstraintViolationList $list, array $type, Context $context)
    {
        return $visitor->visitArray(iterator_to_array($list), $type, $context);
    }

    public function serializeViolationToXml(XmlSerializationVisitor $visitor, ConstraintViolation $violation, array $type = null)
    {
        if (null === $visitor->document) {
            $visitor->document = $visitor->createDocument(null, null, false);
            $visitor->document->appendChild($violationNode = $visitor->document->createElement('violation'));
            $visitor->setCurrentNode($violationNode);
        } else {
            $visitor->getCurrentNode()->appendChild(
                $violationNode = $visitor->document->createElement('violation')
            );
        }

        $violationNode->setAttribute('property_path', $violation->getPropertyPath());
        $violationNode->appendChild($messageNode = $visitor->document->createElement('message'));

        $messageNode->appendChild($visitor->document->createCDATASection($violation->getMessage()));
    }

    public function serializeViolationToJson(JsonSerializationVisitor $visitor, ConstraintViolation $violation, array $type = null)
    {
        $data = array(
            'property_path' => $violation->getPropertyPath(),
            'message' => $violation->getMessage()
        );

        if (null === $visitor->getRoot()) {
            $visitor->setRoot($data);
        }

        return $data;
    }

    public function serializeViolationToYml(YamlSerializationVisitor $visitor, ConstraintViolation $violation, array $type = null)
    {
        return array(
            'property_path' => $violation->getPropertyPath(),
            'message' => $violation->getMessage(),
        );
    }
}
serializer/src/JMS/Serializer/Handler/HandlerRegistryInterface.php000064400000002004147361032420021261 0ustar00<?php

namespace JMS\Serializer\Handler;

/**
 * Handler Registry Interface.
 *
 * @author Johannes M. Schmitt <schmittjoh@gmail.com>
 */
interface HandlerRegistryInterface
{
    /**
     * @param SubscribingHandlerInterface $handler
     *
     * @return void
     */
    public function registerSubscribingHandler(SubscribingHandlerInterface $handler);

    /**
     * Registers a handler in the registry.
     *
     * @param integer $direction one of the GraphNavigator::DIRECTION_??? constants
     * @param string $typeName
     * @param string $format
     * @param callable $handler function(VisitorInterface, mixed $data, array $type): mixed
     *
     * @return void
     */
    public function registerHandler($direction, $typeName, $format, $handler);

    /**
     * @param integer $direction one of the GraphNavigator::DIRECTION_??? constants
     * @param string $typeName
     * @param string $format
     *
     * @return callable|null
     */
    public function getHandler($direction, $typeName, $format);
}
serializer/src/JMS/Serializer/Handler/StdClassHandler.php000064400000002614147361032420017357 0ustar00<?php

namespace JMS\Serializer\Handler;

use JMS\Serializer\Context;
use JMS\Serializer\GraphNavigator;
use JMS\Serializer\Metadata\StaticPropertyMetadata;
use JMS\Serializer\VisitorInterface;

/**
 * @author Asmir Mustafic <goetas@gmail.com>
 */
class StdClassHandler implements SubscribingHandlerInterface
{
    public static function getSubscribingMethods()
    {
        $methods = array();
        $formats = array('json', 'xml', 'yml');

        foreach ($formats as $format) {
            $methods[] = array(
                'direction' => GraphNavigator::DIRECTION_SERIALIZATION,
                'type' => 'stdClass',
                'format' => $format,
                'method' => 'serializeStdClass',
            );
        }

        return $methods;
    }

    public function serializeStdClass(VisitorInterface $visitor, \stdClass $stdClass, array $type, Context $context)
    {
        $classMetadata = $context->getMetadataFactory()->getMetadataForClass('stdClass');
        $visitor->startVisitingObject($classMetadata, $stdClass, array('name' => 'stdClass'), $context);

        foreach ((array)$stdClass as $name => $value) {
            $metadata = new StaticPropertyMetadata('stdClass', $name, $value);
            $visitor->visitProperty($metadata, $value, $context);
        }

        return $visitor->endVisitingObject($classMetadata, $stdClass, array('name' => 'stdClass'), $context);
    }
}
serializer/src/JMS/Serializer/Handler/SubscribingHandlerInterface.php000064400000001061147361032420021725 0ustar00<?php

namespace JMS\Serializer\Handler;

interface SubscribingHandlerInterface
{
    /**
     * Return format:
     *
     *      array(
     *          array(
     *              'direction' => GraphNavigator::DIRECTION_SERIALIZATION,
     *              'format' => 'json',
     *              'type' => 'DateTime',
     *              'method' => 'serializeDateTimeToJson',
     *          ),
     *      )
     *
     * The direction and method keys can be omitted.
     *
     * @return array
     */
    public static function getSubscribingMethods();
}
serializer/src/JMS/Serializer/Handler/DateHandler.php000064400000016731147361032420016521 0ustar00<?php

namespace JMS\Serializer\Handler;

use JMS\Serializer\Context;
use JMS\Serializer\Exception\RuntimeException;
use JMS\Serializer\GraphNavigator;
use JMS\Serializer\JsonDeserializationVisitor;
use JMS\Serializer\VisitorInterface;
use JMS\Serializer\XmlDeserializationVisitor;
use JMS\Serializer\XmlSerializationVisitor;

class DateHandler implements SubscribingHandlerInterface
{
    private $defaultFormat;
    private $defaultTimezone;
    private $xmlCData;

    public static function getSubscribingMethods()
    {
        $methods = array();
        $deserializationTypes = array('DateTime', 'DateTimeImmutable', 'DateInterval');
        $serialisationTypes = array('DateTime', 'DateTimeImmutable', 'DateInterval');

        foreach (array('json', 'xml', 'yml') as $format) {

            foreach ($deserializationTypes as $type) {
                $methods[] = [
                    'type' => $type,
                    'direction' => GraphNavigator::DIRECTION_DESERIALIZATION,
                    'format' => $format,
                ];
            }

            foreach ($serialisationTypes as $type) {
                $methods[] = array(
                    'type' => $type,
                    'format' => $format,
                    'direction' => GraphNavigator::DIRECTION_SERIALIZATION,
                    'method' => 'serialize' . $type,
                );
            }
        }

        return $methods;
    }

    public function __construct($defaultFormat = \DateTime::ISO8601, $defaultTimezone = 'UTC', $xmlCData = true)
    {
        $this->defaultFormat = $defaultFormat;
        $this->defaultTimezone = new \DateTimeZone($defaultTimezone);
        $this->xmlCData = $xmlCData;
    }

    private function serializeDateTimeInterface(
        VisitorInterface $visitor,
        \DateTimeInterface $date,
        array $type,
        Context $context
    )
    {
        if ($visitor instanceof XmlSerializationVisitor && false === $this->xmlCData) {
            return $visitor->visitSimpleString($date->format($this->getFormat($type)), $type, $context);
        }

        $format = $this->getFormat($type);
        if ('U' === $format) {
            return $visitor->visitInteger($date->format($format), $type, $context);
        }

        return $visitor->visitString($date->format($this->getFormat($type)), $type, $context);
    }

    public function serializeDateTime(VisitorInterface $visitor, \DateTime $date, array $type, Context $context)
    {
        return $this->serializeDateTimeInterface($visitor, $date, $type, $context);
    }

    public function serializeDateTimeImmutable(
        VisitorInterface $visitor,
        \DateTimeImmutable $date,
        array $type,
        Context $context
    )
    {
        return $this->serializeDateTimeInterface($visitor, $date, $type, $context);
    }

    public function serializeDateInterval(VisitorInterface $visitor, \DateInterval $date, array $type, Context $context)
    {
        $iso8601DateIntervalString = $this->format($date);

        if ($visitor instanceof XmlSerializationVisitor && false === $this->xmlCData) {
            return $visitor->visitSimpleString($iso8601DateIntervalString, $type, $context);
        }

        return $visitor->visitString($iso8601DateIntervalString, $type, $context);
    }

    private function isDataXmlNull($data)
    {
        $attributes = $data->attributes('xsi', true);
        return isset($attributes['nil'][0]) && (string)$attributes['nil'][0] === 'true';
    }

    public function deserializeDateTimeFromXml(XmlDeserializationVisitor $visitor, $data, array $type)
    {
        if ($this->isDataXmlNull($data)) {
            return null;
        }

        return $this->parseDateTime($data, $type);
    }

    public function deserializeDateTimeImmutableFromXml(XmlDeserializationVisitor $visitor, $data, array $type)
    {
        if ($this->isDataXmlNull($data)) {
            return null;
        }

        return $this->parseDateTime($data, $type, true);
    }

    public function deserializeDateIntervalFromXml(XmlDeserializationVisitor $visitor, $data, array $type)
    {
        if ($this->isDataXmlNull($data)) {
            return null;
        }

        return $this->parseDateInterval($data);
    }

    public function deserializeDateTimeFromJson(JsonDeserializationVisitor $visitor, $data, array $type)
    {
        if (null === $data) {
            return null;
        }

        return $this->parseDateTime($data, $type);
    }

    public function deserializeDateTimeImmutableFromJson(JsonDeserializationVisitor $visitor, $data, array $type)
    {
        if (null === $data) {
            return null;
        }

        return $this->parseDateTime($data, $type, true);
    }

    public function deserializeDateIntervalFromJson(JsonDeserializationVisitor $visitor, $data, array $type)
    {
        if (null === $data) {
            return null;
        }

        return $this->parseDateInterval($data);
    }

    private function parseDateTime($data, array $type, $immutable = false)
    {
        $timezone = !empty($type['params'][1]) ? new \DateTimeZone($type['params'][1]) : $this->defaultTimezone;
        $format = $this->getDeserializationFormat($type);

        if ($immutable) {
            $datetime = \DateTimeImmutable::createFromFormat($format, (string)$data, $timezone);
        } else {
            $datetime = \DateTime::createFromFormat($format, (string)$data, $timezone);
        }

        if (false === $datetime) {
            throw new RuntimeException(sprintf('Invalid datetime "%s", expected format %s.', $data, $format));
        }

        if ($format === 'U') {
            $datetime = $datetime->setTimezone($timezone);
        }

        return $datetime;
    }

    private function parseDateInterval($data)
    {
        $dateInterval = null;
        try {
            $dateInterval = new \DateInterval($data);
        } catch (\Exception $e) {
            throw new RuntimeException(sprintf('Invalid dateinterval "%s", expected ISO 8601 format', $data), null, $e);
        }

        return $dateInterval;
    }

    /**
     * @param array $type
     *  @return string
     */
    private function getDeserializationFormat(array $type)
    {
        if (isset($type['params'][2])) {
            return $type['params'][2];
        }
        if (isset($type['params'][0])) {
            return $type['params'][0];
        }
        return $this->defaultFormat;
    }

    /**
     * @return string
     * @param array $type
     */
    private function getFormat(array $type)
    {
        return isset($type['params'][0]) ? $type['params'][0] : $this->defaultFormat;
    }

    /**
     * @param \DateInterval $dateInterval
     * @return string
     */
    public function format(\DateInterval $dateInterval)
    {
        $format = 'P';

        if (0 < $dateInterval->y) {
            $format .= $dateInterval->y . 'Y';
        }

        if (0 < $dateInterval->m) {
            $format .= $dateInterval->m . 'M';
        }

        if (0 < $dateInterval->d) {
            $format .= $dateInterval->d . 'D';
        }

        if (0 < $dateInterval->h || 0 < $dateInterval->i || 0 < $dateInterval->s) {
            $format .= 'T';
        }

        if (0 < $dateInterval->h) {
            $format .= $dateInterval->h . 'H';
        }

        if (0 < $dateInterval->i) {
            $format .= $dateInterval->i . 'M';
        }

        if (0 < $dateInterval->s) {
            $format .= $dateInterval->s . 'S';
        }

        if ($format === 'P') {
            $format = 'P0DT0S';
        }

        return $format;
    }
}
serializer/src/JMS/Serializer/Handler/HandlerRegistry.php000064400000005103147361032420017443 0ustar00<?php

namespace JMS\Serializer\Handler;

use JMS\Serializer\Exception\LogicException;
use JMS\Serializer\Exception\RuntimeException;
use JMS\Serializer\GraphNavigator;

class HandlerRegistry implements HandlerRegistryInterface
{
    protected $handlers;

    public static function getDefaultMethod($direction, $type, $format)
    {
        if (false !== $pos = strrpos($type, '\\')) {
            $type = substr($type, $pos + 1);
        }

        switch ($direction) {
            case GraphNavigator::DIRECTION_DESERIALIZATION:
                return 'deserialize' . $type . 'From' . $format;

            case GraphNavigator::DIRECTION_SERIALIZATION:
                return 'serialize' . $type . 'To' . $format;

            default:
                throw new LogicException(sprintf('The direction %s does not exist; see GraphNavigator::DIRECTION_??? constants.', json_encode($direction)));
        }
    }

    public function __construct(array $handlers = array())
    {
        $this->handlers = $handlers;
    }

    public function registerSubscribingHandler(SubscribingHandlerInterface $handler)
    {
        foreach ($handler->getSubscribingMethods() as $methodData) {
            if (!isset($methodData['type'], $methodData['format'])) {
                throw new RuntimeException(sprintf('For each subscribing method a "type" and "format" attribute must be given, but only got "%s" for %s.', implode('" and "', array_keys($methodData)), \get_class($handler)));
            }

            $directions = array(GraphNavigator::DIRECTION_DESERIALIZATION, GraphNavigator::DIRECTION_SERIALIZATION);
            if (isset($methodData['direction'])) {
                $directions = array($methodData['direction']);
            }

            foreach ($directions as $direction) {
                $method = isset($methodData['method']) ? $methodData['method'] : self::getDefaultMethod($direction, $methodData['type'], $methodData['format']);
                $this->registerHandler($direction, $methodData['type'], $methodData['format'], array($handler, $method));
            }
        }
    }

    public function registerHandler($direction, $typeName, $format, $handler)
    {
        if (\is_string($direction)) {
            $direction = GraphNavigator::parseDirection($direction);
        }

        $this->handlers[$direction][$typeName][$format] = $handler;
    }

    public function getHandler($direction, $typeName, $format)
    {
        if (!isset($this->handlers[$direction][$typeName][$format])) {
            return null;
        }

        return $this->handlers[$direction][$typeName][$format];
    }
}
serializer/src/JMS/Serializer/Expression/ExpressionEvaluatorInterface.php000064400000000461147361032420022764 0ustar00<?php

namespace JMS\Serializer\Expression;

/**
 * @author Asmir Mustafic <goetas@gmail.com>
 */
interface ExpressionEvaluatorInterface
{
    /**
     * @param  string $expression
     * @param  array $data
     * @return mixed
     */
    public function evaluate($expression, array $data = array());
}
serializer/src/JMS/Serializer/Expression/ExpressionEvaluator.php000064400000002652147361032420021147 0ustar00<?php

namespace JMS\Serializer\Expression;

use Symfony\Component\ExpressionLanguage\ExpressionLanguage;

/**
 * @author Asmir Mustafic <goetas@gmail.com>
 */
class ExpressionEvaluator implements ExpressionEvaluatorInterface
{

    /**
     * @var ExpressionLanguage
     */
    private $expressionLanguage;

    /**
     * @var array
     */
    private $context = array();

    /**
     * @var array
     */
    private $cache = array();

    public function __construct(ExpressionLanguage $expressionLanguage, array $context = array(), array $cache = array())
    {
        $this->expressionLanguage = $expressionLanguage;
        $this->context = $context;
        $this->cache = $cache;
    }

    /**
     * @param string $name
     * @param mixed $value
     */
    public function setContextVariable($name, $value)
    {
        $this->context[$name] = $value;
    }

    /**
     * @param  string $expression
     * @param  array $data
     * @return mixed
     */
    public function evaluate($expression, array $data = array())
    {
        if (!\is_string($expression)) {
            return $expression;
        }

        $context = $data + $this->context;

        if (!array_key_exists($expression, $this->cache)) {
            $this->cache[$expression] = $this->expressionLanguage->parse($expression, array_keys($context));
        }

        return $this->expressionLanguage->evaluate($this->cache[$expression], $context);
    }
}
serializer/src/JMS/Serializer/GenericDeserializationVisitor.php000064400000012631147361032420020767 0ustar00<?php

namespace JMS\Serializer;

use JMS\Serializer\Exception\RuntimeException;
use JMS\Serializer\Metadata\ClassMetadata;
use JMS\Serializer\Metadata\PropertyMetadata;
use JMS\Serializer\Naming\AdvancedNamingStrategyInterface;
use JMS\Serializer\Naming\PropertyNamingStrategyInterface;

/**
 * Generic Deserialization Visitor.
 * @deprecated
 * @author Johannes M. Schmitt <schmittjoh@gmail.com>
 */
abstract class GenericDeserializationVisitor extends AbstractVisitor
{
    private $navigator;
    private $result;
    private $objectStack;
    private $currentObject;

    public function setNavigator(GraphNavigator $navigator)
    {
        $this->navigator = $navigator;
        $this->result = null;
        $this->objectStack = new \SplStack;
    }

    public function getNavigator()
    {
        return $this->navigator;
    }

    public function prepare($data)
    {
        return $this->decode($data);
    }

    public function visitNull($data, array $type, Context $context)
    {
        return null;
    }

    public function visitString($data, array $type, Context $context)
    {
        $data = (string)$data;

        if (null === $this->result) {
            $this->result = $data;
        }

        return $data;
    }

    public function visitBoolean($data, array $type, Context $context)
    {
        $data = (Boolean)$data;

        if (null === $this->result) {
            $this->result = $data;
        }

        return $data;
    }

    public function visitInteger($data, array $type, Context $context)
    {
        $data = (integer)$data;

        if (null === $this->result) {
            $this->result = $data;
        }

        return $data;
    }

    public function visitDouble($data, array $type, Context $context)
    {
        $data = (double)$data;

        if (null === $this->result) {
            $this->result = $data;
        }

        return $data;
    }

    public function visitArray($data, array $type, Context $context)
    {
        if (!\is_array($data)) {
            throw new RuntimeException(sprintf('Expected array, but got %s: %s', \gettype($data), json_encode($data)));
        }

        // If no further parameters were given, keys/values are just passed as is.
        if (!$type['params']) {
            if (null === $this->result) {
                $this->result = $data;
            }

            return $data;
        }

        switch (\count($type['params'])) {
            case 1: // Array is a list.
                $listType = $type['params'][0];

                $result = array();
                if (null === $this->result) {
                    $this->result = &$result;
                }

                foreach ($data as $v) {
                    $result[] = $this->navigator->accept($v, $listType, $context);
                }

                return $result;

            case 2: // Array is a map.
                list($keyType, $entryType) = $type['params'];

                $result = array();
                if (null === $this->result) {
                    $this->result = &$result;
                }

                foreach ($data as $k => $v) {
                    $result[$this->navigator->accept($k, $keyType, $context)] = $this->navigator->accept($v, $entryType, $context);
                }

                return $result;

            default:
                throw new RuntimeException(sprintf('Array type cannot have more than 2 parameters, but got %s.', json_encode($type['params'])));
        }
    }

    public function startVisitingObject(ClassMetadata $metadata, $object, array $type, Context $context)
    {
        $this->setCurrentObject($object);

        if (null === $this->result) {
            $this->result = $this->currentObject;
        }
    }

    public function visitProperty(PropertyMetadata $metadata, $data, Context $context)
    {
        if ($this->namingStrategy instanceof AdvancedNamingStrategyInterface) {
            $name = $this->namingStrategy->getPropertyName($metadata, $context);
        } else {
            $name = $this->namingStrategy->translateName($metadata);
        }

        if (null === $data) {
            return;
        }

        if (!\is_array($data)) {
            throw new RuntimeException(sprintf('Invalid data "%s"(%s), expected "%s".', $data, $metadata->type['name'], $metadata->reflection->class));
        }

        if (!array_key_exists($name, $data)) {
            return;
        }

        if (!$metadata->type) {
            throw new RuntimeException(sprintf('You must define a type for %s::$%s.', $metadata->reflection->class, $metadata->name));
        }

        $v = $data[$name] !== null ? $this->navigator->accept($data[$name], $metadata->type, $context) : null;

        $this->accessor->setValue($this->currentObject, $v, $metadata);

    }

    public function endVisitingObject(ClassMetadata $metadata, $data, array $type, Context $context)
    {
        $obj = $this->currentObject;
        $this->revertCurrentObject();

        return $obj;
    }

    public function getResult()
    {
        return $this->result;
    }

    public function setCurrentObject($object)
    {
        $this->objectStack->push($this->currentObject);
        $this->currentObject = $object;
    }

    public function getCurrentObject()
    {
        return $this->currentObject;
    }

    public function revertCurrentObject()
    {
        return $this->currentObject = $this->objectStack->pop();
    }

    abstract protected function decode($str);
}
serializer/src/JMS/Serializer/Accessor/ExpressionAccessorStrategy.php000064400000002200147361032420022062 0ustar00<?php

namespace JMS\Serializer\Accessor;

use JMS\Serializer\Expression\ExpressionEvaluatorInterface;
use JMS\Serializer\Metadata\ExpressionPropertyMetadata;
use JMS\Serializer\Metadata\PropertyMetadata;

/**
 * @author Asmir Mustafic <goetas@gmail.com>
 */
class ExpressionAccessorStrategy implements AccessorStrategyInterface
{
    /**
     * @var AccessorStrategyInterface
     */
    private $fallback;
    /**
     * @var ExpressionEvaluatorInterface
     */
    private $evaluator;

    public function __construct(ExpressionEvaluatorInterface $evaluator, AccessorStrategyInterface $fallback)
    {
        $this->fallback = $fallback;
        $this->evaluator = $evaluator;
    }

    public function getValue($object, PropertyMetadata $metadata)
    {
        if ($metadata instanceof ExpressionPropertyMetadata) {
            return $this->evaluator->evaluate($metadata->expression, array('object' => $object));
        }
        return $this->fallback->getValue($object, $metadata);
    }

    public function setValue($object, $value, PropertyMetadata $metadata)
    {
        $this->fallback->setValue($object, $value, $metadata);
    }
}
serializer/src/JMS/Serializer/Accessor/AccessorStrategyInterface.php000064400000001066147361032420021634 0ustar00<?php

namespace JMS\Serializer\Accessor;

use JMS\Serializer\Metadata\PropertyMetadata;

/**
 * @author Asmir Mustafic <goetas@gmail.com>
 */
interface AccessorStrategyInterface
{
    /**
     * @param object $object
     * @param PropertyMetadata $metadata
     * @return mixed
     */
    public function getValue($object, PropertyMetadata $metadata);

    /**
     * @param object $object
     * @param mixed $value
     * @param PropertyMetadata $metadata
     * @return void
     */
    public function setValue($object, $value, PropertyMetadata $metadata);
}
serializer/src/JMS/Serializer/Accessor/DefaultAccessorStrategy.php000064400000000727147361032420021323 0ustar00<?php

namespace JMS\Serializer\Accessor;

use JMS\Serializer\Metadata\PropertyMetadata;

/**
 * @author Asmir Mustafic <goetas@gmail.com>
 */
class DefaultAccessorStrategy implements AccessorStrategyInterface
{

    public function getValue($object, PropertyMetadata $metadata)
    {
        return $metadata->getValue($object);
    }

    public function setValue($object, $value, PropertyMetadata $metadata)
    {
        $metadata->setValue($object, $value);
    }
}
serializer/src/JMS/Serializer/Construction/ObjectConstructorInterface.php000064400000001656147361032420022760 0ustar00<?php

namespace JMS\Serializer\Construction;

use JMS\Serializer\DeserializationContext;
use JMS\Serializer\Metadata\ClassMetadata;
use JMS\Serializer\VisitorInterface;

/**
 * Implementations of this interface construct new objects during deserialization.
 *
 * @author Johannes M. Schmitt <schmittjoh@gmail.com>
 */
interface ObjectConstructorInterface
{
    /**
     * Constructs a new object.
     *
     * Implementations could for example create a new object calling "new", use
     * "unserialize" techniques, reflection, or other means.
     *
     * @param VisitorInterface $visitor
     * @param ClassMetadata $metadata
     * @param mixed $data
     * @param array $type ["name" => string, "params" => array]
     * @param DeserializationContext $context
     *
     * @return object
     */
    public function construct(VisitorInterface $visitor, ClassMetadata $metadata, $data, array $type, DeserializationContext $context);
}
serializer/src/JMS/Serializer/Construction/UnserializeObjectConstructor.php000064400000001443147361032420023344 0ustar00<?php

namespace JMS\Serializer\Construction;

use Doctrine\Instantiator\Instantiator;
use JMS\Serializer\DeserializationContext;
use JMS\Serializer\Metadata\ClassMetadata;
use JMS\Serializer\VisitorInterface;

class UnserializeObjectConstructor implements ObjectConstructorInterface
{
    /** @var Instantiator */
    private $instantiator;

    public function construct(VisitorInterface $visitor, ClassMetadata $metadata, $data, array $type, DeserializationContext $context)
    {
        return $this->getInstantiator()->instantiate($metadata->name);
    }

    /**
     * @return Instantiator
     */
    private function getInstantiator()
    {
        if (null == $this->instantiator) {
            $this->instantiator = new Instantiator();
        }

        return $this->instantiator;
    }
}
serializer/src/JMS/Serializer/Construction/DoctrineObjectConstructor.php000064400000010230147361032420022613 0ustar00<?php

namespace JMS\Serializer\Construction;

use Doctrine\Common\Persistence\ManagerRegistry;
use JMS\Serializer\AbstractVisitor;
use JMS\Serializer\DeserializationContext;
use JMS\Serializer\Exception\InvalidArgumentException;
use JMS\Serializer\Exception\ObjectConstructionException;
use JMS\Serializer\Metadata\ClassMetadata;
use JMS\Serializer\Naming\PropertyNamingStrategyInterface;
use JMS\Serializer\VisitorInterface;

/**
 * Doctrine object constructor for new (or existing) objects during deserialization.
 */
class DoctrineObjectConstructor implements ObjectConstructorInterface
{
    const ON_MISSING_NULL = 'null';
    const ON_MISSING_EXCEPTION = 'exception';
    const ON_MISSING_FALLBACK = 'fallback';
    /**
     * @var string
     */
    private $fallbackStrategy;

    private $managerRegistry;
    private $fallbackConstructor;

    /**
     * Constructor.
     *
     * @param ManagerRegistry $managerRegistry Manager registry
     * @param ObjectConstructorInterface $fallbackConstructor Fallback object constructor
     * @param string $fallbackStrategy
     */
    public function __construct(ManagerRegistry $managerRegistry, ObjectConstructorInterface $fallbackConstructor, $fallbackStrategy = self::ON_MISSING_NULL)
    {
        $this->managerRegistry = $managerRegistry;
        $this->fallbackConstructor = $fallbackConstructor;
        $this->fallbackStrategy = $fallbackStrategy;
    }

    /**
     * {@inheritdoc}
     */
    public function construct(VisitorInterface $visitor, ClassMetadata $metadata, $data, array $type, DeserializationContext $context)
    {
        // Locate possible ObjectManager
        $objectManager = $this->managerRegistry->getManagerForClass($metadata->name);

        if (!$objectManager) {
            // No ObjectManager found, proceed with normal deserialization
            return $this->fallbackConstructor->construct($visitor, $metadata, $data, $type, $context);
        }

        // Locate possible ClassMetadata
        $classMetadataFactory = $objectManager->getMetadataFactory();

        if ($classMetadataFactory->isTransient($metadata->name)) {
            // No ClassMetadata found, proceed with normal deserialization
            return $this->fallbackConstructor->construct($visitor, $metadata, $data, $type, $context);
        }

        // Managed entity, check for proxy load
        if (!\is_array($data)) {
            // Single identifier, load proxy
            return $objectManager->getReference($metadata->name, $data);
        }

        // Fallback to default constructor if missing identifier(s)
        $classMetadata = $objectManager->getClassMetadata($metadata->name);
        $identifierList = array();

        foreach ($classMetadata->getIdentifierFieldNames() as $name) {
            if ($visitor instanceof AbstractVisitor) {
                /** @var PropertyNamingStrategyInterface $namingStrategy */
                $namingStrategy = $visitor->getNamingStrategy();
                $dataName = $namingStrategy->translateName($metadata->propertyMetadata[$name]);
            } else {
                $dataName = $name;
            }

            if (!array_key_exists($dataName, $data)) {
                return $this->fallbackConstructor->construct($visitor, $metadata, $data, $type, $context);
            }

            $identifierList[$name] = $data[$dataName];
        }

        // Entity update, load it from database
        $object = $objectManager->find($metadata->name, $identifierList);

        if (null === $object) {
            switch ($this->fallbackStrategy) {
                case self::ON_MISSING_NULL:
                    return null;
                case self::ON_MISSING_EXCEPTION:
                    throw new ObjectConstructionException(sprintf("Entity %s can not be found", $metadata->name));
                case self::ON_MISSING_FALLBACK:
                    return $this->fallbackConstructor->construct($visitor, $metadata, $data, $type, $context);
                default:
                    throw new InvalidArgumentException("The provided fallback strategy for the object constructor is not valid");
            }
        }

        $objectManager->initializeObject($object);

        return $object;
    }
}
serializer/src/JMS/Serializer/NullAwareVisitorInterface.php000064400000000556147361032420020062 0ustar00<?php

namespace JMS\Serializer;

interface NullAwareVisitorInterface extends VisitorInterface
{
    /**
     * Determine if a value conveys a null value.
     * An example could be an xml element (Dom, SimpleXml, ...) that is tagged with a xsi:nil attribute
     *
     * @param mixed $value
     *
     * @return bool
     */
    public function isNull($value);
}
serializer/src/JMS/Serializer/ArrayTransformerInterface.php000064400000001724147361032420020107 0ustar00<?php

namespace JMS\Serializer;

/**
 * Interface for array transformation.
 *
 * @author Daniel Bojdo <daniel@bojdo.eu>
 */
interface ArrayTransformerInterface
{
    /**
     * Converts objects to an array structure.
     *
     * This is useful when the data needs to be passed on to other methods which expect array data.
     *
     * @param mixed $data anything that converts to an array, typically an object or an array of objects
     * @param SerializationContext|null $context
     *
     * @return array
     */
    public function toArray($data, SerializationContext $context = null);

    /**
     * Restores objects from an array structure.
     *
     * @param array $data
     * @param string $type
     * @param DeserializationContext|null $context
     *
     * @return mixed this returns whatever the passed type is, typically an object or an array of objects
     */
    public function fromArray(array $data, $type, DeserializationContext $context = null);
}
serializer/src/JMS/Serializer/JsonDeserializationVisitor.php000064400000002233147361032420020321 0ustar00<?php

namespace JMS\Serializer;

use JMS\Serializer\Exception\RuntimeException;

class JsonDeserializationVisitor extends GenericDeserializationVisitor
{
    protected function decode($str)
    {
        $decoded = json_decode($str, true);

        switch (json_last_error()) {
            case JSON_ERROR_NONE:
                return $decoded;

            case JSON_ERROR_DEPTH:
                throw new RuntimeException('Could not decode JSON, maximum stack depth exceeded.');

            case JSON_ERROR_STATE_MISMATCH:
                throw new RuntimeException('Could not decode JSON, underflow or the nodes mismatch.');

            case JSON_ERROR_CTRL_CHAR:
                throw new RuntimeException('Could not decode JSON, unexpected control character found.');

            case JSON_ERROR_SYNTAX:
                throw new RuntimeException('Could not decode JSON, syntax error - malformed JSON.');

            case JSON_ERROR_UTF8:
                throw new RuntimeException('Could not decode JSON, malformed UTF-8 characters (incorrectly encoded?)');

            default:
                throw new RuntimeException('Could not decode JSON.');
        }
    }
}
serializer/src/JMS/Serializer/Exception/UnsupportedFormatException.php000064400000000162147361032420022276 0ustar00<?php

namespace JMS\Serializer\Exception;

class UnsupportedFormatException extends InvalidArgumentException
{
}
serializer/src/JMS/Serializer/Exception/LogicException.php000064400000000331147361032420017630 0ustar00<?php

namespace JMS\Serializer\Exception;

/**
 * LogicException for the Serializer.
 *
 * @author Johannes M. Schmitt <schmittjoh@gmail.com>
 */
class LogicException extends \LogicException implements Exception
{
}
serializer/src/JMS/Serializer/Exception/ObjectConstructionException.php000064400000000350147361032420022415 0ustar00<?php

namespace JMS\Serializer\Exception;

/**
 * InvalidArgumentException for the Serializer.
 *
 * @author Asmir Mustafic <goetas@gmail.com>
 */
class ObjectConstructionException extends RuntimeException implements Exception
{
}
serializer/src/JMS/Serializer/Exception/Exception.php000064400000000253147361032420016655 0ustar00<?php

namespace JMS\Serializer\Exception;

/**
 * Base exception for the Serializer.
 *
 * @author Johannes M. Schmitt <schmittjoh@gmail.com>
 */
interface Exception
{
}
serializer/src/JMS/Serializer/Exception/ExpressionLanguageRequiredException.php000064400000000246147361032420024104 0ustar00<?php

namespace JMS\Serializer\Exception;

/**
 * @author Asmir Mustafic <goetas@gmail.com>
 */
class ExpressionLanguageRequiredException extends LogicException
{
}
serializer/src/JMS/Serializer/Exception/InvalidArgumentException.php000064400000000367147361032420021675 0ustar00<?php

namespace JMS\Serializer\Exception;

/**
 * InvalidArgumentException for the Serializer.
 *
 * @author Johannes M. Schmitt <schmittjoh@gmail.com>
 */
class InvalidArgumentException extends \InvalidArgumentException implements Exception
{
}
serializer/src/JMS/Serializer/Exception/ValidationFailedException.php000064400000001145147361032420021776 0ustar00<?php

namespace JMS\Serializer\Exception;

use Symfony\Component\Validator\ConstraintViolationListInterface;

class ValidationFailedException extends RuntimeException
{
    /**
     * @var ConstraintViolationListInterface
     */
    private $list;

    public function __construct(ConstraintViolationListInterface $list)
    {
        parent::__construct(sprintf('Validation failed with %d error(s).', \count($list)));

        $this->list = $list;
    }

    /**
     * @return ConstraintViolationListInterface
     */
    public function getConstraintViolationList()
    {
        return $this->list;
    }
}
serializer/src/JMS/Serializer/Exception/XmlErrorException.php000064400000001477147361032420020361 0ustar00<?php

namespace JMS\Serializer\Exception;

class XmlErrorException extends RuntimeException
{
    private $xmlError;

    public function __construct(\LibXMLError $error)
    {
        switch ($error->level) {
            case LIBXML_ERR_WARNING:
                $level = 'WARNING';
                break;

            case LIBXML_ERR_FATAL:
                $level = 'FATAL';
                break;

            case LIBXML_ERR_ERROR:
                $level = 'ERROR';
                break;

            default:
                $level = 'UNKNOWN';
        }

        parent::__construct(sprintf('[%s] %s in %s (line: %d, column: %d)', $level, $error->message, $error->file, $error->line, $error->column));

        $this->xmlError = $error;
    }

    public function getXmlError()
    {
        return $this->xmlError;
    }
}
serializer/src/JMS/Serializer/Exception/RuntimeException.php000064400000000337147361032420020224 0ustar00<?php

namespace JMS\Serializer\Exception;

/**
 * RuntimeException for the Serializer.
 *
 * @author Johannes M. Schmitt <schmittjoh@gmail.com>
 */
class RuntimeException extends \RuntimeException implements Exception
{
}
serializer/src/JMS/Serializer/GraphNavigatorInterface.php000064400000001506147361032420017520 0ustar00<?php

namespace JMS\Serializer;

/**
 * Handles traversal along the object graph.
 *
 * This class handles traversal along the graph, and calls different methods
 * on visitors, or custom handlers to process its nodes.
 *
 * @author Asmir Mustafic <goetas@gmail.com>
 */
interface GraphNavigatorInterface
{
    const DIRECTION_SERIALIZATION = 1;
    const DIRECTION_DESERIALIZATION = 2;
    /**
     * Called for each node of the graph that is being traversed.
     *
     * @param mixed $data the data depends on the direction, and type of visitor
     * @param null|array $type array has the format ["name" => string, "params" => array]
     * @param Context $context
     * @return mixed the return value depends on the direction, and type of visitor
     */
    public function accept($data, array $type = null, Context $context);
}
serializer/src/JMS/Serializer/VisitorInterface.php000064400000005505147361032420016246 0ustar00<?php

namespace JMS\Serializer;

use JMS\Serializer\Metadata\ClassMetadata;
use JMS\Serializer\Metadata\PropertyMetadata;

/**
 * Interface for visitors.
 *
 * This contains the minimal set of values that must be supported for any
 * output format.
 *
 * @author Johannes M. Schmitt <schmittjoh@gmail.com>
 */
interface VisitorInterface
{
    /**
     * Allows visitors to convert the input data to a different representation
     * before the actual serialization/deserialization process starts.
     *
     * @param mixed $data
     *
     * @return mixed
     */
    public function prepare($data);

    /**
     * @param mixed $data
     * @param array $type
     *
     * @return mixed
     */
    public function visitNull($data, array $type, Context $context);

    /**
     * @param mixed $data
     * @param array $type
     *
     * @return mixed
     */
    public function visitString($data, array $type, Context $context);

    /**
     * @param mixed $data
     * @param array $type
     *
     * @return mixed
     */
    public function visitBoolean($data, array $type, Context $context);

    /**
     * @param mixed $data
     * @param array $type
     *
     * @return mixed
     */
    public function visitDouble($data, array $type, Context $context);

    /**
     * @param mixed $data
     * @param array $type
     *
     * @return mixed
     */
    public function visitInteger($data, array $type, Context $context);

    /**
     * @param mixed $data
     * @param array $type
     *
     * @return mixed
     */
    public function visitArray($data, array $type, Context $context);

    /**
     * Called before the properties of the object are being visited.
     *
     * @param ClassMetadata $metadata
     * @param mixed $data
     * @param array $type
     *
     * @return void
     */
    public function startVisitingObject(ClassMetadata $metadata, $data, array $type, Context $context);

    /**
     * @param PropertyMetadata $metadata
     * @param mixed $data
     *
     * @return void
     */
    public function visitProperty(PropertyMetadata $metadata, $data, Context $context);

    /**
     * Called after all properties of the object have been visited.
     *
     * @param ClassMetadata $metadata
     * @param mixed $data
     * @param array $type
     *
     * @return mixed
     */
    public function endVisitingObject(ClassMetadata $metadata, $data, array $type, Context $context);

    /**
     * Called before serialization/deserialization starts.
     *
     * @param GraphNavigator $navigator
     *
     * @return void
     */
    public function setNavigator(GraphNavigator $navigator);

    /**
     * @deprecated use Context::getNavigator/Context::accept instead
     * @return GraphNavigator
     */
    public function getNavigator();

    /**
     * @return object|array|scalar
     */
    public function getResult();
}
serializer/src/JMS/Serializer/SerializerBuilder.php000064400000040265147361032420016410 0ustar00<?php

namespace JMS\Serializer;

use Doctrine\Common\Annotations\AnnotationReader;
use Doctrine\Common\Annotations\CachedReader;
use Doctrine\Common\Annotations\Reader;
use Doctrine\Common\Cache\FilesystemCache;
use JMS\Serializer\Accessor\AccessorStrategyInterface;
use JMS\Serializer\Accessor\DefaultAccessorStrategy;
use JMS\Serializer\Accessor\ExpressionAccessorStrategy;
use JMS\Serializer\Builder\DefaultDriverFactory;
use JMS\Serializer\Builder\DriverFactoryInterface;
use JMS\Serializer\Construction\ObjectConstructorInterface;
use JMS\Serializer\Construction\UnserializeObjectConstructor;
use JMS\Serializer\ContextFactory\CallableDeserializationContextFactory;
use JMS\Serializer\ContextFactory\CallableSerializationContextFactory;
use JMS\Serializer\ContextFactory\DeserializationContextFactoryInterface;
use JMS\Serializer\ContextFactory\SerializationContextFactoryInterface;
use JMS\Serializer\EventDispatcher\EventDispatcher;
use JMS\Serializer\EventDispatcher\Subscriber\DoctrineProxySubscriber;
use JMS\Serializer\Exception\InvalidArgumentException;
use JMS\Serializer\Exception\RuntimeException;
use JMS\Serializer\Expression\ExpressionEvaluatorInterface;
use JMS\Serializer\Handler\ArrayCollectionHandler;
use JMS\Serializer\Handler\DateHandler;
use JMS\Serializer\Handler\HandlerRegistry;
use JMS\Serializer\Handler\PhpCollectionHandler;
use JMS\Serializer\Handler\PropelCollectionHandler;
use JMS\Serializer\Handler\StdClassHandler;
use JMS\Serializer\Naming\AdvancedNamingStrategyInterface;
use JMS\Serializer\Naming\CamelCaseNamingStrategy;
use JMS\Serializer\Naming\PropertyNamingStrategyInterface;
use JMS\Serializer\Naming\SerializedNameAnnotationStrategy;
use Metadata\Cache\CacheInterface;
use Metadata\Cache\FileCache;
use Metadata\MetadataFactory;
use PhpCollection\Map;

/**
 * Builder for serializer instances.
 *
 * This object makes serializer construction a breeze for projects that do not use
 * any special dependency injection container.
 *
 * @author Johannes M. Schmitt <schmittjoh@gmail.com>
 */
class SerializerBuilder
{
    private $metadataDirs = array();
    private $handlerRegistry;
    private $handlersConfigured = false;
    private $eventDispatcher;
    private $listenersConfigured = false;
    private $objectConstructor;
    private $serializationVisitors;
    private $deserializationVisitors;
    private $visitorsAdded = false;
    private $propertyNamingStrategy;
    private $debug = false;
    private $cacheDir;
    private $annotationReader;
    private $includeInterfaceMetadata = false;
    private $driverFactory;
    private $serializationContextFactory;
    private $deserializationContextFactory;

    /**
     * @var ExpressionEvaluatorInterface
     */
    private $expressionEvaluator;

    /**
     * @var AccessorStrategyInterface
     */
    private $accessorStrategy;

    /**
     * @var CacheInterface
     */
    private $metadataCache;

    public static function create()
    {
        return new static();
    }

    public function __construct()
    {
        $this->handlerRegistry = new HandlerRegistry();
        $this->eventDispatcher = new EventDispatcher();
        $this->driverFactory = new DefaultDriverFactory();
        $this->serializationVisitors = new Map();
        $this->deserializationVisitors = new Map();
    }

    public function setAccessorStrategy(AccessorStrategyInterface $accessorStrategy)
    {
        $this->accessorStrategy = $accessorStrategy;
    }

    protected function getAccessorStrategy()
    {
        if (!$this->accessorStrategy) {
            $this->accessorStrategy = new DefaultAccessorStrategy();

            if ($this->expressionEvaluator) {
                $this->accessorStrategy = new ExpressionAccessorStrategy($this->expressionEvaluator, $this->accessorStrategy);
            }
        }
        return $this->accessorStrategy;
    }

    public function setExpressionEvaluator(ExpressionEvaluatorInterface $expressionEvaluator)
    {
        $this->expressionEvaluator = $expressionEvaluator;

        return $this;
    }

    public function setAnnotationReader(Reader $reader)
    {
        $this->annotationReader = $reader;

        return $this;
    }

    public function setDebug($bool)
    {
        $this->debug = (boolean)$bool;

        return $this;
    }

    public function setCacheDir($dir)
    {
        if (!is_dir($dir)) {
            $this->createDir($dir);
        }
        if (!is_writable($dir)) {
            throw new InvalidArgumentException(sprintf('The cache directory "%s" is not writable.', $dir));
        }

        $this->cacheDir = $dir;

        return $this;
    }

    public function addDefaultHandlers()
    {
        $this->handlersConfigured = true;
        $this->handlerRegistry->registerSubscribingHandler(new DateHandler());
        $this->handlerRegistry->registerSubscribingHandler(new StdClassHandler());
        $this->handlerRegistry->registerSubscribingHandler(new PhpCollectionHandler());
        $this->handlerRegistry->registerSubscribingHandler(new ArrayCollectionHandler());
        $this->handlerRegistry->registerSubscribingHandler(new PropelCollectionHandler());

        return $this;
    }

    public function configureHandlers(\Closure $closure)
    {
        $this->handlersConfigured = true;
        $closure($this->handlerRegistry);

        return $this;
    }

    public function addDefaultListeners()
    {
        $this->listenersConfigured = true;
        $this->eventDispatcher->addSubscriber(new DoctrineProxySubscriber());

        return $this;
    }

    public function configureListeners(\Closure $closure)
    {
        $this->listenersConfigured = true;
        $closure($this->eventDispatcher);

        return $this;
    }

    public function setObjectConstructor(ObjectConstructorInterface $constructor)
    {
        $this->objectConstructor = $constructor;

        return $this;
    }

    public function setPropertyNamingStrategy(PropertyNamingStrategyInterface $propertyNamingStrategy)
    {
        $this->propertyNamingStrategy = $propertyNamingStrategy;

        return $this;
    }

    public function setAdvancedNamingStrategy(AdvancedNamingStrategyInterface $advancedNamingStrategy)
    {
        $this->propertyNamingStrategy = $advancedNamingStrategy;

        return $this;
    }

    public function setSerializationVisitor($format, VisitorInterface $visitor)
    {
        $this->visitorsAdded = true;
        $this->serializationVisitors->set($format, $visitor);

        return $this;
    }

    public function setDeserializationVisitor($format, VisitorInterface $visitor)
    {
        $this->visitorsAdded = true;
        $this->deserializationVisitors->set($format, $visitor);

        return $this;
    }

    public function addDefaultSerializationVisitors()
    {
        $this->initializePropertyNamingStrategy();

        $this->visitorsAdded = true;
        $this->serializationVisitors->setAll(array(
            'xml' => new XmlSerializationVisitor($this->propertyNamingStrategy, $this->getAccessorStrategy()),
            'yml' => new YamlSerializationVisitor($this->propertyNamingStrategy, $this->getAccessorStrategy()),
            'json' => new JsonSerializationVisitor($this->propertyNamingStrategy, $this->getAccessorStrategy()),
        ));

        return $this;
    }

    public function addDefaultDeserializationVisitors()
    {
        $this->initializePropertyNamingStrategy();

        $this->visitorsAdded = true;
        $this->deserializationVisitors->setAll(array(
            'xml' => new XmlDeserializationVisitor($this->propertyNamingStrategy),
            'json' => new JsonDeserializationVisitor($this->propertyNamingStrategy),
        ));

        return $this;
    }

    /**
     * @param Boolean $include Whether to include the metadata from the interfaces
     *
     * @return SerializerBuilder
     */
    public function includeInterfaceMetadata($include)
    {
        $this->includeInterfaceMetadata = (Boolean)$include;

        return $this;
    }

    /**
     * Sets a map of namespace prefixes to directories.
     *
     * This method overrides any previously defined directories.
     *
     * @param array <string,string> $namespacePrefixToDirMap
     *
     * @return SerializerBuilder
     *
     * @throws InvalidArgumentException When a directory does not exist
     */
    public function setMetadataDirs(array $namespacePrefixToDirMap)
    {
        foreach ($namespacePrefixToDirMap as $dir) {
            if (!is_dir($dir)) {
                throw new InvalidArgumentException(sprintf('The directory "%s" does not exist.', $dir));
            }
        }

        $this->metadataDirs = $namespacePrefixToDirMap;

        return $this;
    }

    /**
     * Adds a directory where the serializer will look for class metadata.
     *
     * The namespace prefix will make the names of the actual metadata files a bit shorter. For example, let's assume
     * that you have a directory where you only store metadata files for the ``MyApplication\Entity`` namespace.
     *
     * If you use an empty prefix, your metadata files would need to look like:
     *
     * ``my-dir/MyApplication.Entity.SomeObject.yml``
     * ``my-dir/MyApplication.Entity.OtherObject.xml``
     *
     * If you use ``MyApplication\Entity`` as prefix, your metadata files would need to look like:
     *
     * ``my-dir/SomeObject.yml``
     * ``my-dir/OtherObject.yml``
     *
     * Please keep in mind that you currently may only have one directory per namespace prefix.
     *
     * @param string $dir The directory where metadata files are located.
     * @param string $namespacePrefix An optional prefix if you only store metadata for specific namespaces in this directory.
     *
     * @return SerializerBuilder
     *
     * @throws InvalidArgumentException When a directory does not exist
     * @throws InvalidArgumentException When a directory has already been registered
     */
    public function addMetadataDir($dir, $namespacePrefix = '')
    {
        if (!is_dir($dir)) {
            throw new InvalidArgumentException(sprintf('The directory "%s" does not exist.', $dir));
        }

        if (isset($this->metadataDirs[$namespacePrefix])) {
            throw new InvalidArgumentException(sprintf('There is already a directory configured for the namespace prefix "%s". Please use replaceMetadataDir() to override directories.', $namespacePrefix));
        }

        $this->metadataDirs[$namespacePrefix] = $dir;

        return $this;
    }

    /**
     * Adds a map of namespace prefixes to directories.
     *
     * @param array <string,string> $namespacePrefixToDirMap
     *
     * @return SerializerBuilder
     */
    public function addMetadataDirs(array $namespacePrefixToDirMap)
    {
        foreach ($namespacePrefixToDirMap as $prefix => $dir) {
            $this->addMetadataDir($dir, $prefix);
        }

        return $this;
    }

    /**
     * Similar to addMetadataDir(), but overrides an existing entry.
     *
     * @param string $dir
     * @param string $namespacePrefix
     *
     * @return SerializerBuilder
     *
     * @throws InvalidArgumentException When a directory does not exist
     * @throws InvalidArgumentException When no directory is configured for the ns prefix
     */
    public function replaceMetadataDir($dir, $namespacePrefix = '')
    {
        if (!is_dir($dir)) {
            throw new InvalidArgumentException(sprintf('The directory "%s" does not exist.', $dir));
        }

        if (!isset($this->metadataDirs[$namespacePrefix])) {
            throw new InvalidArgumentException(sprintf('There is no directory configured for namespace prefix "%s". Please use addMetadataDir() for adding new directories.', $namespacePrefix));
        }

        $this->metadataDirs[$namespacePrefix] = $dir;

        return $this;
    }

    public function setMetadataDriverFactory(DriverFactoryInterface $driverFactory)
    {
        $this->driverFactory = $driverFactory;

        return $this;
    }

    /**
     * @param SerializationContextFactoryInterface|callable $serializationContextFactory
     *
     * @return self
     */
    public function setSerializationContextFactory($serializationContextFactory)
    {
        if ($serializationContextFactory instanceof SerializationContextFactoryInterface) {
            $this->serializationContextFactory = $serializationContextFactory;
        } elseif (is_callable($serializationContextFactory)) {
            $this->serializationContextFactory = new CallableSerializationContextFactory(
                $serializationContextFactory
            );
        } else {
            throw new InvalidArgumentException('expected SerializationContextFactoryInterface or callable.');
        }

        return $this;
    }

    /**
     * @param DeserializationContextFactoryInterface|callable $deserializationContextFactory
     *
     * @return self
     */
    public function setDeserializationContextFactory($deserializationContextFactory)
    {
        if ($deserializationContextFactory instanceof DeserializationContextFactoryInterface) {
            $this->deserializationContextFactory = $deserializationContextFactory;
        } elseif (is_callable($deserializationContextFactory)) {
            $this->deserializationContextFactory = new CallableDeserializationContextFactory(
                $deserializationContextFactory
            );
        } else {
            throw new InvalidArgumentException('expected DeserializationContextFactoryInterface or callable.');
        }

        return $this;
    }

    /**
     * @param CacheInterface $cache
     *
     * @return self
     */
    public function setMetadataCache(CacheInterface $cache)
    {
        $this->metadataCache = $cache;
        return $this;
    }

    public function build()
    {
        $annotationReader = $this->annotationReader;
        if (null === $annotationReader) {
            $annotationReader = new AnnotationReader();

            if (null !== $this->cacheDir) {
                $this->createDir($this->cacheDir . '/annotations');
                $annotationsCache = new FilesystemCache($this->cacheDir . '/annotations');
                $annotationReader = new CachedReader($annotationReader, $annotationsCache, $this->debug);
            }
        }

        $metadataDriver = $this->driverFactory->createDriver($this->metadataDirs, $annotationReader);
        $metadataFactory = new MetadataFactory($metadataDriver, null, $this->debug);

        $metadataFactory->setIncludeInterfaces($this->includeInterfaceMetadata);

        if ($this->metadataCache !== null) {
            $metadataFactory->setCache($this->metadataCache);
        } elseif (null !== $this->cacheDir) {
            $this->createDir($this->cacheDir . '/metadata');
            $metadataFactory->setCache(new FileCache($this->cacheDir . '/metadata'));
        }

        if (!$this->handlersConfigured) {
            $this->addDefaultHandlers();
        }

        if (!$this->listenersConfigured) {
            $this->addDefaultListeners();
        }

        if (!$this->visitorsAdded) {
            $this->addDefaultSerializationVisitors();
            $this->addDefaultDeserializationVisitors();
        }

        $serializer = new Serializer(
            $metadataFactory,
            $this->handlerRegistry,
            $this->objectConstructor ?: new UnserializeObjectConstructor(),
            $this->serializationVisitors,
            $this->deserializationVisitors,
            $this->eventDispatcher,
            null,
            $this->expressionEvaluator
        );

        if (null !== $this->serializationContextFactory) {
            $serializer->setSerializationContextFactory($this->serializationContextFactory);
        }

        if (null !== $this->deserializationContextFactory) {
            $serializer->setDeserializationContextFactory($this->deserializationContextFactory);
        }

        return $serializer;
    }

    private function initializePropertyNamingStrategy()
    {
        if (null !== $this->propertyNamingStrategy) {
            return;
        }

        $this->propertyNamingStrategy = new SerializedNameAnnotationStrategy(new CamelCaseNamingStrategy());
    }

    private function createDir($dir)
    {
        if (is_dir($dir)) {
            return;
        }

        if (false === @mkdir($dir, 0777, true) && false === is_dir($dir)) {
            throw new RuntimeException(sprintf('Could not create directory "%s".', $dir));
        }
    }
}
serializer/src/JMS/Serializer/GenericSerializationVisitor.php000064400000012573147361032420020463 0ustar00<?php

namespace JMS\Serializer;

use JMS\Serializer\Exception\InvalidArgumentException;
use JMS\Serializer\Metadata\ClassMetadata;
use JMS\Serializer\Metadata\PropertyMetadata;
use JMS\Serializer\Naming\AdvancedNamingStrategyInterface;

/**
 * @deprecated
 */
abstract class GenericSerializationVisitor extends AbstractVisitor
{
    private $navigator;
    private $root;
    private $dataStack;
    private $data;

    public function setNavigator(GraphNavigator $navigator)
    {
        $this->navigator = $navigator;
        $this->root = null;
        $this->dataStack = new \SplStack;
    }

    /**
     * @return GraphNavigator
     */
    public function getNavigator()
    {
        return $this->navigator;
    }

    public function visitNull($data, array $type, Context $context)
    {
        return null;
    }

    public function visitString($data, array $type, Context $context)
    {
        if (null === $this->root) {
            $this->root = $data;
        }

        return (string)$data;
    }

    public function visitBoolean($data, array $type, Context $context)
    {
        if (null === $this->root) {
            $this->root = $data;
        }

        return (boolean)$data;
    }

    public function visitInteger($data, array $type, Context $context)
    {
        if (null === $this->root) {
            $this->root = $data;
        }

        return (int)$data;
    }

    public function visitDouble($data, array $type, Context $context)
    {
        if (null === $this->root) {
            $this->root = $data;
        }

        return (float)$data;
    }

    /**
     * @param array $data
     * @param array $type
     */
    public function visitArray($data, array $type, Context $context)
    {
        $this->dataStack->push($data);

        $isHash = isset($type['params'][1]);

        if (null === $this->root) {
            $this->root = $isHash ? new \ArrayObject() : array();
            $rs = &$this->root;
        } else {
            $rs = $isHash ? new \ArrayObject() : array();
        }

        $isList = isset($type['params'][0]) && !isset($type['params'][1]);

        foreach ($data as $k => $v) {
            $v = $this->navigator->accept($v, $this->getElementType($type), $context);

            if (null === $v && $context->shouldSerializeNull() !== true) {
                continue;
            }

            if ($isList) {
                $rs[] = $v;
            } else {
                $rs[$k] = $v;
            }
        }

        $this->dataStack->pop();

        return $rs;
    }

    public function startVisitingObject(ClassMetadata $metadata, $data, array $type, Context $context)
    {
        if (null === $this->root) {
            $this->root = new \stdClass;
        }

        $this->dataStack->push($this->data);
        $this->data = array();
    }

    public function endVisitingObject(ClassMetadata $metadata, $data, array $type, Context $context)
    {
        $rs = $this->data;
        $this->data = $this->dataStack->pop();

        if ($this->root instanceof \stdClass && 0 === $this->dataStack->count()) {
            $this->root = $rs;
        }

        return $rs;
    }

    public function visitProperty(PropertyMetadata $metadata, $data, Context $context)
    {
        $v = $this->accessor->getValue($data, $metadata);

        $v = $this->navigator->accept($v, $metadata->type, $context);
        if (null === $v && $context->shouldSerializeNull() !== true) {
            return;
        }

        if ($this->namingStrategy instanceof AdvancedNamingStrategyInterface) {
            $k = $this->namingStrategy->getPropertyName($metadata, $context);
        } else {
            $k = $this->namingStrategy->translateName($metadata);
        }

        if ($metadata->inline) {
            if (\is_array($v)) {
                $this->data = array_merge($this->data, $v);
            }
        } else {
            $this->data[$k] = $v;
        }
    }

    /**
     * Allows you to add additional data to the current object/root element.
     * @deprecated use setData instead
     * @param string $key
     * @param integer|float|boolean|string|array|null $value This value must either be a regular scalar, or an array.
     *                                                       It must not contain any objects anymore.
     */
    public function addData($key, $value)
    {
        if (isset($this->data[$key])) {
            throw new InvalidArgumentException(sprintf('There is already data for "%s".', $key));
        }

        $this->data[$key] = $value;
    }

    /**
     * Checks if some data key exists.
     *
     * @param string $key
     * @return boolean
     */
    public function hasData($key)
    {
        return isset($this->data[$key]);
    }

    /**
     * Allows you to replace existing data on the current object/root element.
     *
     * @param string $key
     * @param integer|float|boolean|string|array|null $value This value must either be a regular scalar, or an array.
     *                                                       It must not contain any objects anymore.
     */
    public function setData($key, $value)
    {
        $this->data[$key] = $value;
    }

    public function getRoot()
    {
        return $this->root;
    }

    /**
     * @param array|\ArrayObject $data the passed data must be understood by whatever encoding function is applied later.
     */
    public function setRoot($data)
    {
        $this->root = $data;
    }
}
serializer/src/JMS/Serializer/ContextFactory/DeserializationContextFactoryInterface.php000064400000000462147361032420025603 0ustar00<?php

namespace JMS\Serializer\ContextFactory;

use JMS\Serializer\DeserializationContext;

/**
 * Deserialization Context Factory Interface.
 */
interface DeserializationContextFactoryInterface
{
    /**
     * @return DeserializationContext
     */
    public function createDeserializationContext();
}
serializer/src/JMS/Serializer/ContextFactory/DefaultDeserializationContextFactory.php000064400000000603147361032420025264 0ustar00<?php

namespace JMS\Serializer\ContextFactory;

use JMS\Serializer\DeserializationContext;

/**
 * Default Deserialization Context Factory.
 */
class DefaultDeserializationContextFactory implements DeserializationContextFactoryInterface
{
    /**
     * {@InheritDoc}
     */
    public function createDeserializationContext()
    {
        return new DeserializationContext();
    }
}
serializer/src/JMS/Serializer/ContextFactory/CallableSerializationContextFactory.php000064400000000566147361032420025076 0ustar00<?php

namespace JMS\Serializer\ContextFactory;

/**
 * Serialization Context Factory using a callable.
 */
class CallableSerializationContextFactory extends CallableContextFactory implements
    SerializationContextFactoryInterface
{
    /**
     * {@InheritDoc}
     */
    public function createSerializationContext()
    {
        return $this->createContext();
    }
}
serializer/src/JMS/Serializer/ContextFactory/DefaultSerializationContextFactory.php000064400000000567147361032420024764 0ustar00<?php

namespace JMS\Serializer\ContextFactory;

use JMS\Serializer\SerializationContext;

/**
 * Default Serialization Context Factory.
 */
class DefaultSerializationContextFactory implements SerializationContextFactoryInterface
{
    /**
     * {@InheritDoc}
     */
    public function createSerializationContext()
    {
        return new SerializationContext();
    }
}
serializer/src/JMS/Serializer/ContextFactory/CallableContextFactory.php000064400000000766147361032420022342 0ustar00<?php

namespace JMS\Serializer\ContextFactory;

/**
 * Context Factory using a callable.
 */
abstract class CallableContextFactory
{
    /**
     * @var callable
     */
    private $callable;

    /**
     * @param callable $callable
     */
    public function __construct(callable $callable)
    {
        $this->callable = $callable;
    }

    /**
     * @return mixed
     */
    protected function createContext()
    {
        $callable = $this->callable;

        return $callable();
    }
}
serializer/src/JMS/Serializer/ContextFactory/CallableDeserializationContextFactory.php000064400000000576147361032420025410 0ustar00<?php

namespace JMS\Serializer\ContextFactory;

/**
 * Deserialization Context Factory using a callable.
 */
class CallableDeserializationContextFactory extends CallableContextFactory implements
    DeserializationContextFactoryInterface
{
    /**
     * {@InheritDoc}
     */
    public function createDeserializationContext()
    {
        return $this->createContext();
    }
}
serializer/src/JMS/Serializer/ContextFactory/SerializationContextFactoryInterface.php000064400000000450147361032420025267 0ustar00<?php

namespace JMS\Serializer\ContextFactory;

use JMS\Serializer\SerializationContext;

/**
 * Serialization Context Factory Interface.
 */
interface SerializationContextFactoryInterface
{
    /**
     * @return SerializationContext
     */
    public function createSerializationContext();
}
serializer/src/JMS/Serializer/SerializerInterface.php000064400000001432147361032420016713 0ustar00<?php

namespace JMS\Serializer;

/**
 * Serializer Interface.
 *
 * @author Johannes M. Schmitt <schmittjoh@gmail.com>
 */
interface SerializerInterface
{
    /**
     * Serializes the given data to the specified output format.
     *
     * @param object|array|scalar $data
     * @param string $format
     * @param Context $context
     *
     * @return string
     */
    public function serialize($data, $format, SerializationContext $context = null);

    /**
     * Deserializes the given data to the specified type.
     *
     * @param string $data
     * @param string $type
     * @param string $format
     * @param Context $context
     *
     * @return object|array|scalar
     */
    public function deserialize($data, $type, $format, DeserializationContext $context = null);
}
serializer/src/JMS/Serializer/EventDispatcher/EventDispatcherInterface.php000064400000002261147361032420022763 0ustar00<?php

namespace JMS\Serializer\EventDispatcher;

interface EventDispatcherInterface
{
    /**
     * Returns whether there are listeners.
     *
     * @param string $eventName
     * @param string $class
     * @param string $format
     *
     * @return boolean
     */
    public function hasListeners($eventName, $class, $format);

    /**
     * Dispatches an event.
     *
     * The listeners/subscribers are called in the same order in which they
     * were added to the dispatcher.
     *
     * @param string $eventName
     * @param string $class
     * @param string $format
     * @param Event $event
     * @return void
     */
    public function dispatch($eventName, $class, $format, Event $event);

    /**
     * Adds a listener.
     *
     * @param string $eventName
     * @param callable $callable
     * @param string|null $class
     * @param string|null $format
     * @return void
     */
    public function addListener($eventName, $callable, $class = null, $format = null);

    /**
     * Adds a subscribers.
     *
     * @param EventSubscriberInterface $subscriber
     * @return void
     */
    public function addSubscriber(EventSubscriberInterface $subscriber);
}
serializer/src/JMS/Serializer/EventDispatcher/Subscriber/DoctrineProxySubscriber.php000064400000007617147361032420025024 0ustar00<?php

namespace JMS\Serializer\EventDispatcher\Subscriber;

use Doctrine\Common\Persistence\Proxy;
use Doctrine\ODM\MongoDB\PersistentCollection as MongoDBPersistentCollection;
use Doctrine\ODM\PHPCR\PersistentCollection as PHPCRPersistentCollection;
use Doctrine\ORM\PersistentCollection;
use Doctrine\ORM\Proxy\Proxy as ORMProxy;
use JMS\Serializer\EventDispatcher\EventDispatcherInterface;
use JMS\Serializer\EventDispatcher\EventSubscriberInterface;
use JMS\Serializer\EventDispatcher\PreSerializeEvent;

class DoctrineProxySubscriber implements EventSubscriberInterface
{
    /**
     * @var bool
     */
    private $skipVirtualTypeInit = false;

    /**
     * @var bool
     */
    private $initializeExcluded = true;

    public function __construct($skipVirtualTypeInit = false, $initializeExcluded = true)
    {
        $this->skipVirtualTypeInit = (bool)$skipVirtualTypeInit;
        $this->initializeExcluded = (bool)$initializeExcluded;
    }

    public function onPreSerialize(PreSerializeEvent $event)
    {
        $object = $event->getObject();
        $type = $event->getType();

        // If the set type name is not an actual class, but a faked type for which a custom handler exists, we do not
        // modify it with this subscriber. Also, we forgo autoloading here as an instance of this type is already created,
        // so it must be loaded if its a real class.
        $virtualType = !class_exists($type['name'], false);

        if ($object instanceof PersistentCollection
            || $object instanceof MongoDBPersistentCollection
            || $object instanceof PHPCRPersistentCollection
        ) {
            if (!$virtualType) {
                $event->setType('ArrayCollection');
            }

            return;
        }

        if (($this->skipVirtualTypeInit && $virtualType) ||
            (!$object instanceof Proxy && !$object instanceof ORMProxy)
        ) {
            return;
        }

        // do not initialize the proxy if is going to be excluded by-class by some exclusion strategy
        if ($this->initializeExcluded === false && !$virtualType) {
            $context = $event->getContext();
            $exclusionStrategy = $context->getExclusionStrategy();
            if ($exclusionStrategy !== null && $exclusionStrategy->shouldSkipClass($context->getMetadataFactory()->getMetadataForClass(get_parent_class($object)), $context)) {
                return;
            }
        }

        $object->__load();

        if (!$virtualType) {
            $event->setType(get_parent_class($object), $type['params']);
        }
    }

    public function onPreSerializeTypedProxy(PreSerializeEvent $event, $eventName, $class, $format, EventDispatcherInterface $dispatcher)
    {
        $type = $event->getType();
        // is a virtual type? then there is no need to change the event name
        if (!class_exists($type['name'], false)) {
            return;
        }

        $object = $event->getObject();
        if ($object instanceof Proxy) {
            $parentClassName = get_parent_class($object);

            // check if this is already a re-dispatch
            if (strtolower($class) !== strtolower($parentClassName)) {
                $event->stopPropagation();
                $newEvent = new PreSerializeEvent($event->getContext(), $object, array('name' => $parentClassName, 'params' => $type['params']));
                $dispatcher->dispatch($eventName, $parentClassName, $format, $newEvent);

                // update the type in case some listener changed it
                $newType = $newEvent->getType();
                $event->setType($newType['name'], $newType['params']);
            }
        }
    }

    public static function getSubscribedEvents()
    {
        return array(
            array('event' => 'serializer.pre_serialize', 'method' => 'onPreSerializeTypedProxy'),
            array('event' => 'serializer.pre_serialize', 'method' => 'onPreSerialize'),
        );
    }
}
serializer/src/JMS/Serializer/EventDispatcher/Subscriber/SymfonyValidatorSubscriber.php000064400000002332147361032420025512 0ustar00<?php

namespace JMS\Serializer\EventDispatcher\Subscriber;

use JMS\Serializer\EventDispatcher\Event;
use JMS\Serializer\EventDispatcher\EventSubscriberInterface;
use JMS\Serializer\Exception\ValidationFailedException;
use Symfony\Component\Validator\ValidatorInterface;

class SymfonyValidatorSubscriber implements EventSubscriberInterface
{
    private $validator;

    public function __construct(ValidatorInterface $validator)
    {
        $this->validator = $validator;
    }

    public static function getSubscribedEvents()
    {
        return array(
            array('event' => 'serializer.post_deserialize', 'method' => 'onPostDeserialize'),
        );
    }

    public function onPostDeserialize(Event $event)
    {
        $context = $event->getContext();

        if ($context->getDepth() > 0) {
            return;
        }

        $validator = $this->validator;
        $context->attributes->get('validation_groups')->map(
            function (array $groups) use ($event, $validator) {
                $list = $validator->validate($event->getObject(), $groups);

                if ($list->count() > 0) {
                    throw new ValidationFailedException($list);
                }
            }
        );
    }
}
serializer/src/JMS/Serializer/EventDispatcher/Subscriber/SymfonyValidatorValidatorSubscriber.php000064400000003042147361032420027357 0ustar00<?php

namespace JMS\Serializer\EventDispatcher\Subscriber;

use JMS\Serializer\EventDispatcher\Event;
use JMS\Serializer\EventDispatcher\EventSubscriberInterface;
use JMS\Serializer\Exception\ValidationFailedException;
use PhpOption\None;
use Symfony\Component\Validator\Validator\ValidatorInterface;

class SymfonyValidatorValidatorSubscriber implements EventSubscriberInterface
{
    /**
     * @var ValidatorInterface
     */
    private $validator;

    public function __construct(ValidatorInterface $validator)
    {
        $this->validator = $validator;
    }

    public static function getSubscribedEvents()
    {
        return array(
            array('event' => 'serializer.post_deserialize', 'method' => 'onPostDeserialize'),
        );
    }

    public function onPostDeserialize(Event $event)
    {
        $context = $event->getContext();

        if ($context->getDepth() > 0) {
            return;
        }

        $validator = $this->validator;
        $groups = $context->attributes->get('validation_groups') instanceof None
            ? null
            : $context->attributes->get('validation_groups')->get();

        if (!$groups) {
            return;
        }

        $constraints = $context->attributes->get('validation_constraints') instanceof None
            ? null
            : $context->attributes->get('validation_constraints')->get();

        $list = $validator->validate($event->getObject(), $constraints, $groups);

        if ($list->count() > 0) {
            throw new ValidationFailedException($list);
        }
    }
}
serializer/src/JMS/Serializer/EventDispatcher/PreSerializeEvent.php000064400000000500147361032420021444 0ustar00<?php

namespace JMS\Serializer\EventDispatcher;

class PreSerializeEvent extends ObjectEvent
{
    /**
     * @param string $typeName
     * @param array $params
     */
    public function setType($typeName, array $params = array())
    {
        $this->type = array('name' => $typeName, 'params' => $params);
    }
}
serializer/src/JMS/Serializer/EventDispatcher/PreDeserializeEvent.php000064400000001153147361032420021762 0ustar00<?php

namespace JMS\Serializer\EventDispatcher;

use JMS\Serializer\DeserializationContext;

class PreDeserializeEvent extends Event
{
    private $data;

    public function __construct(DeserializationContext $context, $data, array $type)
    {
        parent::__construct($context, $type);

        $this->data = $data;
    }

    public function setType($name, array $params = array())
    {
        $this->type = array('name' => $name, 'params' => $params);
    }

    public function getData()
    {
        return $this->data;
    }

    public function setData($data)
    {
        $this->data = $data;
    }
}
serializer/src/JMS/Serializer/EventDispatcher/ObjectEvent.php000064400000000570147361032420020263 0ustar00<?php

namespace JMS\Serializer\EventDispatcher;

use JMS\Serializer\Context;

class ObjectEvent extends Event
{
    private $object;

    public function __construct(Context $context, $object, array $type)
    {
        parent::__construct($context, $type);

        $this->object = $object;
    }

    public function getObject()
    {
        return $this->object;
    }
}
serializer/src/JMS/Serializer/EventDispatcher/Events.php000064400000000546147361032420017322 0ustar00<?php

namespace JMS\Serializer\EventDispatcher;

abstract class Events
{
    const PRE_SERIALIZE = 'serializer.pre_serialize';
    const POST_SERIALIZE = 'serializer.post_serialize';
    const PRE_DESERIALIZE = 'serializer.pre_deserialize';
    const POST_DESERIALIZE = 'serializer.post_deserialize';

    final private function __construct()
    {
    }
}
serializer/src/JMS/Serializer/EventDispatcher/Event.php000064400000002435147361032420017136 0ustar00<?php

namespace JMS\Serializer\EventDispatcher;

use JMS\Serializer\Context;

class Event
{
    /**
     * @var bool Whether no further event listeners should be triggered
     */
    private $propagationStopped = false;

    protected $type;
    private $context;

    public function __construct(Context $context, array $type)
    {
        $this->context = $context;
        $this->type = $type;
    }

    public function getVisitor()
    {
        return $this->context->getVisitor();
    }

    public function getContext()
    {
        return $this->context;
    }

    public function getType()
    {
        return $this->type;
    }

    /**
     * Returns whether further event listeners should be triggered.
     *
     * @see Event::stopPropagation()
     *
     * @return bool Whether propagation was already stopped for this event
     */
    public function isPropagationStopped()
    {
        return $this->propagationStopped;
    }

    /**
     * Stops the propagation of the event to further event listeners.
     *
     * If multiple event listeners are connected to the same event, no
     * further event listener will be triggered once any trigger calls
     * stopPropagation().
     */
    public function stopPropagation()
    {
        $this->propagationStopped = true;
    }
}
serializer/src/JMS/Serializer/EventDispatcher/EventDispatcher.php000064400000007323147361032420021146 0ustar00<?php

namespace JMS\Serializer\EventDispatcher;

use JMS\Serializer\Exception\InvalidArgumentException;

/**
 * Light-weight event dispatcher.
 *
 * This implementation focuses primarily on performance, and dispatching
 * events for certain classes. It is not a general purpose event dispatcher.
 *
 * @author Johannes M. Schmitt <schmittjoh@gmail.com>
 */
class EventDispatcher implements EventDispatcherInterface
{
    private $listeners = array();
    private $classListeners = array();

    public static function getDefaultMethodName($eventName)
    {
        return 'on' . str_replace(array('_', '.'), '', $eventName);
    }

    /**
     * Sets the listeners.
     *
     * @param array $listeners
     */
    public function setListeners(array $listeners)
    {
        $this->listeners = $listeners;
        $this->classListeners = array();
    }

    public function addListener($eventName, $callable, $class = null, $format = null)
    {
        $this->listeners[$eventName][] = array($callable, null === $class ? null : strtolower($class), $format);
        unset($this->classListeners[$eventName]);
    }

    public function addSubscriber(EventSubscriberInterface $subscriber)
    {
        foreach ($subscriber->getSubscribedEvents() as $eventData) {
            if (!isset($eventData['event'])) {
                throw new InvalidArgumentException(sprintf('Each event must have a "event" key.'));
            }

            $method = isset($eventData['method']) ? $eventData['method'] : self::getDefaultMethodName($eventData['event']);
            $class = isset($eventData['class']) ? strtolower($eventData['class']) : null;
            $format = isset($eventData['format']) ? $eventData['format'] : null;
            $this->listeners[$eventData['event']][] = array(array($subscriber, $method), $class, $format);
            unset($this->classListeners[$eventData['event']]);
        }
    }

    public function hasListeners($eventName, $class, $format)
    {
        if (!isset($this->listeners[$eventName])) {
            return false;
        }

        $loweredClass = strtolower($class);
        if (!isset($this->classListeners[$eventName][$loweredClass][$format])) {
            $this->classListeners[$eventName][$loweredClass][$format] = $this->initializeListeners($eventName, $loweredClass, $format);
        }

        return !!$this->classListeners[$eventName][$loweredClass][$format];
    }

    public function dispatch($eventName, $class, $format, Event $event)
    {
        if (!isset($this->listeners[$eventName])) {
            return;
        }

        $loweredClass = strtolower($class);
        if (!isset($this->classListeners[$eventName][$loweredClass][$format])) {
            $this->classListeners[$eventName][$loweredClass][$format] = $this->initializeListeners($eventName, $loweredClass, $format);
        }

        foreach ($this->classListeners[$eventName][$loweredClass][$format] as $listener) {

            if ($event->isPropagationStopped()) {
                break;
            }

            \call_user_func($listener, $event, $eventName, $loweredClass, $format, $this);
        }
    }

    /**
     * @param string $eventName
     * @param string $loweredClass
     * @param string $format
     *
     * @return array An array of listeners
     */
    protected function initializeListeners($eventName, $loweredClass, $format)
    {
        $listeners = array();
        foreach ($this->listeners[$eventName] as $listener) {
            if (null !== $listener[1] && $loweredClass !== $listener[1]) {
                continue;
            }
            if (null !== $listener[2] && $format !== $listener[2]) {
                continue;
            }

            $listeners[] = $listener[0];
        }

        return $listeners;
    }
}
serializer/src/JMS/Serializer/EventDispatcher/LazyEventDispatcher.php000064400000002405147361032420022002 0ustar00<?php

namespace JMS\Serializer\EventDispatcher;

use Psr\Container\ContainerInterface as PsrContainerInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;

class LazyEventDispatcher extends EventDispatcher
{
    private $container;

    public function __construct($container)
    {
        if (!$container instanceof PsrContainerInterface && !$container instanceof ContainerInterface) {
            throw new \InvalidArgumentException(sprintf('The container must be an instance of %s or %s (%s given).', PsrContainerInterface::class, ContainerInterface::class, \is_object($container) ? \get_class($container) : \gettype($container)));
        }

        $this->container = $container;
    }

    /**
     * {@inheritdoc}
     */
    protected function initializeListeners($eventName, $loweredClass, $format)
    {
        $listeners = parent::initializeListeners($eventName, $loweredClass, $format);

        foreach ($listeners as &$listener) {
            if (!\is_array($listener) || !\is_string($listener[0])) {
                continue;
            }

            if (!$this->container->has($listener[0])) {
                continue;
            }

            $listener[0] = $this->container->get($listener[0]);
        }

        return $listeners;
    }
}
serializer/src/JMS/Serializer/EventDispatcher/EventSubscriberInterface.php000064400000001115147361032420022775 0ustar00<?php

namespace JMS\Serializer\EventDispatcher;

interface EventSubscriberInterface
{
    /**
     * Returns the events to which this class has subscribed.
     *
     * Return format:
     *     array(
     *         array('event' => 'the-event-name', 'method' => 'onEventName', 'class' => 'some-class', 'format' => 'json'),
     *         array(...),
     *     )
     *
     * The class may be omitted if the class wants to subscribe to events of all classes.
     * Same goes for the format key.
     *
     * @return array
     */
    public static function getSubscribedEvents();
}
serializer/src/JMS/Serializer/YamlSerializationVisitor.php000064400000013012147361032420017776 0ustar00<?php

namespace JMS\Serializer;

use JMS\Serializer\Accessor\AccessorStrategyInterface;
use JMS\Serializer\Metadata\ClassMetadata;
use JMS\Serializer\Metadata\PropertyMetadata;
use JMS\Serializer\Naming\AdvancedNamingStrategyInterface;
use JMS\Serializer\Naming\PropertyNamingStrategyInterface;
use JMS\Serializer\Util\Writer;
use Symfony\Component\Yaml\Inline;

/**
 * Serialization Visitor for the YAML format.
 *
 * @see http://www.yaml.org/spec/
 * @author Johannes M. Schmitt <schmittjoh@gmail.com>
 */
class YamlSerializationVisitor extends AbstractVisitor
{
    public $writer;

    private $navigator;
    private $stack;
    private $metadataStack;
    private $currentMetadata;

    public function __construct($namingStrategy, AccessorStrategyInterface $accessorStrategy = null)
    {
        parent::__construct($namingStrategy, $accessorStrategy);

        $this->writer = new Writer();
    }

    public function setNavigator(GraphNavigator $navigator)
    {
        $this->navigator = $navigator;
        $this->writer->reset();
        $this->stack = new \SplStack;
        $this->metadataStack = new \SplStack;
    }

    public function visitNull($data, array $type, Context $context)
    {
        if ('' === $this->writer->content) {
            $this->writer->writeln('null');
        }

        return 'null';
    }

    public function visitString($data, array $type, Context $context)
    {
        $v = Inline::dump($data);

        if ('' === $this->writer->content) {
            $this->writer->writeln($v);
        }

        return $v;
    }

    /**
     * @param array $data
     * @param array $type
     */
    public function visitArray($data, array $type, Context $context)
    {
        $isHash = isset($type['params'][1]);

        $count = $this->writer->changeCount;
        $isList = (isset($type['params'][0]) && !isset($type['params'][1]))
            || array_keys($data) === range(0, \count($data) - 1);

        foreach ($data as $k => $v) {
            if (null === $v && $context->shouldSerializeNull() !== true) {
                continue;
            }

            if ($isList && !$isHash) {
                $this->writer->writeln('-');
            } else {
                $this->writer->writeln(Inline::dump($k) . ':');
            }

            $this->writer->indent();

            if (null !== $v = $this->navigator->accept($v, $this->getElementType($type), $context)) {
                $this->writer
                    ->rtrim(false)
                    ->writeln(' ' . $v);
            }

            $this->writer->outdent();
        }

        if ($count === $this->writer->changeCount && isset($type['params'][1])) {
            $this->writer
                ->rtrim(false)
                ->writeln(' {}');
        } elseif (empty($data)) {
            $this->writer
                ->rtrim(false)
                ->writeln(' []');
        }
    }

    public function visitBoolean($data, array $type, Context $context)
    {
        $v = $data ? 'true' : 'false';

        if ('' === $this->writer->content) {
            $this->writer->writeln($v);
        }

        return $v;
    }

    public function visitDouble($data, array $type, Context $context)
    {
        $v = (string)$data;

        if ('' === $this->writer->content) {
            $this->writer->writeln($v);
        }

        return $v;
    }

    public function visitInteger($data, array $type, Context $context)
    {
        $v = (string)$data;

        if ('' === $this->writer->content) {
            $this->writer->writeln($v);
        }

        return $v;
    }

    public function startVisitingObject(ClassMetadata $metadata, $data, array $type, Context $context)
    {
    }

    public function visitProperty(PropertyMetadata $metadata, $data, Context $context)
    {
        $v = $this->accessor->getValue($data, $metadata);

        if ((null === $v && $context->shouldSerializeNull() !== true)
            || (true === $metadata->skipWhenEmpty && ($v instanceof \ArrayObject || \is_array($v)) && 0 === count($v))
        ) {
            return;
        }

        if ($this->namingStrategy instanceof AdvancedNamingStrategyInterface) {
            $name = $this->namingStrategy->getPropertyName($metadata, $context);
        } else {
            $name = $this->namingStrategy->translateName($metadata);
        }

        if (!$metadata->inline) {
            $this->writer
                ->writeln(Inline::dump($name) . ':')
                ->indent();
        }

        $this->setCurrentMetadata($metadata);

        $count = $this->writer->changeCount;

        if (null !== $v = $this->navigator->accept($v, $metadata->type, $context)) {
            $this->writer
                ->rtrim(false)
                ->writeln(' ' . $v);
        } elseif ($count === $this->writer->changeCount && !$metadata->inline) {
            $this->writer->revert();
        }

        if (!$metadata->inline) {
            $this->writer->outdent();
        }
        $this->revertCurrentMetadata();
    }

    public function endVisitingObject(ClassMetadata $metadata, $data, array $type, Context $context)
    {
    }

    public function setCurrentMetadata(PropertyMetadata $metadata)
    {
        $this->metadataStack->push($this->currentMetadata);
        $this->currentMetadata = $metadata;
    }

    public function revertCurrentMetadata()
    {
        return $this->currentMetadata = $this->metadataStack->pop();
    }

    public function getNavigator()
    {
        return $this->navigator;
    }

    public function getResult()
    {
        return $this->writer->getContent();
    }
}
serializer/src/JMS/Serializer/XmlDeserializationVisitor.php000064400000033011147361032420020146 0ustar00<?php

namespace JMS\Serializer;

use JMS\Serializer\Exception\InvalidArgumentException;
use JMS\Serializer\Exception\LogicException;
use JMS\Serializer\Exception\RuntimeException;
use JMS\Serializer\Exception\XmlErrorException;
use JMS\Serializer\Metadata\ClassMetadata;
use JMS\Serializer\Metadata\PropertyMetadata;
use JMS\Serializer\Naming\AdvancedNamingStrategyInterface;

class XmlDeserializationVisitor extends AbstractVisitor implements NullAwareVisitorInterface
{
    private $objectStack;
    private $metadataStack;
    private $objectMetadataStack;
    private $currentObject;
    private $currentMetadata;
    private $result;
    private $navigator;
    private $disableExternalEntities = true;
    private $doctypeWhitelist = array();

    public function enableExternalEntities()
    {
        $this->disableExternalEntities = false;
    }

    public function setNavigator(GraphNavigator $navigator)
    {
        $this->navigator = $navigator;
        $this->objectStack = new \SplStack;
        $this->metadataStack = new \SplStack;
        $this->objectMetadataStack = new \SplStack;
        $this->result = null;
    }

    public function getNavigator()
    {
        return $this->navigator;
    }

    public function prepare($data)
    {
        $data = $this->emptyStringToSpaceCharacter($data);

        $previous = libxml_use_internal_errors(true);
        libxml_clear_errors();

        $previousEntityLoaderState = libxml_disable_entity_loader($this->disableExternalEntities);

        if (false !== stripos($data, '<!doctype')) {
            $internalSubset = $this->getDomDocumentTypeEntitySubset($data);
            if (!in_array($internalSubset, $this->doctypeWhitelist, true)) {
                throw new InvalidArgumentException(sprintf(
                    'The document type "%s" is not allowed. If it is safe, you may add it to the whitelist configuration.',
                    $internalSubset
                ));
            }
        }

        $doc = simplexml_load_string($data);

        libxml_use_internal_errors($previous);
        libxml_disable_entity_loader($previousEntityLoaderState);

        if (false === $doc) {
            throw new XmlErrorException(libxml_get_last_error());
        }

        return $doc;
    }

    private function emptyStringToSpaceCharacter($data)
    {
        return $data === '' ? ' ' : (string)$data;
    }

    public function visitNull($data, array $type, Context $context)
    {
        return null;
    }

    public function visitString($data, array $type, Context $context)
    {
        $data = (string)$data;

        if (null === $this->result) {
            $this->result = $data;
        }

        return $data;
    }

    public function visitBoolean($data, array $type, Context $context)
    {
        $data = (string)$data;

        if ('true' === $data || '1' === $data) {
            $data = true;
        } elseif ('false' === $data || '0' === $data) {
            $data = false;
        } else {
            throw new RuntimeException(sprintf('Could not convert data to boolean. Expected "true", "false", "1" or "0", but got %s.', json_encode($data)));
        }

        if (null === $this->result) {
            $this->result = $data;
        }

        return $data;
    }

    public function visitInteger($data, array $type, Context $context)
    {
        $data = (integer)$data;

        if (null === $this->result) {
            $this->result = $data;
        }

        return $data;
    }

    public function visitDouble($data, array $type, Context $context)
    {
        $data = (double)$data;

        if (null === $this->result) {
            $this->result = $data;
        }

        return $data;
    }

    public function visitArray($data, array $type, Context $context)
    {
        // handle key-value-pairs
        if (null !== $this->currentMetadata && $this->currentMetadata->xmlKeyValuePairs) {
            if (2 !== count($type['params'])) {
                throw new RuntimeException('The array type must be specified as "array<K,V>" for Key-Value-Pairs.');
            }
            $this->revertCurrentMetadata();

            list($keyType, $entryType) = $type['params'];

            $result = [];
            foreach ($data as $key => $v) {
                $k = $this->navigator->accept($key, $keyType, $context);
                $result[$k] = $this->navigator->accept($v, $entryType, $context);
            }

            return $result;
        }

        $entryName = null !== $this->currentMetadata && $this->currentMetadata->xmlEntryName ? $this->currentMetadata->xmlEntryName : 'entry';
        $namespace = null !== $this->currentMetadata && $this->currentMetadata->xmlEntryNamespace ? $this->currentMetadata->xmlEntryNamespace : null;

        if ($namespace === null && $this->objectMetadataStack->count()) {
            $classMetadata = $this->objectMetadataStack->top();
            $namespace = isset($classMetadata->xmlNamespaces['']) ? $classMetadata->xmlNamespaces[''] : $namespace;
            if ($namespace === null) {
                $namespaces = $data->getDocNamespaces();
                if (isset($namespaces[''])) {
                    $namespace = $namespaces[''];
                }
            }
        }

        if (null !== $namespace) {
            $prefix = uniqid('ns-');
            $data->registerXPathNamespace($prefix, $namespace);
            $nodes = $data->xpath("$prefix:$entryName");
        } else {
            $nodes = $data->xpath($entryName);
        }

        if (!is_iterable($nodes) || !\count($nodes)) {
            if (null === $this->result) {
                return $this->result = array();
            }

            return array();
        }

        switch (\count($type['params'])) {
            case 0:
                throw new RuntimeException(sprintf('The array type must be specified either as "array<T>", or "array<K,V>".'));

            case 1:
                $result = array();

                if (null === $this->result) {
                    $this->result = &$result;
                }

                foreach ($nodes as $v) {
                    $result[] = $this->navigator->accept($v, $type['params'][0], $context);
                }

                return $result;

            case 2:
                if (null === $this->currentMetadata) {
                    throw new RuntimeException('Maps are not supported on top-level without metadata.');
                }

                list($keyType, $entryType) = $type['params'];
                $result = array();
                if (null === $this->result) {
                    $this->result = &$result;
                }

                $nodes = $data->children($namespace)->$entryName;
                foreach ($nodes as $v) {
                    $attrs = $v->attributes();
                    if (!isset($attrs[$this->currentMetadata->xmlKeyAttribute])) {
                        throw new RuntimeException(sprintf('The key attribute "%s" must be set for each entry of the map.', $this->currentMetadata->xmlKeyAttribute));
                    }

                    $k = $this->navigator->accept($attrs[$this->currentMetadata->xmlKeyAttribute], $keyType, $context);
                    $result[$k] = $this->navigator->accept($v, $entryType, $context);
                }

                return $result;

            default:
                throw new LogicException(sprintf('The array type does not support more than 2 parameters, but got %s.', json_encode($type['params'])));
        }
    }

    public function startVisitingObject(ClassMetadata $metadata, $object, array $type, Context $context)
    {
        $this->setCurrentObject($object);
        $this->objectMetadataStack->push($metadata);
        if (null === $this->result) {
            $this->result = $this->currentObject;
        }
    }

    public function visitProperty(PropertyMetadata $metadata, $data, Context $context)
    {
        if ($this->namingStrategy instanceof AdvancedNamingStrategyInterface) {
            $name = $this->namingStrategy->getPropertyName($metadata, $context);
        } else {
            $name = $this->namingStrategy->translateName($metadata);
        }

        if (!$metadata->type) {
            throw new RuntimeException(sprintf('You must define a type for %s::$%s.', $metadata->reflection->class, $metadata->name));
        }

        if ($metadata->xmlAttribute) {

            $attributes = $data->attributes($metadata->xmlNamespace);
            if (isset($attributes[$name])) {
                $v = $this->navigator->accept($attributes[$name], $metadata->type, $context);
                $this->accessor->setValue($this->currentObject, $v, $metadata);
            }

            return;
        }

        if ($metadata->xmlValue) {
            $v = $this->navigator->accept($data, $metadata->type, $context);
            $this->accessor->setValue($this->currentObject, $v, $metadata);

            return;
        }

        if ($metadata->xmlCollection) {
            $enclosingElem = $data;
            if (!$metadata->xmlCollectionInline) {
                $enclosingElem = $data->children($metadata->xmlNamespace)->$name;
            }

            $this->setCurrentMetadata($metadata);
            $v = $this->navigator->accept($enclosingElem, $metadata->type, $context);
            $this->revertCurrentMetadata();
            $this->accessor->setValue($this->currentObject, $v, $metadata);

            return;
        }

        if ($metadata->xmlNamespace) {
            $node = $data->children($metadata->xmlNamespace)->$name;
            if (!$node->count()) {
                return;
            }
        } else {

            $namespaces = $data->getDocNamespaces();

            if (isset($namespaces[''])) {
                $prefix = uniqid('ns-');
                $data->registerXPathNamespace($prefix, $namespaces['']);
                $nodes = $data->xpath('./' . $prefix . ':' . $name);
            } else {
                $nodes = $data->xpath('./' . $name);
            }
            if (empty($nodes)) {
                return;
            }
            $node = reset($nodes);
        }

        if ($metadata->xmlKeyValuePairs) {
            $this->setCurrentMetadata($metadata);
        }

        $v = $this->navigator->accept($node, $metadata->type, $context);

        $this->accessor->setValue($this->currentObject, $v, $metadata);
    }

    public function endVisitingObject(ClassMetadata $metadata, $data, array $type, Context $context)
    {
        $rs = $this->currentObject;
        $this->objectMetadataStack->pop();
        $this->revertCurrentObject();

        return $rs;
    }

    public function setCurrentObject($object)
    {
        $this->objectStack->push($this->currentObject);
        $this->currentObject = $object;
    }

    public function getCurrentObject()
    {
        return $this->currentObject;
    }

    public function revertCurrentObject()
    {
        return $this->currentObject = $this->objectStack->pop();
    }

    public function setCurrentMetadata(PropertyMetadata $metadata)
    {
        $this->metadataStack->push($this->currentMetadata);
        $this->currentMetadata = $metadata;
    }

    public function getCurrentMetadata()
    {
        return $this->currentMetadata;
    }

    public function revertCurrentMetadata()
    {
        return $this->currentMetadata = $this->metadataStack->pop();
    }

    public function getResult()
    {
        return $this->result;
    }

    /**
     * @param array <string> $doctypeWhitelist
     */
    public function setDoctypeWhitelist(array $doctypeWhitelist)
    {
        $this->doctypeWhitelist = $doctypeWhitelist;
    }

    /**
     * @return array<string>
     */
    public function getDoctypeWhitelist()
    {
        return $this->doctypeWhitelist;
    }

    /**
     * Retrieves internalSubset even in bugfixed php versions
     *
     * @param \DOMDocumentType $child
     * @param string $data
     * @return string
     */
    private function getDomDocumentTypeEntitySubset($data)
    {
        $startPos = $endPos = stripos($data, '<!doctype');
        $braces = 0;
        do {
            $char = $data[$endPos++];
            if ($char === '<') {
                ++$braces;
            }
            if ($char === '>') {
                --$braces;
            }
        } while ($braces > 0);

        $internalSubset = substr($data, $startPos, $endPos - $startPos);
        $internalSubset = str_replace(array("\n", "\r"), '', $internalSubset);
        $internalSubset = preg_replace('/\s{2,}/', ' ', $internalSubset);
        $internalSubset = str_replace(array("[ <!", "> ]>"), array('[<!', '>]>'), $internalSubset);

        return $internalSubset;
    }

    /**
     * @param mixed $value
     *
     * @return bool
     */
    public function isNull($value)
    {
        if ($value instanceof \SimpleXMLElement) {
            // Workaround for https://bugs.php.net/bug.php?id=75168 and https://github.com/schmittjoh/serializer/issues/817
            // If the "name" is empty means that we are on an not-existent node and subsequent operations on the object will trigger the warning:
            // "Node no longer exists"
            if ($value->getName() === "") {
                // @todo should be "true", but for collections needs a default collection value. maybe something for the 2.0
                return false;
            }

            $xsiAttributes = $value->attributes('http://www.w3.org/2001/XMLSchema-instance');
            if (isset($xsiAttributes['nil'])
                && ((string) $xsiAttributes['nil'] === 'true' || (string) $xsiAttributes['nil'] === '1')
            ) {
                return true;
            }
        }

        return $value === null;
    }
}
serializer/src/JMS/Serializer/TypeParser.php000064400000005525147361032420015066 0ustar00<?php

namespace JMS\Serializer;

/**
 * Parses a serializer type.
 *
 * @author Johannes M. Schmitt <schmittjoh@gmail.com>
 */
final class TypeParser extends \JMS\Parser\AbstractParser
{
    const T_NAME = 1;
    const T_STRING = 2;
    const T_OPEN_BRACKET = 3;
    const T_CLOSE_BRACKET = 4;
    const T_COMMA = 5;
    const T_NONE = 6;

    public function __construct()
    {
        parent::__construct(new \JMS\Parser\SimpleLexer(
            '/
                # PHP Class Names
                ((?:[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*\\\\)*[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*)

                # Strings
                |("(?:[^"]|"")*"|\'(?:[^\']|\'\')*\')

                # Ignore whitespace
                |\s*

                # Terminals
                |(.)
            /x',
            array(self::T_NAME => 'T_NAME', self::T_STRING => 'T_STRING', self::T_OPEN_BRACKET => 'T_OPEN_BRACKET',
                self::T_CLOSE_BRACKET => 'T_CLOSE_BRACKET', self::T_COMMA => 'T_COMMA', self::T_NONE => 'T_NONE'),
            function ($value) {
                switch ($value[0]) {
                    case '"':
                    case "'":
                        return array(TypeParser::T_STRING, substr($value, 1, -1));

                    case '<':
                        return array(TypeParser::T_OPEN_BRACKET, '<');

                    case '>':
                        return array(TypeParser::T_CLOSE_BRACKET, '>');

                    case ',':
                        return array(TypeParser::T_COMMA, ',');

                    default:
                        if (preg_match('/^(?:[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*\\\\)*[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*$/', $value)) {
                            return array(TypeParser::T_NAME, $value);
                        }

                        return array(TypeParser::T_NONE, $value);
                }
            }
        ));
    }

    /**
     * @return array of the format ["name" => string, "params" => array]
     */
    protected function parseInternal()
    {
        $typeName = $this->match(self::T_NAME);
        if (!$this->lexer->isNext(self::T_OPEN_BRACKET)) {
            return array('name' => $typeName, 'params' => array());
        }

        $this->match(self::T_OPEN_BRACKET);
        $params = array();
        do {
            if ($this->lexer->isNext(self::T_NAME)) {
                $params[] = $this->parseInternal();
            } else if ($this->lexer->isNext(self::T_STRING)) {
                $params[] = $this->match(self::T_STRING);
            } else {
                $this->matchAny(array(self::T_NAME, self::T_STRING)); // Will throw an exception.
            }
        } while ($this->lexer->isNext(self::T_COMMA) && $this->lexer->moveNext());

        $this->match(self::T_CLOSE_BRACKET);

        return array('name' => $typeName, 'params' => $params);
    }
}
serializer/src/JMS/Serializer/Annotation/Until.php000064400000000215147361032420016164 0ustar00<?php

namespace JMS\Serializer\Annotation;

/**
 * @Annotation
 * @Target({"PROPERTY", "METHOD"})
 */
final class Until extends Version
{
}
serializer/src/JMS/Serializer/Annotation/Inline.php000064400000000212147361032420016304 0ustar00<?php

namespace JMS\Serializer\Annotation;

/**
 * @Annotation
 * @Target({"PROPERTY","METHOD","ANNOTATION"})
 */
final class Inline
{
}
serializer/src/JMS/Serializer/Annotation/Since.php000064400000000215147361032420016132 0ustar00<?php

namespace JMS\Serializer\Annotation;

/**
 * @Annotation
 * @Target({"PROPERTY", "METHOD"})
 */
final class Since extends Version
{
}
serializer/src/JMS/Serializer/Annotation/XmlCollection.php000064400000000521147361032420017645 0ustar00<?php

namespace JMS\Serializer\Annotation;

abstract class XmlCollection
{
    /**
     * @var string
     */
    public $entry = 'entry';

    /**
     * @var boolean
     */
    public $inline = false;

    /**
     * @var string
     */
    public $namespace;

    /**
     * @var boolean
     */
    public $skipWhenEmpty = true;
}
serializer/src/JMS/Serializer/Annotation/XmlKeyValuePairs.php000064400000000224147361032420020276 0ustar00<?php

namespace JMS\Serializer\Annotation;

/**
 * @Annotation
 * @Target({"PROPERTY","METHOD","ANNOTATION"})
 */
final class XmlKeyValuePairs
{
}
serializer/src/JMS/Serializer/Annotation/PreSerialize.php000064400000000626147361032420017475 0ustar00<?php

namespace JMS\Serializer\Annotation;

/**
 * This annotation can be declared on methods which should be called
 * before the Serialization process.
 *
 * These methods do not need to be public, and should do any clean-up, or
 * preparation of the object that is necessary.
 *
 * @Annotation
 * @Target("METHOD")
 * @author Johannes M. Schmitt <schmittjoh@gmail.com>
 */
final class PreSerialize
{
}
serializer/src/JMS/Serializer/Annotation/Version.php000064400000000221147361032420016513 0ustar00<?php

namespace JMS\Serializer\Annotation;

abstract class Version
{
    /**
     * @Required
     * @var string
     */
    public $version;
}
serializer/src/JMS/Serializer/Annotation/AccessorOrder.php000064400000000557147361032420017640 0ustar00<?php

namespace JMS\Serializer\Annotation;

/**
 * Controls the order of properties in a class.
 *
 * @Annotation
 * @Target("CLASS")
 * @author Johannes M. Schmitt <schmittjoh@gmail.com>
 */
final class AccessorOrder
{
    /**
     * @Required
     * @var string
     */
    public $order;

    /**
     * @var array<string>
     */
    public $custom = array();
}
serializer/src/JMS/Serializer/Annotation/ExclusionPolicy.php000064400000001217147361032420020225 0ustar00<?php

namespace JMS\Serializer\Annotation;

use JMS\Serializer\Exception\RuntimeException;

/**
 * @Annotation
 * @Target("CLASS")
 */
final class ExclusionPolicy
{
    const NONE = 'NONE';
    const ALL = 'ALL';

    public $policy;

    public function __construct(array $values)
    {
        if (!\is_string($values['value'])) {
            throw new RuntimeException('"value" must be a string.');
        }

        $this->policy = strtoupper($values['value']);

        if (self::NONE !== $this->policy && self::ALL !== $this->policy) {
            throw new RuntimeException('Exclusion policy must either be "ALL", or "NONE".');
        }
    }
}
serializer/src/JMS/Serializer/Annotation/SkipWhenEmpty.php000064400000000221147361032420017635 0ustar00<?php

namespace JMS\Serializer\Annotation;

/**
 * @Annotation
 * @Target({"PROPERTY","METHOD","ANNOTATION"})
 */
final class SkipWhenEmpty
{
}
serializer/src/JMS/Serializer/Annotation/Groups.php000064400000000306147361032420016351 0ustar00<?php

namespace JMS\Serializer\Annotation;

/**
 * @Annotation
 * @Target({"PROPERTY","METHOD","ANNOTATION"})
 */
final class Groups
{
    /** @var array<string> @Required */
    public $groups;
}
serializer/src/JMS/Serializer/Annotation/XmlRoot.php000064400000000361147361032420016477 0ustar00<?php

namespace JMS\Serializer\Annotation;

/**
 * @Annotation
 * @Target("CLASS")
 */
final class XmlRoot
{
    /**
     * @Required
     * @var string
     */
    public $name;

    /**
     * @var string
     */
    public $namespace;
}
serializer/src/JMS/Serializer/Annotation/SerializedName.php000064400000000733147361032420017772 0ustar00<?php

namespace JMS\Serializer\Annotation;

use JMS\Serializer\Exception\RuntimeException;

/**
 * @Annotation
 * @Target({"PROPERTY","METHOD", "ANNOTATION"})
 */
final class SerializedName
{
    public $name;

    public function __construct(array $values)
    {
        if (!isset($values['value']) || !\is_string($values['value'])) {
            throw new RuntimeException(sprintf('"value" must be a string.'));
        }

        $this->name = $values['value'];
    }
}
serializer/src/JMS/Serializer/Annotation/XmlDiscriminator.php000064400000000461147361032420020364 0ustar00<?php

namespace JMS\Serializer\Annotation;


/**
 * @Annotation
 * @Target("CLASS")
 */
class XmlDiscriminator
{
    /**
     * @var boolean
     */
    public $attribute = false;

    /**
     * @var boolean
     */
    public $cdata = true;

    /**
     * @var string
     */
    public $namespace;
}
serializer/src/JMS/Serializer/Annotation/Discriminator.php000064400000000502147361032420017677 0ustar00<?php

namespace JMS\Serializer\Annotation;

/**
 * @Annotation
 * @Target("CLASS")
 */
class Discriminator
{
    /** @var array<string> */
    public $map;

    /** @var string */
    public $field = 'type';

    /** @var boolean */
    public $disabled = false;

    /** @var string[] */
    public $groups = array();
}
serializer/src/JMS/Serializer/Annotation/XmlValue.php000064400000000312147361032420016624 0ustar00<?php

namespace JMS\Serializer\Annotation;

/**
 * @Annotation
 * @Target({"PROPERTY","METHOD","ANNOTATION"})
 */
final class XmlValue
{
    /**
     * @var boolean
     */
    public $cdata = true;
}
serializer/src/JMS/Serializer/Annotation/Type.php000064400000000317147361032420016015 0ustar00<?php

namespace JMS\Serializer\Annotation;

/**
 * @Annotation
 * @Target({"PROPERTY", "METHOD","ANNOTATION"})
 */
final class Type
{
    /**
     * @Required
     * @var string
     */
    public $name;
}
serializer/src/JMS/Serializer/Annotation/XmlNamespace.php000064400000000367147361032420017456 0ustar00<?php

namespace JMS\Serializer\Annotation;

/**
 * @Annotation
 * @Target("CLASS")
 */
final class XmlNamespace
{
    /**
     * @Required
     * @var string
     */
    public $uri;

    /**
     * @var string
     */
    public $prefix = '';
}
serializer/src/JMS/Serializer/Annotation/HandlerCallback.php000064400000000522147361032420020064 0ustar00<?php

namespace JMS\Serializer\Annotation;

/**
 * @Annotation
 * @Target("METHOD")
 * @deprecated
 * @author Johannes M. Schmitt <schmittjoh@gmail.com>
 */
final class HandlerCallback
{
    /**
     * @Required
     * @var string
     */
    public $format;

    /**
     * @Required
     * @var string
     */
    public $direction;
}
serializer/src/JMS/Serializer/Annotation/MaxDepth.php000064400000000324147361032420016604 0ustar00<?php

namespace JMS\Serializer\Annotation;

/**
 * @Annotation
 * @Target({"PROPERTY","METHOD","ANNOTATION"})
 */
final class MaxDepth
{
    /**
     * @Required
     * @var integer
     */
    public $depth;
}
serializer/src/JMS/Serializer/Annotation/XmlAttribute.php000064400000000313147361032420017514 0ustar00<?php

namespace JMS\Serializer\Annotation;

/**
 * @Annotation
 * @Target({"PROPERTY", "METHOD","ANNOTATION"})
 */
final class XmlAttribute
{
    /**
     * @var string
     */
    public $namespace;
}
serializer/src/JMS/Serializer/Annotation/XmlElement.php000064400000000410147361032420017140 0ustar00<?php

namespace JMS\Serializer\Annotation;

/**
 * @Annotation
 * @Target({"PROPERTY", "METHOD","ANNOTATION"})
 */
final class XmlElement
{
    /**
     * @var boolean
     */
    public $cdata = true;

    /**
     * @var string
     */
    public $namespace;
}
serializer/src/JMS/Serializer/Annotation/Exclude.php000064400000000246147361032420016466 0ustar00<?php

namespace JMS\Serializer\Annotation;

/**
 * @Annotation
 * @Target({"PROPERTY", "CLASS", "METHOD", "ANNOTATION"})
 */
final class Exclude
{
    public $if;
}
serializer/src/JMS/Serializer/Annotation/XmlMap.php000064400000000346147361032420016274 0ustar00<?php

namespace JMS\Serializer\Annotation;

/**
 * @Annotation
 * @Target({"PROPERTY","METHOD","ANNOTATION"})
 */
final class XmlMap extends XmlCollection
{
    /**
     * @var string
     */
    public $keyAttribute = '_key';
}
serializer/src/JMS/Serializer/Annotation/XmlAttributeMap.php000064400000000207147361032420020154 0ustar00<?php

namespace JMS\Serializer\Annotation;

/**
 * @Annotation
 * @Target({"PROPERTY", "METHOD"})
 */
final class XmlAttributeMap
{
}
serializer/src/JMS/Serializer/Annotation/Expose.php000064400000000233147361032420016334 0ustar00<?php

namespace JMS\Serializer\Annotation;

/**
 * @Annotation
 * @Target({"PROPERTY", "METHOD","ANNOTATION"})
 */
final class Expose
{
    public $if;
}
serializer/src/JMS/Serializer/Annotation/PostSerialize.php000064400000000167147361032420017674 0ustar00<?php

namespace JMS\Serializer\Annotation;

/**
 * @Annotation
 * @Target("METHOD")
 */
final class PostSerialize
{
}
serializer/src/JMS/Serializer/Annotation/ReadOnlyProperty.php000064400000000362147361032420020356 0ustar00<?php

declare(strict_types=1);

namespace JMS\Serializer\Annotation;

/**
 * @Annotation
 * @Target({"CLASS","PROPERTY"})
 *
 * @final
 */
/* final */ class ReadOnlyProperty
{
    /**
     * @var bool
     */
    public $readOnly = true;
}

serializer/src/JMS/Serializer/Annotation/ReadOnly.php000064400000000412147361032420016605 0ustar00<?php

namespace JMS\Serializer\Annotation;

/**
 * @Annotation
 * @Target({"CLASS","PROPERTY"})
 *
 * @deprecated use `@ReadOnlyProperty` instead
 */
final class ReadOnly extends ReadOnlyProperty
{
    /**
     * @var boolean
     */
    public $readOnly = true;
}
serializer/src/JMS/Serializer/Annotation/PostDeserialize.php000064400000000542147361032420020202 0ustar00<?php

namespace JMS\Serializer\Annotation;

/**
 * This annotation can be defined on methods which are called after the
 * deserialization of the object is complete.
 *
 * These methods do not necessarily have to be public.
 *
 * @Annotation
 * @Target("METHOD")
 * @author Johannes M. Schmitt <schmittjoh@gmail.com>
 */
final class PostDeserialize
{
}
serializer/src/JMS/Serializer/Annotation/Accessor.php000064400000000434147361032420016636 0ustar00<?php

namespace JMS\Serializer\Annotation;

/**
 * @Annotation
 * @Target("PROPERTY")
 *
 * @author Johannes M. Schmitt <schmittjoh@gmail.com>
 */
final class Accessor
{
    /**
     * @var string
     */
    public $getter;

    /**
     * @var string
     */
    public $setter;
}
serializer/src/JMS/Serializer/Annotation/VirtualProperty.php000064400000001317147361032420020270 0ustar00<?php

namespace JMS\Serializer\Annotation;

/**
 * @Annotation
 * @Target({"METHOD", "CLASS"})
 *
 * @author Alexander Klimenkov <alx.devel@gmail.com>
 */
final class VirtualProperty
{
    public $exp;
    public $name;
    public $options = array();

    public function __construct(array $data)
    {
        if (isset($data['value'])) {
            $data['name'] = $data['value'];
            unset($data['value']);
        }

        foreach ($data as $key => $value) {
            if (!property_exists(__CLASS__, $key)) {
                throw new \BadMethodCallException(sprintf('Unknown property "%s" on annotation "%s".', $key, __CLASS__));
            }
            $this->{$key} = $value;
        }
    }
}

serializer/src/JMS/Serializer/Annotation/XmlList.php000064400000000241147361032420016464 0ustar00<?php

namespace JMS\Serializer\Annotation;

/**
 * @Annotation
 * @Target({"PROPERTY","METHOD","ANNOTATION"})
 */
final class XmlList extends XmlCollection
{
}
serializer/src/JMS/Serializer/Annotation/AccessType.php000064400000000400147361032420017130 0ustar00<?php

namespace JMS\Serializer\Annotation;

/**
 * @Annotation
 * @Target({"CLASS", "PROPERTY"})
 *
 * @author Johannes M. Schmitt <schmittjoh@gmail.com>
 */
final class AccessType
{
    /**
     * @Required
     * @var string
     */
    public $type;
}
serializer/src/JMS/Serializer/Context.php000064400000015037147361032420014413 0ustar00<?php

namespace JMS\Serializer;

use JMS\Serializer\Exception\RuntimeException;
use JMS\Serializer\Exclusion\DepthExclusionStrategy;
use JMS\Serializer\Exclusion\DisjunctExclusionStrategy;
use JMS\Serializer\Exclusion\ExclusionStrategyInterface;
use JMS\Serializer\Exclusion\GroupsExclusionStrategy;
use JMS\Serializer\Exclusion\VersionExclusionStrategy;
use JMS\Serializer\Metadata\ClassMetadata;
use JMS\Serializer\Metadata\PropertyMetadata;
use Metadata\MetadataFactory;
use Metadata\MetadataFactoryInterface;
use PhpCollection\Map;

abstract class Context
{
    /**
     * @deprecated use has/get/set attribute methods
     * @var \PhpCollection\Map
     */
    public $attributes;

    private $format;

    /** @var VisitorInterface */
    private $visitor;

    /** @var GraphNavigator */
    private $navigator;

    /** @var MetadataFactory */
    private $metadataFactory;

    /** @var ExclusionStrategyInterface */
    private $exclusionStrategy;

    /** @var boolean|null */
    private $serializeNull;

    private $initialized = false;

    /** @var \SplStack */
    private $metadataStack;

    public function __construct()
    {
        $this->attributes = new Map();
        $this->metadataStack = new \SplStack();
    }

    /**
     * @param string $format
     */
    public function initialize($format, VisitorInterface $visitor, GraphNavigator $navigator, MetadataFactoryInterface $factory)
    {
        if ($this->initialized) {
            throw new \LogicException('This context was already initialized, and cannot be re-used.');
        }

        $this->initialized = true;
        $this->format = $format;
        $this->visitor = $visitor;
        $this->navigator = $navigator;
        $this->metadataFactory = $factory;
        $this->metadataStack = new \SplStack();
    }

    /**
     * @deprecated  Will be removed in 2.0, Use getNavigator()->accept() instead
     * @param $data
     * @param array|null $type
     * @return mixed
     */
    public function accept($data, array $type = null)
    {
        return $this->navigator->accept($data, $type, $this);
    }

    public function getMetadataFactory()
    {
        return $this->metadataFactory;
    }

    public function getVisitor()
    {
        return $this->visitor;
    }

    public function getNavigator()
    {
        return $this->navigator;
    }

    public function getExclusionStrategy()
    {
        return $this->exclusionStrategy;
    }

    public function hasAttribute($key)
    {
        return $this->attributes->get($key)->isDefined();
    }

    public function getAttribute($key)
    {
        return $this->attributes->get($key)->get();
    }

    public function setAttribute($key, $value)
    {
        $this->assertMutable();
        $this->attributes->set($key, $value);

        return $this;
    }

    private function assertMutable()
    {
        if (!$this->initialized) {
            return;
        }

        throw new \LogicException('This context was already initialized and is immutable; you cannot modify it anymore.');
    }

    public function addExclusionStrategy(ExclusionStrategyInterface $strategy)
    {
        $this->assertMutable();

        if (null === $this->exclusionStrategy) {
            $this->exclusionStrategy = $strategy;

            return $this;
        }

        if ($this->exclusionStrategy instanceof DisjunctExclusionStrategy) {
            $this->exclusionStrategy->addStrategy($strategy);

            return $this;
        }

        $this->exclusionStrategy = new DisjunctExclusionStrategy(array(
            $this->exclusionStrategy,
            $strategy,
        ));

        return $this;
    }

    /**
     * @param integer $version
     */
    public function setVersion($version)
    {
        if (null === $version) {
            throw new \LogicException('The version must not be null.');
        }

        $this->attributes->set('version', $version);
        $this->addExclusionStrategy(new VersionExclusionStrategy($version));

        return $this;
    }

    /**
     * @param array|string $groups
     */
    public function setGroups($groups)
    {
        if (empty($groups)) {
            throw new \LogicException('The groups must not be empty.');
        }

        $this->attributes->set('groups', (array)$groups);
        $this->addExclusionStrategy(new GroupsExclusionStrategy((array)$groups));

        return $this;
    }

    public function enableMaxDepthChecks()
    {
        $this->addExclusionStrategy(new DepthExclusionStrategy());

        return $this;
    }

    /**
     * Set if NULLs should be serialized (TRUE) ot not (FALSE)
     *
     * @param bool $bool
     * @return $this
     */
    public function setSerializeNull($bool)
    {
        $this->serializeNull = (boolean)$bool;

        return $this;
    }

    /**
     * Returns TRUE when NULLs should be serialized
     * Returns FALSE when NULLs should not be serialized
     * Returns NULL when NULLs should not be serialized,
     * but the user has not explicitly decided to use this policy
     *
     * @return bool|null
     */
    public function shouldSerializeNull()
    {
        return $this->serializeNull;
    }

    /**
     * @return string
     */
    public function getFormat()
    {
        return $this->format;
    }

    public function pushClassMetadata(ClassMetadata $metadata)
    {
        $this->metadataStack->push($metadata);
    }

    public function pushPropertyMetadata(PropertyMetadata $metadata)
    {
        $this->metadataStack->push($metadata);
    }

    public function popPropertyMetadata()
    {
        $metadata = $this->metadataStack->pop();

        if (!$metadata instanceof PropertyMetadata) {
            throw new RuntimeException('Context metadataStack not working well');
        }
    }

    public function popClassMetadata()
    {
        $metadata = $this->metadataStack->pop();

        if (!$metadata instanceof ClassMetadata) {
            throw new RuntimeException('Context metadataStack not working well');
        }
    }

    public function getMetadataStack()
    {
        return $this->metadataStack;
    }

    /**
     * @return array
     */
    public function getCurrentPath()
    {
        if (!$this->metadataStack) {
            return array();
        }

        $paths = array();
        foreach ($this->metadataStack as $metadata) {
            if ($metadata instanceof PropertyMetadata) {
                array_unshift($paths, $metadata->name);
            }
        }

        return $paths;
    }


    abstract public function getDepth();

    /**
     * @return integer
     */
    abstract public function getDirection();
}
serializer/README.md000064400000000664147361032420010204 0ustar00Serializer [![Scrutinizer Quality Score](https://scrutinizer-ci.com/g/schmittjoh/serializer/badges/quality-score.png?s=189df68e00c75d3fe155bc0da0b53b53709a9895)](https://scrutinizer-ci.com/g/schmittjoh/serializer/) [![Build Status](https://travis-ci.org/schmittjoh/serializer.svg?branch=master)](https://travis-ci.org/schmittjoh/serializer)
==========

Learn more about it in its [documentation](http://jmsyst.com/libs/serializer/1.x).
serializer/CHANGELOG.md000064400000215320147361032420010533 0ustar00# Change Log

## [1.14.1](https://github.com/schmittjoh/serializer/tree/1.14.1) (2020-02-22)

**Merged pull requests:**

- PHP7.4 ternary operator deprecation [\#1163](https://github.com/schmittjoh/serializer/pull/1163) ([adhocore](https://github.com/adhocore))

## [1.14.0](https://github.com/schmittjoh/serializer/tree/1.14.0) (2019-04-17)

**Implemented enhancements:**

- Discriminator property serialization when parent is in discriminator map for v1 [\#982](https://github.com/schmittjoh/serializer/pull/982) ([supersmile2009](https://github.com/supersmile2009))
- Expose and test GroupsExclusionStrategy::getGroupsFor\(\) [\#1069](https://github.com/schmittjoh/serializer/pull/1069) ([goetas](https://github.com/goetas))

## [1.13.0](https://github.com/schmittjoh/serializer/tree/1.13.0)

**Implemented enhancements:**

- Bugfix/metadata serialization [\#969](https://github.com/schmittjoh/serializer/pull/969) ([supersmile2009](https://github.com/supersmile2009))

**Fixed bugs:**

- Exception on deserialization using XML and exclude-if [\#975](https://github.com/schmittjoh/serializer/issues/975)

**Closed issues:**

- Serialization fails if root element has custom handler [\#961](https://github.com/schmittjoh/serializer/issues/961)
- Make inline property work with deserialization too [\#937](https://github.com/schmittjoh/serializer/issues/937)

**Merged pull requests:**

- Serializer 2.0 compatibility features [\#967](https://github.com/schmittjoh/serializer/pull/967) ([goetas](https://github.com/goetas))

## [1.12.1](https://github.com/schmittjoh/serializer/tree/1.12.1) (2018-06-01)

**Fixed bugs:**

- Accessing static property as non static [\#960](https://github.com/schmittjoh/serializer/issues/960)
- creating JMS\Serializer\Metadata-\>closureAccessor on internal class failed [\#959](https://github.com/schmittjoh/serializer/issues/959)

## [1.12.0](https://github.com/schmittjoh/serializer/tree/1.12.0) (2018-05-25)

**Implemented enhancements:**

- Add support for namespaced XML attribute on Discriminator + Tests [\#909](https://github.com/schmittjoh/serializer/pull/909) ([ArthurJam](https://github.com/ArthurJam))
- Introduce graph navigator interface [\#876](https://github.com/schmittjoh/serializer/pull/876) ([goetas](https://github.com/goetas))
- Use Bind closure accessor [\#875](https://github.com/schmittjoh/serializer/pull/875) ([goetas](https://github.com/goetas))

**Fixed bugs:**

- DoctrineObjectConstructor and deserialize not work [\#806](https://github.com/schmittjoh/serializer/issues/806)
- \[Symfony\] DoctrineObjectorConstructor always creates new entity because of camel case to snake case conversion [\#734](https://github.com/schmittjoh/serializer/issues/734)
- Fix DoctrineObjectConstructor deserialization with naming strategies [\#951](https://github.com/schmittjoh/serializer/pull/951) ([re2bit](https://github.com/re2bit))

**Closed issues:**

- Feature proposal: dynamic property serialized name [\#225](https://github.com/schmittjoh/serializer/issues/225)
- Mapping request payload works for JSON but not for XML [\#820](https://github.com/schmittjoh/serializer/issues/820)

**Merged pull requests:**

- Cange the spelling of a word [\#939](https://github.com/schmittjoh/serializer/pull/939) ([greg0ire](https://github.com/greg0ire))
- Use dedicated PHPUnit assertions [\#928](https://github.com/schmittjoh/serializer/pull/928) ([carusogabriel](https://github.com/carusogabriel))
- Update arrays.rst [\#907](https://github.com/schmittjoh/serializer/pull/907) ([burki](https://github.com/burki))
- Change to MIT license [\#956](https://github.com/schmittjoh/serializer/pull/956) ([goetas](https://github.com/goetas))
- Double logic for group exclusion \(20% faster\) [\#941](https://github.com/schmittjoh/serializer/pull/941) ([goetas](https://github.com/goetas))
- Type casting tests [\#917](https://github.com/schmittjoh/serializer/pull/917) ([goetas](https://github.com/goetas))
- Explicitly set serialization precision for tests [\#899](https://github.com/schmittjoh/serializer/pull/899) ([Majkl578](https://github.com/Majkl578))
- Deprecations   [\#877](https://github.com/schmittjoh/serializer/pull/877) ([goetas](https://github.com/goetas))
- Added note on SerializedName annotation valididity [\#874](https://github.com/schmittjoh/serializer/pull/874) ([bobvandevijver](https://github.com/bobvandevijver))
- Optimizations [\#861](https://github.com/schmittjoh/serializer/pull/861) ([goetas](https://github.com/goetas))

## [1.11.0](https://github.com/schmittjoh/serializer/tree/1.11.0) (2018-02-04)

**Implemented enhancements:**

- Deserialize xmlKeyValuePairs [\#868](https://github.com/schmittjoh/serializer/pull/868) ([goetas](https://github.com/goetas))
- Add AdvancedNamingStrategyInterface [\#859](https://github.com/schmittjoh/serializer/pull/859) ([LeaklessGfy](https://github.com/LeaklessGfy))
- Deserialize xmlKeyValuePairs [\#840](https://github.com/schmittjoh/serializer/pull/840) ([fdyckhoff](https://github.com/fdyckhoff))

**Fixed bugs:**

- Exception thrown for non-existant accessor to an excluded property [\#862](https://github.com/schmittjoh/serializer/issues/862)
- Support non-namespaced lists in namespaced XML [\#851](https://github.com/schmittjoh/serializer/pull/851) ([bertterheide](https://github.com/bertterheide))

**Closed issues:**

- Context Group not working [\#865](https://github.com/schmittjoh/serializer/issues/865)
- Not all virtual properties are serialized [\#864](https://github.com/schmittjoh/serializer/issues/864)
- DeserializedName [\#857](https://github.com/schmittjoh/serializer/issues/857)
- Annotation does not exist, or could not be auto-loaded. [\#855](https://github.com/schmittjoh/serializer/issues/855)
- \[Question\] Serialization of primitive types [\#853](https://github.com/schmittjoh/serializer/issues/853)
- Empty list when deserializing namespaced XML with children that are not namespaced [\#850](https://github.com/schmittjoh/serializer/issues/850)
- XmlList\(skipWhenEmpty=true\) or @SkipWhenEmpty\(\) does not work [\#847](https://github.com/schmittjoh/serializer/issues/847)
- DateHandler Timezone ignored on deserialization [\#457](https://github.com/schmittjoh/serializer/issues/457)

**Merged pull requests:**

- Drop HHVM support [\#869](https://github.com/schmittjoh/serializer/pull/869) ([goetas](https://github.com/goetas))
- Allow excluded private properties to not have a getter acc… [\#863](https://github.com/schmittjoh/serializer/pull/863) ([0mars](https://github.com/0mars))
- Solve php 7.2 deprecations [\#860](https://github.com/schmittjoh/serializer/pull/860) ([goetas](https://github.com/goetas))
- Fixed issue where timezone is lost when creating DateTime from unix timestamp [\#835](https://github.com/schmittjoh/serializer/pull/835) ([goetas](https://github.com/goetas))

## [1.10.0](https://github.com/schmittjoh/serializer/tree/1.10.0) (2017-11-30)

**Implemented enhancements:**

- support PSR-11 compatible DI containers [\#844](https://github.com/schmittjoh/serializer/pull/844) ([xabbuh](https://github.com/xabbuh))

**Closed issues:**

- Serialize using jsonSerialize\(\) if object implements JsonSerializable [\#846](https://github.com/schmittjoh/serializer/issues/846)
- ExclusionStrategy backward compatibility break [\#843](https://github.com/schmittjoh/serializer/issues/843)
- @MaxDepth jms/serializer-bundle 2.2 [\#842](https://github.com/schmittjoh/serializer/issues/842)

## [1.9.2](https://github.com/schmittjoh/serializer/tree/1.9.2) (2017-11-22)

**Fixed bugs:**

- Missing ClassMetadata deserialization data [\#841](https://github.com/schmittjoh/serializer/pull/841) ([TristanMogwai](https://github.com/TristanMogwai))

**Closed issues:**

- DateTime format documentation [\#836](https://github.com/schmittjoh/serializer/issues/836)
- Deserialization not working with camelCase [\#831](https://github.com/schmittjoh/serializer/issues/831)

**Merged pull requests:**

- Fix documentation syntax errors on available types [\#839](https://github.com/schmittjoh/serializer/pull/839) ([andy-morgan](https://github.com/andy-morgan))
- Improve documentation about default DateTime format [\#838](https://github.com/schmittjoh/serializer/pull/838) ([enumag](https://github.com/enumag))

## [1.9.1](https://github.com/schmittjoh/serializer/tree/1.9.1) (2017-10-27)

**Fixed bugs:**

- Dynamic exclusion strategy, Variable "object" is not valid [\#826](https://github.com/schmittjoh/serializer/issues/826)

**Closed issues:**

- Allow DateTime or Null [\#779](https://github.com/schmittjoh/serializer/issues/779)

**Merged pull requests:**

- Alow to use "object" var in expressions when deserializing [\#827](https://github.com/schmittjoh/serializer/pull/827) ([goetas](https://github.com/goetas))

## [1.9.0](https://github.com/schmittjoh/serializer/tree/1.9.0) (2017-09-28)

**Implemented enhancements:**

- Doctrine LazyCriteriaCollection not supported [\#814](https://github.com/schmittjoh/serializer/issues/814)
- Do not require the translator [\#824](https://github.com/schmittjoh/serializer/pull/824) ([goetas](https://github.com/goetas))
- Added mapping for guid type [\#802](https://github.com/schmittjoh/serializer/pull/802) ([develth](https://github.com/develth))
- Added translation domain to FormErrorHandler [\#783](https://github.com/schmittjoh/serializer/pull/783) ([prosalov](https://github.com/prosalov))

**Fixed bugs:**

-  Node no longer exists - Deserialize Error [\#817](https://github.com/schmittjoh/serializer/issues/817)
- Serializer fails if there is no AnnotationDriver in the DriverChain instance [\#815](https://github.com/schmittjoh/serializer/issues/815)
- Evaluate XML xsi:nil="1" to null  [\#799](https://github.com/schmittjoh/serializer/pull/799) ([Bouwdie](https://github.com/Bouwdie))

**Closed issues:**

- Empty array removed from XML serialization [\#816](https://github.com/schmittjoh/serializer/issues/816)
- XML Discriminator tags don't work in YAML metadata [\#811](https://github.com/schmittjoh/serializer/issues/811)
- Launching phpunit does not execute any test [\#809](https://github.com/schmittjoh/serializer/issues/809)
- Add "bool" Annotation/Type [\#807](https://github.com/schmittjoh/serializer/issues/807)
- Add support for overriding default annotation driver configuration [\#804](https://github.com/schmittjoh/serializer/issues/804)
- Add description to PropertyMetadata? [\#800](https://github.com/schmittjoh/serializer/issues/800)

**Merged pull requests:**

- Workaround to avoid triggering simplexml warning [\#825](https://github.com/schmittjoh/serializer/pull/825) ([goetas](https://github.com/goetas))
- Added null metadata driver [\#822](https://github.com/schmittjoh/serializer/pull/822) ([goetas](https://github.com/goetas))
- Run Travis tests against modern PHP [\#819](https://github.com/schmittjoh/serializer/pull/819) ([Majkl578](https://github.com/Majkl578))
- Added bool type alias [\#818](https://github.com/schmittjoh/serializer/pull/818) ([Majkl578](https://github.com/Majkl578))
- Revert back to PSR-0 [\#797](https://github.com/schmittjoh/serializer/pull/797) ([goetas](https://github.com/goetas))

## [1.8.1](https://github.com/schmittjoh/serializer/tree/1.8.1) (2017-07-13)

**Closed issues:**

- Version 1.8 is breaking backwards compatibility [\#796](https://github.com/schmittjoh/serializer/issues/796)

## [1.8.0](https://github.com/schmittjoh/serializer/tree/1.8.0) (2017-07-12)

**Implemented enhancements:**

- Detect XML xsi:nil="true" to null when deserializing [\#790](https://github.com/schmittjoh/serializer/pull/790) ([goetas](https://github.com/goetas))
- Added support for a third deserialize parameter for the DateTime type [\#788](https://github.com/schmittjoh/serializer/pull/788) ([bobvandevijver](https://github.com/bobvandevijver))
- Added trim to xml metadata reader for groups parameter, and added support for groups element [\#781](https://github.com/schmittjoh/serializer/pull/781) ([mrosiu](https://github.com/mrosiu))
- Add propertyMetdata to dynamic expression variables [\#778](https://github.com/schmittjoh/serializer/pull/778) ([goetas](https://github.com/goetas))
- Fix xml deserialization when xsi:nil="true" is set [\#771](https://github.com/schmittjoh/serializer/pull/771) ([Bouwdie](https://github.com/Bouwdie))

**Fixed bugs:**

- do not disappear type params in DoctrineProxySubscriber [\#793](https://github.com/schmittjoh/serializer/pull/793) ([kriswallsmith](https://github.com/kriswallsmith))
- \#784 fix with inline array of type array\<K, V\> [\#785](https://github.com/schmittjoh/serializer/pull/785) ([aviortm](https://github.com/aviortm))

**Closed issues:**

- inline array with type array\<K, V\> not serialized [\#784](https://github.com/schmittjoh/serializer/issues/784)
- \[2.0\] \[Feature-request\] Provide InitializedObjectConstructor as default [\#775](https://github.com/schmittjoh/serializer/issues/775)
- Allow access to PropertyMetadata in Dynamic Exclusion strategies [\#772](https://github.com/schmittjoh/serializer/issues/772)
- Overriding groups at runtime does not work, or? [\#767](https://github.com/schmittjoh/serializer/issues/767)
- DateTime format and control characters [\#94](https://github.com/schmittjoh/serializer/issues/94)

**Merged pull requests:**

- Missing features of the compiler pass [\#789](https://github.com/schmittjoh/serializer/pull/789) ([mikemix](https://github.com/mikemix))
- Updated documentation related to PR \#778 [\#780](https://github.com/schmittjoh/serializer/pull/780) ([bblue](https://github.com/bblue))
- \[RFC\] Move to PSR 4 [\#770](https://github.com/schmittjoh/serializer/pull/770) ([goetas](https://github.com/goetas))
- Re-formatted code for better PSR compliance [\#769](https://github.com/schmittjoh/serializer/pull/769) ([goetas](https://github.com/goetas))
- Proposing some guidelines for contributing [\#763](https://github.com/schmittjoh/serializer/pull/763) ([goetas](https://github.com/goetas))

## [1.7.1](https://github.com/schmittjoh/serializer/tree/1.7.1) (2017-05-15)

**Fixed bugs:**

- Custom type handlers does not work with doctrine proxies anymore [\#765](https://github.com/schmittjoh/serializer/issues/765)
- Doctrine listener should not change the type on proxies with virtual type [\#768](https://github.com/schmittjoh/serializer/pull/768) ([goetas](https://github.com/goetas))

**Closed issues:**

- Missing bool type in graphNavigator.php in method accept\(\) [\#764](https://github.com/schmittjoh/serializer/issues/764)
- The sub-class "Proxy-Class" is not listed in the discriminator of the base class "DiscriminatorClass" [\#459](https://github.com/schmittjoh/serializer/issues/459)
- Configure whether serializing empty array. [\#124](https://github.com/schmittjoh/serializer/issues/124)

## [1.7.0](https://github.com/schmittjoh/serializer/tree/1.7.0) (2017-05-10)

**Implemented enhancements:**

- Skip doctrine proxy initializations when exclusion strategy will exclude it  [\#760](https://github.com/schmittjoh/serializer/pull/760) ([goetas](https://github.com/goetas))

**Closed issues:**

- Error deserializing a map of \(nullable\) objects [\#762](https://github.com/schmittjoh/serializer/issues/762)
- Add data using setData produces hashes instead of arrays [\#761](https://github.com/schmittjoh/serializer/issues/761)

## [1.7.0-RC2](https://github.com/schmittjoh/serializer/tree/1.7.0-RC2) (2017-05-05)

**Implemented enhancements:**

- Make sure input is always a string [\#755](https://github.com/schmittjoh/serializer/pull/755) ([goetas](https://github.com/goetas))
- Allow namespaced XML element discriminator [\#753](https://github.com/schmittjoh/serializer/pull/753) ([goetas](https://github.com/goetas))

**Fixed bugs:**

- Allow to skip "empty serialization result" when serializing [\#757](https://github.com/schmittjoh/serializer/pull/757) ([goetas](https://github.com/goetas))

**Closed issues:**

- Is it possible to use @XmlNamespace & @XmlRoot in a class at same time ? [\#759](https://github.com/schmittjoh/serializer/issues/759)
- Serializes FOS:User datas with ExclusionPolicy\("all"\)  [\#599](https://github.com/schmittjoh/serializer/issues/599)

**Merged pull requests:**

- Add a quick reference for how to enable expression evaluator [\#758](https://github.com/schmittjoh/serializer/pull/758) ([chasen](https://github.com/chasen))
- Allow for setExpressionEvaluator usage to be chainable [\#756](https://github.com/schmittjoh/serializer/pull/756) ([chasen](https://github.com/chasen))
- Fix typo in annotation docs [\#754](https://github.com/schmittjoh/serializer/pull/754) ([JustBlackBird](https://github.com/JustBlackBird))

## [1.7.0-RC1](https://github.com/schmittjoh/serializer/tree/1.7.0-RC1) (2017-04-25)

**Implemented enhancements:**

- Allow to configure the doctrine object constructor [\#751](https://github.com/schmittjoh/serializer/pull/751) ([goetas](https://github.com/goetas))
- Trigger doctrine events on doctrine proxies [\#750](https://github.com/schmittjoh/serializer/pull/750) ([goetas](https://github.com/goetas))
- Added stdClass serialization handler [\#749](https://github.com/schmittjoh/serializer/pull/749) ([goetas](https://github.com/goetas))

**Fixed bugs:**

- Array gets serialized as object, not as array, depending on order. [\#709](https://github.com/schmittjoh/serializer/issues/709)
- Doctrine Proxies and serializer.pre\_serialize [\#666](https://github.com/schmittjoh/serializer/issues/666)
- Fix stdClass inconsistencies when serializing to JSON [\#730](https://github.com/schmittjoh/serializer/pull/730) ([goetas](https://github.com/goetas))
- Allow to typehint for the type \(array/hash\) of the root item to be serialized [\#728](https://github.com/schmittjoh/serializer/pull/728) ([goetas](https://github.com/goetas))

**Closed issues:**

- Array serialized as JSON object [\#706](https://github.com/schmittjoh/serializer/issues/706)
- From old issue \#290 [\#670](https://github.com/schmittjoh/serializer/issues/670)
- Form validation error response - field names not converted from camel case to underscore [\#587](https://github.com/schmittjoh/serializer/issues/587)
- Ability to getGroups on Context [\#554](https://github.com/schmittjoh/serializer/issues/554)
- SerializedName misleading usage and constructor issue [\#548](https://github.com/schmittjoh/serializer/issues/548)
- Discriminator should support xmlAttribute [\#547](https://github.com/schmittjoh/serializer/issues/547)
- Public method accessor is required for excluded/not exposed properties [\#519](https://github.com/schmittjoh/serializer/issues/519)
- Entity changed via preserialize and wrongly persisted [\#509](https://github.com/schmittjoh/serializer/issues/509)
- XML deserialization properties null when using default namespace [\#504](https://github.com/schmittjoh/serializer/issues/504)
- AccessorOrder is ignored [\#501](https://github.com/schmittjoh/serializer/issues/501)
- Deserialization of sub entites with non existing id [\#492](https://github.com/schmittjoh/serializer/issues/492)
- \[Question\] Handler/Converter for specific field [\#476](https://github.com/schmittjoh/serializer/issues/476)
- getClassName regex may incorrectly retrieve a false class name from comments above the class. [\#460](https://github.com/schmittjoh/serializer/issues/460)
- Multiple types for property? [\#445](https://github.com/schmittjoh/serializer/issues/445)
- Allow non-qualified XML serialization when XML namespaces are part of the metadata [\#413](https://github.com/schmittjoh/serializer/issues/413)
- Discriminator field name [\#412](https://github.com/schmittjoh/serializer/issues/412)
- Serializing to and deserializing from DateTime is inconsistent [\#394](https://github.com/schmittjoh/serializer/issues/394)
- ManyToOne and OneToMany Serialization Groups [\#387](https://github.com/schmittjoh/serializer/issues/387)
- Static SubscribingHandlerInterface::getSubscribingMethod [\#380](https://github.com/schmittjoh/serializer/issues/380)
- User defined ordering function [\#379](https://github.com/schmittjoh/serializer/issues/379)
- serialized\_name for discriminator [\#372](https://github.com/schmittjoh/serializer/issues/372)
- Serializing object with empty array [\#350](https://github.com/schmittjoh/serializer/issues/350)
- VirtualProperty\(s\) are ignored with AccessorOrder [\#349](https://github.com/schmittjoh/serializer/issues/349)
- When setting a group of serialization, the inheritance doesn't work anymore [\#328](https://github.com/schmittjoh/serializer/issues/328)
- Serialization of empty object [\#323](https://github.com/schmittjoh/serializer/issues/323)
- "Can't pop from an empty datastructure" error when multiple serializer calls [\#319](https://github.com/schmittjoh/serializer/issues/319)
- virtual\_properties cannot be excluded with groups [\#291](https://github.com/schmittjoh/serializer/issues/291)
- Integer serialized as String using VirtualProperty [\#289](https://github.com/schmittjoh/serializer/issues/289)
- SimpleObjectProxy is not implement abstract methods of Proxy class [\#287](https://github.com/schmittjoh/serializer/issues/287)
- Serializing array that have one of the element or member of an element an empty object [\#277](https://github.com/schmittjoh/serializer/issues/277)
- Serialization with groups return json object instead array [\#267](https://github.com/schmittjoh/serializer/issues/267)
- The purpose of "Force JSON output to "{}" instead of "\[\]" if it contains either no properties or all properties are null" [\#248](https://github.com/schmittjoh/serializer/issues/248)
- Json array serialisation [\#242](https://github.com/schmittjoh/serializer/issues/242)
- Ignoring "Assert" in output doc if excluded [\#241](https://github.com/schmittjoh/serializer/issues/241)
- Alphabetical accessor order doesn't respect SerializedName overrides [\#240](https://github.com/schmittjoh/serializer/issues/240)
- Request Annotation for Array Data [\#234](https://github.com/schmittjoh/serializer/issues/234)
- Allow @var instead of @Type when deserializing [\#233](https://github.com/schmittjoh/serializer/issues/233)
- Strange issue with groups exclusion strategy [\#230](https://github.com/schmittjoh/serializer/issues/230)
- Warning when deserializing removed entity [\#216](https://github.com/schmittjoh/serializer/issues/216)
- Where in the JMS code does the navigator call VisitProperty method for visitor [\#207](https://github.com/schmittjoh/serializer/issues/207)
- Property of the type array is not in alphabetic order after serialization [\#196](https://github.com/schmittjoh/serializer/issues/196)
- Magic and inconsistencies in array serialization [\#191](https://github.com/schmittjoh/serializer/issues/191)
- PreSerialization Event not handled if the value is not object [\#162](https://github.com/schmittjoh/serializer/issues/162)
- Hierarchical object serialization does not appear to inherit metadata from ancestors for metadata defined in XML [\#151](https://github.com/schmittjoh/serializer/issues/151)
- When using MaxDepth, Serialization of an array entitiy is not working [\#132](https://github.com/schmittjoh/serializer/issues/132)
- Switch to change default naming strategy [\#128](https://github.com/schmittjoh/serializer/issues/128)
- Throw exceptions on invalid input [\#112](https://github.com/schmittjoh/serializer/issues/112)
- Recursion detected error when serialization groups are in use [\#96](https://github.com/schmittjoh/serializer/issues/96)
- Allow serialization groups to be accessible within event subscriber callbacks. [\#84](https://github.com/schmittjoh/serializer/issues/84)
- Allow Constructed Object to be Passed to Deserialize [\#79](https://github.com/schmittjoh/serializer/issues/79)
- JSON recursion when first object in root list is empty [\#61](https://github.com/schmittjoh/serializer/issues/61)
- Can't serialize an array with an empty object [\#59](https://github.com/schmittjoh/serializer/issues/59)

**Merged pull requests:**

- Added runtime twig extension support \(significant performance improvements\) [\#747](https://github.com/schmittjoh/serializer/pull/747) ([goetas](https://github.com/goetas))

## [1.6.2](https://github.com/schmittjoh/serializer/tree/1.6.2) (2017-04-17)

**Fixed bugs:**

- @VirtualProperty "exp" does not play nice with @ExclusionPolicy\("ALL"\) [\#746](https://github.com/schmittjoh/serializer/issues/746)

## [1.6.1](https://github.com/schmittjoh/serializer/tree/1.6.1) (2017-04-12)

**Fixed bugs:**

- Do not output the XML node when the object will be emtpy [\#744](https://github.com/schmittjoh/serializer/pull/744) ([goetas](https://github.com/goetas))

**Closed issues:**

- XmlList not working since version 1.5.0 with xmlns attributes [\#742](https://github.com/schmittjoh/serializer/issues/742)
- DoctrineObjectConstructor: how to use it without Symfony, in a PHP project [\#741](https://github.com/schmittjoh/serializer/issues/741)
- Outdated docs site [\#733](https://github.com/schmittjoh/serializer/issues/733)
- Why do we need this check inside SerializedName constructor, if there is name? [\#558](https://github.com/schmittjoh/serializer/issues/558)
- Is it possible to deserialize Collection from Json [\#534](https://github.com/schmittjoh/serializer/issues/534)
- PhpCollection 0.4 [\#531](https://github.com/schmittjoh/serializer/issues/531)
- Possible mismatch of xml-attribute-map and $pMetadata-\>xmlAttribute in XmlDriver.php [\#422](https://github.com/schmittjoh/serializer/issues/422)
- Access level propose for Handler/DateHandler.php [\#386](https://github.com/schmittjoh/serializer/issues/386)
- Type DateTime and Timestamp \(U format\) [\#343](https://github.com/schmittjoh/serializer/issues/343)

**Merged pull requests:**

- Update PHPDocs [\#736](https://github.com/schmittjoh/serializer/pull/736) ([gnat42](https://github.com/gnat42))

## [1.6.0](https://github.com/schmittjoh/serializer/tree/1.6.0) (2017-03-24)

**Implemented enhancements:**

- Add DateTimeImmutable support to DateHandler [\#543](https://github.com/schmittjoh/serializer/issues/543)

**Fixed bugs:**

- Virtual property having type overriden by doctrine metadata [\#276](https://github.com/schmittjoh/serializer/issues/276)

**Closed issues:**

- Serialize a subclass [\#735](https://github.com/schmittjoh/serializer/issues/735)
- How to handle Doctrine not found entity ? [\#731](https://github.com/schmittjoh/serializer/issues/731)
- Regression with 1.5.0 =\> Undefined offset 15 [\#715](https://github.com/schmittjoh/serializer/issues/715)
- detect serialisation without groups set [\#546](https://github.com/schmittjoh/serializer/issues/546)
- Introducing the NormalizerInterface [\#537](https://github.com/schmittjoh/serializer/issues/537)
- How to set JSON serialization options? [\#535](https://github.com/schmittjoh/serializer/issues/535)
- @MaxDepth doesn't seem to be working [\#522](https://github.com/schmittjoh/serializer/issues/522)
- max\_depth in YML config is ignored [\#498](https://github.com/schmittjoh/serializer/issues/498)
- Dynamic property type  annotation [\#436](https://github.com/schmittjoh/serializer/issues/436)
- How to deserialize JSON if property might have a list of subobjects? [\#355](https://github.com/schmittjoh/serializer/issues/355)
- Object to array normalization [\#354](https://github.com/schmittjoh/serializer/issues/354)
- Serialize Doctrine object without references [\#353](https://github.com/schmittjoh/serializer/issues/353)
- Post\_serialize doesn't serialize relation! [\#236](https://github.com/schmittjoh/serializer/issues/236)
- parsing string to date [\#217](https://github.com/schmittjoh/serializer/issues/217)
- Discriminator is not exposed when using a group exclusion strategy [\#157](https://github.com/schmittjoh/serializer/issues/157)

## [1.6.0-RC1](https://github.com/schmittjoh/serializer/tree/1.6.0-RC1) (2017-03-14)

**Implemented enhancements:**

- Add symfony expression in exclusions/expositions [\#406](https://github.com/schmittjoh/serializer/issues/406)
- check that cache directory was not created before throwing exception [\#729](https://github.com/schmittjoh/serializer/pull/729) ([mente](https://github.com/mente))
- \#720 - Adding support for DateInterval deserialization [\#721](https://github.com/schmittjoh/serializer/pull/721) ([c0ntax](https://github.com/c0ntax))
- Expression language based virtual properties [\#708](https://github.com/schmittjoh/serializer/pull/708) ([goetas](https://github.com/goetas))
- Added clearing previous libxml errors [\#688](https://github.com/schmittjoh/serializer/pull/688) ([zerkms](https://github.com/zerkms))
- Xml namespaces improvements [\#644](https://github.com/schmittjoh/serializer/pull/644) ([goetas](https://github.com/goetas))

**Fixed bugs:**

- Serialize correctly empty intervals according to ISO-8601 [\#722](https://github.com/schmittjoh/serializer/pull/722) ([goetas](https://github.com/goetas))

**Closed issues:**

- Is it possible to achieve something like - shouldSerializeEmpty  [\#725](https://github.com/schmittjoh/serializer/issues/725)
- How to handle DateTime serialization with fromArray method ? [\#723](https://github.com/schmittjoh/serializer/issues/723)
- DateInterval supported for serialization but not deserialization [\#720](https://github.com/schmittjoh/serializer/issues/720)
- Deserialization of collection when wraped by aditional xml tags [\#719](https://github.com/schmittjoh/serializer/issues/719)
- SerializedName based on a property value [\#716](https://github.com/schmittjoh/serializer/issues/716)
- Blank XML breaks XmlDeserializationVisitor error handling [\#701](https://github.com/schmittjoh/serializer/issues/701)
- Problem with FOSUserBundle ROLE serialization [\#690](https://github.com/schmittjoh/serializer/issues/690)
- Doctrine cache dependency when using setCacheDir [\#676](https://github.com/schmittjoh/serializer/issues/676)
- OneToOne entities are not deserialized if passing a nested one-to-one property [\#652](https://github.com/schmittjoh/serializer/issues/652)
- \[RFC\] Serialization refacotring [\#609](https://github.com/schmittjoh/serializer/issues/609)
- Object handler callback returns array, but serialized object = null [\#594](https://github.com/schmittjoh/serializer/issues/594)
- Cannot add @Discriminator field into specific @Group [\#557](https://github.com/schmittjoh/serializer/issues/557)
- Object check on SerializationContext::isVisiting\(\) [\#502](https://github.com/schmittjoh/serializer/issues/502)
-  Define cdata and namespace for @XmlList elements [\#480](https://github.com/schmittjoh/serializer/issues/480)
- Serializer working with parent class [\#376](https://github.com/schmittjoh/serializer/issues/376)
- Add support for array format [\#374](https://github.com/schmittjoh/serializer/issues/374)
- Obtain VirtualProperty value using a service [\#359](https://github.com/schmittjoh/serializer/issues/359)
- make deserialisation of non existing id's configurable [\#333](https://github.com/schmittjoh/serializer/issues/333)
- HHVM compatibility issue with undefined property JMS\Serializer\Metadata\ClassMetadata::$inline  [\#312](https://github.com/schmittjoh/serializer/issues/312)
- resources serialization [\#275](https://github.com/schmittjoh/serializer/issues/275)
- I'm receiving "Class ArrayCollection does not exist" when serializing \(temporarily solved with a workaround\) [\#274](https://github.com/schmittjoh/serializer/issues/274)
- Can't use handlers on strings \(and other simple types\) [\#194](https://github.com/schmittjoh/serializer/issues/194)
- composer.json update for doctrine [\#178](https://github.com/schmittjoh/serializer/issues/178)
- Use expression for virtual properties [\#171](https://github.com/schmittjoh/serializer/issues/171)
- Handle classes that implement collections \(e.g. ArrayObject\) and properties [\#137](https://github.com/schmittjoh/serializer/issues/137)
- Check CDATA is needed [\#136](https://github.com/schmittjoh/serializer/issues/136)
- property path support [\#22](https://github.com/schmittjoh/serializer/issues/22)

**Merged pull requests:**

- Include reference to cache [\#727](https://github.com/schmittjoh/serializer/pull/727) ([hyperized](https://github.com/hyperized))
- A possible fix for the \#688 [\#689](https://github.com/schmittjoh/serializer/pull/689) ([zerkms](https://github.com/zerkms))

## [1.5.0](https://github.com/schmittjoh/serializer/tree/1.5.0) (2017-02-14)

**Fixed bugs:**

- Deserializing XMLList with Namespaces not \(always\) working as intended [\#697](https://github.com/schmittjoh/serializer/pull/697) ([goetas](https://github.com/goetas))

**Closed issues:**

- Serialized DateTime instances are not valid ISO-8601 [\#713](https://github.com/schmittjoh/serializer/issues/713)
- Impossible to use discriminator field. Why we need StaticPropertyMetadata ? [\#705](https://github.com/schmittjoh/serializer/issues/705)
- Deserializing XMLList with Namespaces not \(always\) working as intended [\#695](https://github.com/schmittjoh/serializer/issues/695)

## [1.5.0-RC1](https://github.com/schmittjoh/serializer/tree/1.5.0-RC1) (2017-01-19)

**Implemented enhancements:**

- added support for xml-attributes as discriminators [\#692](https://github.com/schmittjoh/serializer/pull/692) ([twtinteractive](https://github.com/twtinteractive))
- Prevent doctrine proxy loading for virtual types [\#684](https://github.com/schmittjoh/serializer/pull/684) ([goetas](https://github.com/goetas))
- Implemented dynamic exclusion using symfony expression language [\#673](https://github.com/schmittjoh/serializer/pull/673) ([goetas](https://github.com/goetas))
- Issue543 - Adding DateTimeImmutable support [\#635](https://github.com/schmittjoh/serializer/pull/635) ([toby-griffiths](https://github.com/toby-griffiths))

**Closed issues:**

- Groups logic [\#693](https://github.com/schmittjoh/serializer/issues/693)
- BC from 1.1.\* to ^1.2 [\#643](https://github.com/schmittjoh/serializer/issues/643)
- DoctrineProxySubscriber forces loading of the proxy even if custom handler exist [\#575](https://github.com/schmittjoh/serializer/issues/575)
- ConditionalExpose/Exclude annotation [\#540](https://github.com/schmittjoh/serializer/issues/540)
- Deprecated usage of ValidatorInterface [\#438](https://github.com/schmittjoh/serializer/issues/438)
- Missing addData in XmlSerializerVisitor makes it impossible to add data in serializer.post\_serialize event [\#235](https://github.com/schmittjoh/serializer/issues/235)
- Support JSON PATCH for updating object graph [\#231](https://github.com/schmittjoh/serializer/issues/231)
- Dynamic expose, aka 'fields' query param [\#195](https://github.com/schmittjoh/serializer/issues/195)

**Merged pull requests:**

- Added doc reference for disabling discriminator [\#699](https://github.com/schmittjoh/serializer/pull/699) ([dragosprotung](https://github.com/dragosprotung))
- Use GroupsExclusionStrategy::DEFAULT\_GROUP instead default group. [\#694](https://github.com/schmittjoh/serializer/pull/694) ([Aliance](https://github.com/Aliance))
- Improved Symfony 3.x compatibility  [\#682](https://github.com/schmittjoh/serializer/pull/682) ([goetas](https://github.com/goetas))
- Discriminator Groups [\#579](https://github.com/schmittjoh/serializer/pull/579) ([maennchen](https://github.com/maennchen))
- Add extra test for handling child elements [\#569](https://github.com/schmittjoh/serializer/pull/569) ([tarjei](https://github.com/tarjei))

## [1.4.2](https://github.com/schmittjoh/serializer/tree/1.4.2) (2016-11-13)

**Fixed bugs:**

- Warning: JMS\Serializer\XmlDeserializationVisitor::visitArray\(\): Node no longer exists [\#674](https://github.com/schmittjoh/serializer/issues/674)
- Fixed xml arrays with namespaced entry triggers error [\#675](https://github.com/schmittjoh/serializer/pull/675) ([goetas](https://github.com/goetas))

**Closed issues:**

- Max depth produces array of nulls [\#671](https://github.com/schmittjoh/serializer/issues/671)

## [1.4.1](https://github.com/schmittjoh/serializer/tree/1.4.1) (2016-11-02)

**Fixed bugs:**

- Groups context might be not initialized  [\#669](https://github.com/schmittjoh/serializer/pull/669) ([goetas](https://github.com/goetas))

**Closed issues:**

- Warning: Invalid argument supplied for foreach\(\) on getCurrentPath method [\#668](https://github.com/schmittjoh/serializer/issues/668)

## [1.4.0](https://github.com/schmittjoh/serializer/tree/1.4.0) (2016-10-31)

**Implemented enhancements:**

- Document the implied 'Default' property group when no group is specified [\#661](https://github.com/schmittjoh/serializer/pull/661) ([akoebbe](https://github.com/akoebbe))
- Allow discriminator map in the middle of the hierarchy when deserializing [\#659](https://github.com/schmittjoh/serializer/pull/659) ([goetas](https://github.com/goetas))
- Handle both int and integer [\#657](https://github.com/schmittjoh/serializer/pull/657) ([Aliance](https://github.com/Aliance))
- Can now override groups on specific paths of the graph [\#170](https://github.com/schmittjoh/serializer/pull/170) ([adrienbrault](https://github.com/adrienbrault))

**Fixed bugs:**

- Deserialization fails when discriminator base class extends another class [\#182](https://github.com/schmittjoh/serializer/issues/182)
- Xml setters ignored when deserializing [\#665](https://github.com/schmittjoh/serializer/pull/665) ([goetas](https://github.com/goetas))

**Closed issues:**

- Move `FormErrorHandler` to the bundle [\#664](https://github.com/schmittjoh/serializer/issues/664)
- Not compatible with Symfony 3's Controller::json\(\) [\#663](https://github.com/schmittjoh/serializer/issues/663)
- Class name not reflecting in serialized json [\#662](https://github.com/schmittjoh/serializer/issues/662)
- YML virtual\_properties no group exlcusion [\#656](https://github.com/schmittjoh/serializer/issues/656)
- \[RFC\] Introduce normalizer\denormalizer interface [\#646](https://github.com/schmittjoh/serializer/issues/646)
- Plain arrays are serialized \(normalized\) as "objects", ignoring serializeNull [\#641](https://github.com/schmittjoh/serializer/issues/641)
- serializer doesn't serialize traits [\#638](https://github.com/schmittjoh/serializer/issues/638)
- Add metadata informations [\#637](https://github.com/schmittjoh/serializer/issues/637)
- Unexpected results when serializing arrays containing null value elements  [\#593](https://github.com/schmittjoh/serializer/issues/593)
- Allow to set default serialization context when building serializer [\#528](https://github.com/schmittjoh/serializer/issues/528)
- Enable Sourcegraph [\#455](https://github.com/schmittjoh/serializer/issues/455)
- Use different accessor for each group [\#420](https://github.com/schmittjoh/serializer/issues/420)
- GenericSerializationVisitor and shouldSerializeNull [\#360](https://github.com/schmittjoh/serializer/issues/360)
- Specify group along with MaxDepth [\#150](https://github.com/schmittjoh/serializer/issues/150)
- Allow Post Serialize Event to overwrite existing data [\#129](https://github.com/schmittjoh/serializer/issues/129)
- Warning: array\_key\_exists\(\) expects parameter 2 to be array, string given [\#70](https://github.com/schmittjoh/serializer/issues/70)

**Merged pull requests:**

- Nullable array inconsistency [\#660](https://github.com/schmittjoh/serializer/pull/660) ([goetas](https://github.com/goetas))
- Fixed PHP 7.0.11 BC break \(or bugfix\) [\#658](https://github.com/schmittjoh/serializer/pull/658) ([goetas](https://github.com/goetas))
- Renamed replaceData to setData [\#653](https://github.com/schmittjoh/serializer/pull/653) ([goetas](https://github.com/goetas))
- add required sqlite extension for developing [\#649](https://github.com/schmittjoh/serializer/pull/649) ([scasei](https://github.com/scasei))
- Run serialization benchmarks in the build process [\#647](https://github.com/schmittjoh/serializer/pull/647) ([goetas](https://github.com/goetas))
- Alcalyn feature default serializer context [\#645](https://github.com/schmittjoh/serializer/pull/645) ([goetas](https://github.com/goetas))
- Add format output option [\#640](https://github.com/schmittjoh/serializer/pull/640) ([AyrtonRicardo](https://github.com/AyrtonRicardo))
- Remove deprecated FileCacheReader for doctrine annotations [\#634](https://github.com/schmittjoh/serializer/pull/634) ([goetas](https://github.com/goetas))
- Added tests to ensure SerializeNull policy [\#633](https://github.com/schmittjoh/serializer/pull/633) ([goetas](https://github.com/goetas))
- Revert "Default `$serializeNull` to false" [\#630](https://github.com/schmittjoh/serializer/pull/630) ([goetas](https://github.com/goetas))
- Introducing NormalizerInterface [\#592](https://github.com/schmittjoh/serializer/pull/592) ([alcalyn](https://github.com/alcalyn))
- Fix inheritance of discriminators on Doctrine entities [\#382](https://github.com/schmittjoh/serializer/pull/382) ([xoob](https://github.com/xoob))
- Allow Post Serialize Event to overwrite existing data [\#273](https://github.com/schmittjoh/serializer/pull/273) ([jockri](https://github.com/jockri))

## [1.3.1](https://github.com/schmittjoh/serializer/tree/1.3.1) (2016-08-23)

**Closed issues:**

- \[Idea\] Inline name [\#629](https://github.com/schmittjoh/serializer/issues/629)
- indexBy property doesn't work since 1.2.0 [\#618](https://github.com/schmittjoh/serializer/issues/618)
- Composer deps issue [\#494](https://github.com/schmittjoh/serializer/issues/494)
- PHP 7 compatability issue [\#478](https://github.com/schmittjoh/serializer/issues/478)
- Add new tag \(upgrade packagist\) [\#461](https://github.com/schmittjoh/serializer/issues/461)
- Custom Type Handler for String Values [\#384](https://github.com/schmittjoh/serializer/issues/384)
- serializer ignores properties added by traits [\#313](https://github.com/schmittjoh/serializer/issues/313)
- Skip an element during Xml deserialization process [\#229](https://github.com/schmittjoh/serializer/issues/229)
- Using serializer for JSON serialising [\#223](https://github.com/schmittjoh/serializer/issues/223)
- No way to serialize binary data with a custom type [\#202](https://github.com/schmittjoh/serializer/issues/202)
- Automatic mapping of properties [\#200](https://github.com/schmittjoh/serializer/issues/200)
- Maybe the serializer should also allow the legal literals {1, 0} for booleans [\#198](https://github.com/schmittjoh/serializer/issues/198)
- Customize how Booleans are serialized [\#180](https://github.com/schmittjoh/serializer/issues/180)
- Problem with deserialize related entity [\#123](https://github.com/schmittjoh/serializer/issues/123)
- serialized\_name does not work in yaml [\#118](https://github.com/schmittjoh/serializer/issues/118)

## [1.3.0](https://github.com/schmittjoh/serializer/tree/1.3.0) (2016-08-17)

**Fixed bugs:**

- Fix warning array\_key\_exists in deserialization. [\#398](https://github.com/schmittjoh/serializer/pull/398) ([leonnleite](https://github.com/leonnleite))

**Closed issues:**

- problems with xml namespaces after update [\#621](https://github.com/schmittjoh/serializer/issues/621)
- Trying to decorate a member to ArrayCollection but gets an error when deserilizing because composer didn't download the class from doctrine. [\#596](https://github.com/schmittjoh/serializer/issues/596)
- Missing doctrine/common requirement ? [\#517](https://github.com/schmittjoh/serializer/issues/517)
- PHP Fatal error: Using $this when not in object context in JMS/Serializer/Serializer.php on line 99 [\#441](https://github.com/schmittjoh/serializer/issues/441)
- custom collection handler [\#415](https://github.com/schmittjoh/serializer/issues/415)
- Exclude annotation not preventing attempt to find public methods when using AccessType [\#367](https://github.com/schmittjoh/serializer/issues/367)
- serializer.pre\_serialize event only thrown on objects/classes [\#337](https://github.com/schmittjoh/serializer/issues/337)
- Installing through composer gets "Segmentation fault" [\#308](https://github.com/schmittjoh/serializer/issues/308)
- Erroneous data format for unserializing... [\#283](https://github.com/schmittjoh/serializer/issues/283)
- DoctrineObjectConstructor should skip empty identifier field [\#193](https://github.com/schmittjoh/serializer/issues/193)

**Merged pull requests:**

- Added public `hasData` function to check if a data key already have been added. [\#625](https://github.com/schmittjoh/serializer/pull/625) ([goetas](https://github.com/goetas))
- $context is not used [\#622](https://github.com/schmittjoh/serializer/pull/622) ([olvlvl](https://github.com/olvlvl))
- Fix Doctrine PHPCR ODM 2.0 compatibility [\#605](https://github.com/schmittjoh/serializer/pull/605) ([wouterj](https://github.com/wouterj))
- Fixed type-hinting [\#586](https://github.com/schmittjoh/serializer/pull/586) ([jgendera](https://github.com/jgendera))
- Fix multiple handler callbacks in YamlDriver [\#515](https://github.com/schmittjoh/serializer/pull/515) ([mpajunen](https://github.com/mpajunen))
- Fixed minor typos [\#364](https://github.com/schmittjoh/serializer/pull/364) ([sdaoudi](https://github.com/sdaoudi))
- Default `$serializeNull` to false [\#317](https://github.com/schmittjoh/serializer/pull/317) ([steveYeah](https://github.com/steveYeah))
- Missing attribute 'xml-value' in XML Reference [\#269](https://github.com/schmittjoh/serializer/pull/269) ([holtkamp](https://github.com/holtkamp))
- Removed unnecessary use statement [\#262](https://github.com/schmittjoh/serializer/pull/262) ([dunglas](https://github.com/dunglas))

## [1.2.0](https://github.com/schmittjoh/serializer/tree/1.2.0) (2016-08-03)

**Fixed bugs:**

- Fix xml-attribute-map for the xml driver [\#595](https://github.com/schmittjoh/serializer/pull/595) ([romantomchak](https://github.com/romantomchak))
- \#367 Exclude annotation not preventing attempt to find public methods when using AccessType [\#397](https://github.com/schmittjoh/serializer/pull/397) ([Strate](https://github.com/Strate))

**Closed issues:**

- XML serialisation performance vs. SimpleXML? [\#606](https://github.com/schmittjoh/serializer/issues/606)
- Undefined Offset 21 - PropertyMetadata \(master\) [\#581](https://github.com/schmittjoh/serializer/issues/581)
- Invalid null serialization in arrays [\#571](https://github.com/schmittjoh/serializer/issues/571)
- List Polymorphic with XML Deserialization [\#568](https://github.com/schmittjoh/serializer/issues/568)
- Serialize null values as empty string [\#566](https://github.com/schmittjoh/serializer/issues/566)
- Type mismatch should throw an exception instead of coercing when deserializing JSON [\#561](https://github.com/schmittjoh/serializer/issues/561)
- Serialize to array [\#518](https://github.com/schmittjoh/serializer/issues/518)
- AnnotationDriver Exception on Missing Setter/Getter even on @Exclude'd Properties [\#516](https://github.com/schmittjoh/serializer/issues/516)
- Arrays are serialized as objects like {"0":... } when data contains empty objects [\#488](https://github.com/schmittjoh/serializer/issues/488)
- Tag new release [\#465](https://github.com/schmittjoh/serializer/issues/465)
- Forcing no scientific notation for larg number, type double [\#405](https://github.com/schmittjoh/serializer/issues/405)
- PHP \< 5.3.9 BC break [\#383](https://github.com/schmittjoh/serializer/issues/383)
- Ignoring a tag when deserializing [\#352](https://github.com/schmittjoh/serializer/issues/352)

**Merged pull requests:**

- Allow to not skip empty not inline array root node [\#611](https://github.com/schmittjoh/serializer/pull/611) ([goetas](https://github.com/goetas))
- Allow to use custom serializer with primitive type [\#610](https://github.com/schmittjoh/serializer/pull/610) ([goetas](https://github.com/goetas))
- Composer is not able to resolve a dependency [\#608](https://github.com/schmittjoh/serializer/pull/608) ([goetas](https://github.com/goetas))
- Test on Travis always high and low deps [\#584](https://github.com/schmittjoh/serializer/pull/584) ([goetas](https://github.com/goetas))
- Update Symfony validator and allow PHPUnit 7 [\#583](https://github.com/schmittjoh/serializer/pull/583) ([goetas](https://github.com/goetas))
- Fix serialize bug [\#582](https://github.com/schmittjoh/serializer/pull/582) ([goetas](https://github.com/goetas))
- HHVM compatibility [\#580](https://github.com/schmittjoh/serializer/pull/580) ([goetas](https://github.com/goetas))
- Fixed test suite on master [\#578](https://github.com/schmittjoh/serializer/pull/578) ([goetas](https://github.com/goetas))
- Fix for a broken test: a missing \(incorrectly positioned\) argument [\#577](https://github.com/schmittjoh/serializer/pull/577) ([zerkms](https://github.com/zerkms))
- Fix bug \#343 return integer when the column is datetime [\#562](https://github.com/schmittjoh/serializer/pull/562) ([Bukashk0zzz](https://github.com/Bukashk0zzz))
- \[doc\] fix AccessorOrder documentation [\#553](https://github.com/schmittjoh/serializer/pull/553) ([aledeg](https://github.com/aledeg))
- Generic way to solve setValue on a property which respects its setter [\#550](https://github.com/schmittjoh/serializer/pull/550) ([maennchen](https://github.com/maennchen))
- Added travis-ci label [\#399](https://github.com/schmittjoh/serializer/pull/399) ([spolischook](https://github.com/spolischook))
- Generate namespaced element on XmlList entries [\#301](https://github.com/schmittjoh/serializer/pull/301) ([goetas](https://github.com/goetas))

## [1.1.0](https://github.com/schmittjoh/serializer/tree/1.1.0) (2015-10-27)

**Closed issues:**

- Possible to set xsi:schemalocation? [\#505](https://github.com/schmittjoh/serializer/issues/505)
- Travis needs a renewed token to be able to set the status [\#495](https://github.com/schmittjoh/serializer/issues/495)
- Serialize a many-to-many relation [\#474](https://github.com/schmittjoh/serializer/issues/474)
- The document type "..." is not allowed [\#427](https://github.com/schmittjoh/serializer/issues/427)
- Yml serializer don't serialize empty arrays [\#183](https://github.com/schmittjoh/serializer/issues/183)

**Merged pull requests:**

- Manage empty array for serializer [\#510](https://github.com/schmittjoh/serializer/pull/510) ([Soullivaneuh](https://github.com/Soullivaneuh))
- Fix the method name for the serialization context factory [\#490](https://github.com/schmittjoh/serializer/pull/490) ([stof](https://github.com/stof))
- Switch the Twig integration to use non-deprecated APIs [\#482](https://github.com/schmittjoh/serializer/pull/482) ([stof](https://github.com/stof))
- Add PHP 7 on Travis [\#477](https://github.com/schmittjoh/serializer/pull/477) ([Soullivaneuh](https://github.com/Soullivaneuh))
- Change Proxy class used to Doctrine\Common\Persistence\Proxy [\#351](https://github.com/schmittjoh/serializer/pull/351) ([bburnichon](https://github.com/bburnichon))
- Added PHP 5.6 [\#297](https://github.com/schmittjoh/serializer/pull/297) ([Nyholm](https://github.com/Nyholm))

## [1.0.0](https://github.com/schmittjoh/serializer/tree/1.0.0) (2015-06-16)

**Closed issues:**

- Unrecognized 4 parts namespace [\#449](https://github.com/schmittjoh/serializer/issues/449)
- Groups is ignored [\#440](https://github.com/schmittjoh/serializer/issues/440)
-  Property FelDev\CoreBundle\Entity\Persona::$apellido does not exist  [\#432](https://github.com/schmittjoh/serializer/issues/432)
- Erroneous data format for unserializing [\#430](https://github.com/schmittjoh/serializer/issues/430)
- Deserialize JSON into existing Doctrine entities and empty strings are ignored [\#417](https://github.com/schmittjoh/serializer/issues/417)
- Failing to deserealize JSON string [\#402](https://github.com/schmittjoh/serializer/issues/402)
- Empty results serializing virtual\_properties [\#400](https://github.com/schmittjoh/serializer/issues/400)
- API stable 1.0.0 release in sight? [\#395](https://github.com/schmittjoh/serializer/issues/395)
- Is this project maintained still? [\#361](https://github.com/schmittjoh/serializer/issues/361)
- PreSerialize [\#339](https://github.com/schmittjoh/serializer/issues/339)
- Change default `access\_type` globally [\#336](https://github.com/schmittjoh/serializer/issues/336)
- Deserialization of XmlList does not support namespaces [\#332](https://github.com/schmittjoh/serializer/issues/332)
- Recursion groups, serializing properties in entities [\#329](https://github.com/schmittjoh/serializer/issues/329)
- The testsuite is broken [\#326](https://github.com/schmittjoh/serializer/issues/326)
- Namespaces and serialize/deserialize process [\#303](https://github.com/schmittjoh/serializer/issues/303)
- Exclusion of parent properties failing [\#282](https://github.com/schmittjoh/serializer/issues/282)
- How to deserialize correctly an array of arbitrary values ? [\#280](https://github.com/schmittjoh/serializer/issues/280)
- Try to identify getter/setter from an excluded property [\#278](https://github.com/schmittjoh/serializer/issues/278)
- Bug Entity constructor not called [\#270](https://github.com/schmittjoh/serializer/issues/270)
- Make it possible to escape special characters on serialization [\#265](https://github.com/schmittjoh/serializer/issues/265)
- doctrine annotations without namespace [\#264](https://github.com/schmittjoh/serializer/issues/264)
- php-collection constraint [\#257](https://github.com/schmittjoh/serializer/issues/257)
- \[Metadata\] PHP warning only when unittesting [\#255](https://github.com/schmittjoh/serializer/issues/255)
- Discriminator [\#220](https://github.com/schmittjoh/serializer/issues/220)

**Merged pull requests:**

- fix json output \(from \[\] to {} if empty\) of form error [\#462](https://github.com/schmittjoh/serializer/pull/462) ([jhkchan](https://github.com/jhkchan))
- Add toArray and fromArray methods to the serializer [\#435](https://github.com/schmittjoh/serializer/pull/435) ([tystr](https://github.com/tystr))
- Erroneous data format for unserializing \#430 [\#431](https://github.com/schmittjoh/serializer/pull/431) ([tmilos](https://github.com/tmilos))
- Scrutinizer Auto-Fixes [\#381](https://github.com/schmittjoh/serializer/pull/381) ([scrutinizer-auto-fixer](https://github.com/scrutinizer-auto-fixer))
- Fixing tests for bugfixed PHP versions [\#375](https://github.com/schmittjoh/serializer/pull/375) ([urakozz](https://github.com/urakozz))
- Making test running against phpunit 4.\* [\#369](https://github.com/schmittjoh/serializer/pull/369) ([joelwurtz](https://github.com/joelwurtz))
- Fixes a typo in the annotations.rst [\#363](https://github.com/schmittjoh/serializer/pull/363) ([Potherca](https://github.com/Potherca))
- \[doc\] Default group informations [\#345](https://github.com/schmittjoh/serializer/pull/345) ([emilien-puget](https://github.com/emilien-puget))
- bump branch alias to 0.17 as 0.16 is already released [\#305](https://github.com/schmittjoh/serializer/pull/305) ([lsmith77](https://github.com/lsmith77))
- Unserialization of XML booleans [\#302](https://github.com/schmittjoh/serializer/pull/302) ([goetas](https://github.com/goetas))
- Added xml\_root\_namespace on YAML reference [\#299](https://github.com/schmittjoh/serializer/pull/299) ([goetas](https://github.com/goetas))
- Fixed yml mapping file name [\#256](https://github.com/schmittjoh/serializer/pull/256) ([spolischook](https://github.com/spolischook))
- Serialization of nested polymorphic objects [\#238](https://github.com/schmittjoh/serializer/pull/238) ([DavidMikeSimon](https://github.com/DavidMikeSimon))

## [0.16.0](https://github.com/schmittjoh/serializer/tree/0.16.0) (2014-03-18)

**Closed issues:**

- best way to add root to json?  [\#250](https://github.com/schmittjoh/serializer/issues/250)
- Use Doctrine metadata [\#247](https://github.com/schmittjoh/serializer/issues/247)
- Integration Points - run-time exclusion checking [\#239](https://github.com/schmittjoh/serializer/issues/239)
- Using DoctrineTypeDriver to use Doctrine Anotations  [\#232](https://github.com/schmittjoh/serializer/issues/232)
- Virtual property documentation xml & yaml [\#100](https://github.com/schmittjoh/serializer/issues/100)

**Merged pull requests:**

- Changed some constraint to allow latest versions [\#251](https://github.com/schmittjoh/serializer/pull/251) ([stof](https://github.com/stof))
- XML root element namespace support [\#246](https://github.com/schmittjoh/serializer/pull/246) ([andreasferber](https://github.com/andreasferber))
- Added test for leading backslash in front of class name to TypeParserTest [\#245](https://github.com/schmittjoh/serializer/pull/245) ([deralex](https://github.com/deralex))
- Allow to fetch data from has\*\(\) with public\_method [\#243](https://github.com/schmittjoh/serializer/pull/243) ([jaymecd](https://github.com/jaymecd))
- Improve yaml documentacion Fix \#100 [\#221](https://github.com/schmittjoh/serializer/pull/221) ([BraisGabin](https://github.com/BraisGabin))

## [0.15.0](https://github.com/schmittjoh/serializer/tree/0.15.0) (2014-02-10)

**Closed issues:**

- Add trait support [\#228](https://github.com/schmittjoh/serializer/issues/228)
- "array" type: Not working for arrays of DateTime objects [\#199](https://github.com/schmittjoh/serializer/issues/199)
- Discriminator field filtered by exclusion strategy [\#189](https://github.com/schmittjoh/serializer/issues/189)
- DateTime within an array \(format get ignored\) [\#140](https://github.com/schmittjoh/serializer/issues/140)
- EntityNotFoundException using softDeletable [\#101](https://github.com/schmittjoh/serializer/issues/101)

**Merged pull requests:**

- Read only class [\#227](https://github.com/schmittjoh/serializer/pull/227) ([goetas](https://github.com/goetas))
- @Alex88's Serialize only form child of type Form \#117  [\#224](https://github.com/schmittjoh/serializer/pull/224) ([minayaserrano](https://github.com/minayaserrano))
- @XmlElement notation consistency [\#219](https://github.com/schmittjoh/serializer/pull/219) ([ajgarlag](https://github.com/ajgarlag))
- add $this-\>maxDepth to serialize / unserialize [\#218](https://github.com/schmittjoh/serializer/pull/218) ([rothfahl](https://github.com/rothfahl))
- xml reference updated with virtual-property example [\#215](https://github.com/schmittjoh/serializer/pull/215) ([ribeiropaulor](https://github.com/ribeiropaulor))
- Add XmlNamespace annotation documentation [\#213](https://github.com/schmittjoh/serializer/pull/213) ([jeserkin](https://github.com/jeserkin))
- Scrutinizer Auto-Fixes [\#210](https://github.com/schmittjoh/serializer/pull/210) ([scrutinizer-auto-fixer](https://github.com/scrutinizer-auto-fixer))
- Scrutinizer Auto-Fixes [\#206](https://github.com/schmittjoh/serializer/pull/206) ([scrutinizer-auto-fixer](https://github.com/scrutinizer-auto-fixer))
- Add xmlAttributeMap to serialized values [\#204](https://github.com/schmittjoh/serializer/pull/204) ([colinfrei](https://github.com/colinfrei))
- fix issue \#199: "array" type ignoring DateTime format [\#201](https://github.com/schmittjoh/serializer/pull/201) ([lukey78](https://github.com/lukey78))
- Potential fix for "recursion detected" issue [\#104](https://github.com/schmittjoh/serializer/pull/104) ([tyler-sommer](https://github.com/tyler-sommer))
- Adds XML namespaces support [\#58](https://github.com/schmittjoh/serializer/pull/58) ([ajgarlag](https://github.com/ajgarlag))

## [0.14.0](https://github.com/schmittjoh/serializer/tree/0.14.0) (2013-12-04)

**Closed issues:**

- @HandlerCallback not inherited [\#181](https://github.com/schmittjoh/serializer/issues/181)
- Conditional serialization [\#173](https://github.com/schmittjoh/serializer/issues/173)
- Deserialize XML partially [\#167](https://github.com/schmittjoh/serializer/issues/167)
- getter is not called when serializing Discriminator parent entity [\#156](https://github.com/schmittjoh/serializer/issues/156)
- Deserialize DateTime from js Date.toJSON format fail [\#145](https://github.com/schmittjoh/serializer/issues/145)
- Yaml driver for the parameter xml\_attribute\_map is broken [\#141](https://github.com/schmittjoh/serializer/issues/141)
- XmlKeyValueStore annotation does not seem to deserialize properly [\#139](https://github.com/schmittjoh/serializer/issues/139)
- Boolean conversion gone wrong [\#134](https://github.com/schmittjoh/serializer/issues/134)
- Serialize to/from array? [\#133](https://github.com/schmittjoh/serializer/issues/133)
- @XmlRoot annotation no longer working [\#131](https://github.com/schmittjoh/serializer/issues/131)
- Skip an element based on a condition in a XmlList [\#121](https://github.com/schmittjoh/serializer/issues/121)

**Merged pull requests:**

- No CData [\#187](https://github.com/schmittjoh/serializer/pull/187) ([mvrhov](https://github.com/mvrhov))
- composer is preinstalled on travis [\#185](https://github.com/schmittjoh/serializer/pull/185) ([lsmith77](https://github.com/lsmith77))
- \[WIP\] added support for PHPCR [\#184](https://github.com/schmittjoh/serializer/pull/184) ([lsmith77](https://github.com/lsmith77))
- Metadata filename convention added to yml/xml references [\#172](https://github.com/schmittjoh/serializer/pull/172) ([rodrigodiez](https://github.com/rodrigodiez))
- Fix inline bug with empty child [\#165](https://github.com/schmittjoh/serializer/pull/165) ([adrienbrault](https://github.com/adrienbrault))
- Add virtual properties yaml example [\#163](https://github.com/schmittjoh/serializer/pull/163) ([adrienbrault](https://github.com/adrienbrault))
- Allow deserialization to constructed objects [\#160](https://github.com/schmittjoh/serializer/pull/160) ([eugene-dounar](https://github.com/eugene-dounar))
- Fix DoctrineDriverTest random failures [\#155](https://github.com/schmittjoh/serializer/pull/155) ([eugene-dounar](https://github.com/eugene-dounar))
- Fix XML null DateTime deserialization [\#154](https://github.com/schmittjoh/serializer/pull/154) ([eugene-dounar](https://github.com/eugene-dounar))
- Update doctrine/orm dev dependency [\#153](https://github.com/schmittjoh/serializer/pull/153) ([eugene-dounar](https://github.com/eugene-dounar))
- composer install --dev fails [\#152](https://github.com/schmittjoh/serializer/pull/152) ([eugene-dounar](https://github.com/eugene-dounar))
- Update annotations.rst [\#146](https://github.com/schmittjoh/serializer/pull/146) ([chrisjohnson00](https://github.com/chrisjohnson00))
- Add Doctrine\ODM\PHPCR\ChildrenCollection to ArrayCollectionHandler [\#143](https://github.com/schmittjoh/serializer/pull/143) ([hacfi](https://github.com/hacfi))
- xml\_attribute\_map fix for the yaml driver [\#142](https://github.com/schmittjoh/serializer/pull/142) ([mvanmeerbeck](https://github.com/mvanmeerbeck))
- fix wrong quote in used in docs [\#130](https://github.com/schmittjoh/serializer/pull/130) ([jaapio](https://github.com/jaapio))
- Support PropelCollection serialization [\#81](https://github.com/schmittjoh/serializer/pull/81) ([zebraf1](https://github.com/zebraf1))

## [0.13.0](https://github.com/schmittjoh/serializer/tree/0.13.0) (2013-07-29)

**Closed issues:**

- Documentation on Exclusion Strategies has an error [\#122](https://github.com/schmittjoh/serializer/issues/122)
- How access to the current serializing group in a subscriber ? [\#99](https://github.com/schmittjoh/serializer/issues/99)
- DoctrineProxySubscriber not found [\#93](https://github.com/schmittjoh/serializer/issues/93)
- Namespaces at root level [\#86](https://github.com/schmittjoh/serializer/issues/86)
- Issues when requesting JSON or XML using Doctrine MongoDB ODM [\#85](https://github.com/schmittjoh/serializer/issues/85)
- addGlobalIgnoredName not working [\#78](https://github.com/schmittjoh/serializer/issues/78)
- serialize\_null configuration [\#77](https://github.com/schmittjoh/serializer/issues/77)
- Add json prefix to prevent script tag csrf attack [\#76](https://github.com/schmittjoh/serializer/issues/76)
- Add support for replacing serialization object inside events [\#74](https://github.com/schmittjoh/serializer/issues/74)
- Next stable version? [\#64](https://github.com/schmittjoh/serializer/issues/64)
- Deserialize with object refs [\#62](https://github.com/schmittjoh/serializer/issues/62)

**Merged pull requests:**

- Document the handler $context argument [\#116](https://github.com/schmittjoh/serializer/pull/116) ([adrienbrault](https://github.com/adrienbrault))
- Document the SubscribingHandlerInterface a bit [\#115](https://github.com/schmittjoh/serializer/pull/115) ([adrienbrault](https://github.com/adrienbrault))
- Add getter for the xml serialization visitor defaultRootName property [\#114](https://github.com/schmittjoh/serializer/pull/114) ([adrienbrault](https://github.com/adrienbrault))
- Add Serializer::getMetadataFactory [\#113](https://github.com/schmittjoh/serializer/pull/113) ([adrienbrault](https://github.com/adrienbrault))
- Accessor order [\#108](https://github.com/schmittjoh/serializer/pull/108) ([jaapio](https://github.com/jaapio))
- Added xmlns:xsi namespace and fixed tests [\#107](https://github.com/schmittjoh/serializer/pull/107) ([josser](https://github.com/josser))
- \[Doc\] Fixed typo in event\_system [\#106](https://github.com/schmittjoh/serializer/pull/106) ([lyrixx](https://github.com/lyrixx))
- Fix discriminator map search in ClassMetadata [\#97](https://github.com/schmittjoh/serializer/pull/97) ([xanido](https://github.com/xanido))
- Use the AnnotationReader interface in the SerializerBuilder, instead of the implemented AnnotationReader itself [\#82](https://github.com/schmittjoh/serializer/pull/82) ([HarmenM](https://github.com/HarmenM))
- Remove useless YamlSerializationVisitor::prepare method [\#75](https://github.com/schmittjoh/serializer/pull/75) ([adrienbrault](https://github.com/adrienbrault))
- Add the PRE\_DESERIALIZE event to the Events class [\#73](https://github.com/schmittjoh/serializer/pull/73) ([adrienbrault](https://github.com/adrienbrault))
- Improve serialization example [\#71](https://github.com/schmittjoh/serializer/pull/71) ([tvlooy](https://github.com/tvlooy))
- Max depth strategy [\#4](https://github.com/schmittjoh/serializer/pull/4) ([adrienbrault](https://github.com/adrienbrault))

## [0.12.0](https://github.com/schmittjoh/serializer/tree/0.12.0) (2013-03-28)

**Closed issues:**

- Serialization profile/definition builder [\#68](https://github.com/schmittjoh/serializer/issues/68)
- I want to configure the default exclution policy [\#65](https://github.com/schmittjoh/serializer/issues/65)
- Mulit type property mapping [\#56](https://github.com/schmittjoh/serializer/issues/56)
- AccessType\("public\_method"\): Setters ignored when deserializing to non-standard XML properties [\#53](https://github.com/schmittjoh/serializer/issues/53)
- Adding @Accessor with custom getter causes LogicException if Doctrine ManyToOneEntity [\#52](https://github.com/schmittjoh/serializer/issues/52)
- Handler callback's does not get passed context [\#49](https://github.com/schmittjoh/serializer/issues/49)
- PostSerialize callback causes data loss [\#46](https://github.com/schmittjoh/serializer/issues/46)
- Empty Objects get serialized as "array\(\)" [\#43](https://github.com/schmittjoh/serializer/issues/43)
- Exclusion Policies aren't properly applied when "serializeNull" is "true" [\#42](https://github.com/schmittjoh/serializer/issues/42)
- Accessor annotation ignored [\#40](https://github.com/schmittjoh/serializer/issues/40)
- Support for multiple exclusion strategies [\#39](https://github.com/schmittjoh/serializer/issues/39)
- srholt123@yahoo.com [\#35](https://github.com/schmittjoh/serializer/issues/35)
- Could you tag a stable version? [\#34](https://github.com/schmittjoh/serializer/issues/34)
- Default conversion of camelCase to underscores is counterintuitive [\#33](https://github.com/schmittjoh/serializer/issues/33)
- Define the xml root when deserializing [\#18](https://github.com/schmittjoh/serializer/issues/18)

**Merged pull requests:**

- \[Annotation\] Added the ability to set the type when using @VirtualProperty [\#69](https://github.com/schmittjoh/serializer/pull/69) ([pylebecq](https://github.com/pylebecq))
- Added documentation for the @VirtualProperty annotation [\#67](https://github.com/schmittjoh/serializer/pull/67) ([pylebecq](https://github.com/pylebecq))
- Metadata stack tests [\#57](https://github.com/schmittjoh/serializer/pull/57) ([adrienbrault](https://github.com/adrienbrault))
- Adding context to twig extension [\#55](https://github.com/schmittjoh/serializer/pull/55) ([smurfy](https://github.com/smurfy))
- Allow deserialization of polymorphic classes by class without specifying the type [\#48](https://github.com/schmittjoh/serializer/pull/48) ([gordalina](https://github.com/gordalina))
- Moves all state to dedicated context class [\#47](https://github.com/schmittjoh/serializer/pull/47) ([schmittjoh](https://github.com/schmittjoh))
- Add PropertyNamingStrategy [\#37](https://github.com/schmittjoh/serializer/pull/37) ([passkey1510](https://github.com/passkey1510))
- The NavigatorContext now holds a metadata stack [\#28](https://github.com/schmittjoh/serializer/pull/28) ([adrienbrault](https://github.com/adrienbrault))

## [0.11.0](https://github.com/schmittjoh/serializer/tree/0.11.0) (2013-01-29)

**Closed issues:**

- Hooking into metadata directly... [\#17](https://github.com/schmittjoh/serializer/issues/17)
- Serializing null values [\#14](https://github.com/schmittjoh/serializer/issues/14)
- Strange caching-error [\#13](https://github.com/schmittjoh/serializer/issues/13)
- handling of plain array [\#10](https://github.com/schmittjoh/serializer/issues/10)
- Unsupported format doesn't throw exception anymore [\#8](https://github.com/schmittjoh/serializer/issues/8)

**Merged pull requests:**

- Fix typo [\#32](https://github.com/schmittjoh/serializer/pull/32) ([inanimatt](https://github.com/inanimatt))
- Fixed the serialization of pluralized form errors [\#31](https://github.com/schmittjoh/serializer/pull/31) ([stof](https://github.com/stof))
- Extract json specific logic from GenericSerializationVisitor [\#29](https://github.com/schmittjoh/serializer/pull/29) ([adrienbrault](https://github.com/adrienbrault))
- \[Serializer\] Misc cleanup [\#27](https://github.com/schmittjoh/serializer/pull/27) ([vicb](https://github.com/vicb))
- \[Builder\] Add ability to include if metadata [\#25](https://github.com/schmittjoh/serializer/pull/25) ([vicb](https://github.com/vicb))
- Fix DateTimeZone issue when using the DateTime type [\#23](https://github.com/schmittjoh/serializer/pull/23) ([colinmorelli](https://github.com/colinmorelli))
- Wrong exception message for parsing datetime [\#21](https://github.com/schmittjoh/serializer/pull/21) ([nickelc](https://github.com/nickelc))
- Fixed typo in doc/reference/annotations.rst [\#16](https://github.com/schmittjoh/serializer/pull/16) ([iambrosi](https://github.com/iambrosi))
- Typecast when serializing primitive types [\#15](https://github.com/schmittjoh/serializer/pull/15) ([baldurrensch](https://github.com/baldurrensch))
- add check and helpful exception message on inconsistent type situation [\#12](https://github.com/schmittjoh/serializer/pull/12) ([dbu](https://github.com/dbu))
- Dispatch pre-serialization event before handling data to have ability change type in listener [\#7](https://github.com/schmittjoh/serializer/pull/7) ([megazoll](https://github.com/megazoll))
- Fix tests running in different environments [\#6](https://github.com/schmittjoh/serializer/pull/6) ([megazoll](https://github.com/megazoll))
- Add DateInterval serialization to DateHandler formerly DateTimeHandler [\#5](https://github.com/schmittjoh/serializer/pull/5) ([rpg600](https://github.com/rpg600))
- WIP Navigator context [\#3](https://github.com/schmittjoh/serializer/pull/3) ([adrienbrault](https://github.com/adrienbrault))
- Update src/JMS/Serializer/Construction/DoctrineObjectConstructor.php [\#2](https://github.com/schmittjoh/serializer/pull/2) ([robocoder](https://github.com/robocoder))
- Filter out non-identifiers from $data before calling find\(\) [\#1](https://github.com/schmittjoh/serializer/pull/1) ([robocoder](https://github.com/robocoder))



\* *This Change Log was automatically generated by [github_changelog_generator](https://github.com/skywinder/Github-Changelog-Generator)*
serializer/LICENSE000064400000002047147361032420007727 0ustar00Copyright (c) 2018 Johannes M. Schmitt

Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do
so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
serializer/.github/CONTRIBUTING.md000064400000004644147361032420012520 0ustar00# CONTRIBUTING

First of all, **thank you** for contributing, **you are awesome**!

Before we can merge your Pull-Request here are some guidelines that you need to follow. 
These guidelines exist not to annoy you, but to keep the code base clean, unified and future proof.

Thank you for contributing!

## Pull Request Description 

While creating your Pull Request on GitHub, you must write a description
which gives the context and/or explains why you are creating it.

## Dependencies

We're using [`composer/composer`](https://github.com/composer/composer) to manage dependencies

## Coding Standard

We are using the latest [PSR](http://www.php-fig.org/psr/) recommendations.

## Unit-Tests

We're using [`phpunit/phpunit`](https://github.com/sebastianbergmann/phpunit) to run tests.

You can run the unit-tests by calling `vendor/bin/phpunit` from the root of the project.

If you are changing code, you must update or add tests for your changes.


## Travis

We automatically run your pull request through [Travis CI](http://www.travis-ci.org).
If you break the tests, we cannot merge your code,
so please make sure that your code is working before opening up a Pull-Request.

## Documentation

If you are adding a new feature, you must update the documentation.

## Issues and Bugs

To create a new issue, you can use the GitHub issue tracking system.

Please avoid creating issues for support requests,
please read carefully the project documentation, 
try more appropriate channels as forums, questions and answers platforms...

Issues considered as "support request" will be closed, 
the discussion can continue on a closed issue, maintainers will do their best to help.

## Getting merged

Please allow us time to review your pull requests.
We will give our best to review everything as fast as possible, 
but cannot always live up to our own expectations.

Please, write [commit messages that make
sense](http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html),
and [rebase your branch](http://git-scm.com/book/en/Git-Branching-Rebasing)
before submitting your Pull Request.

One may ask you to [squash your
commits](http://gitready.com/advanced/2009/02/10/squashing-commits-with-rebase.html)
too. This is used to "clean" your Pull Request before merging it (we don't want
commits such as "fix tests", "fix 2", "fix 3", etc.).

Pull requests without tests most probably will not be merged.
Documentation PRs obviously do not require tests.

serializer/.github/PULL_REQUEST_TEMPLATE.md000064400000000603147361032420014057 0ustar00| Q             | A
| ------------- | ---
| Bug fix?      | yes/no
| New feature?  | yes/no
| Doc updated   | yes/no
| BC breaks?    | yes/no <!-- don't forget updating UPGRADING.md file -->
| Deprecations? | yes/no <!-- don't forget updating UPGRADING.md file -->
| Tests pass?   | yes/no
| Fixed tickets | #... <!-- #-prefixed issue number(s), if any -->
| License       | Apache-2.0

serializer/.github/CONDUCT.md000064400000003575147361032420011712 0ustar00# Contributor Code of Conduct

As contributors and maintainers of this project, and in the interest of fostering an open and welcoming community, we 
pledge to respect all people who contribute through reporting issues, posting feature requests, updating documentation, 
submitting pull requests or patches, and other activities.

We are committed to making participation in this project a harassment-free experience for everyone, regardless of level 
of experience, gender, gender identity and expression, sexual orientation, disability, personal appearance, body size, 
race, ethnicity, age, religion, or nationality.

Examples of unacceptable behavior by participants include:

* The use of sexualized language or imagery
* Personal attacks
* Trolling or insulting/derogatory comments
* Public or private harassment
* Publishing other's private information, such as physical or electronic addresses, without explicit permission
* Other unethical or unprofessional conduct
* Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, 
  issues, and other contributions that are not aligned to this Code of Conduct. By adopting this Code of Conduct, 
  project maintainers commit themselves to fairly and consistently applying these principles to every aspect of 
  managing this project. Project maintainers who do not follow or enforce the Code of Conduct may be permanently 
  removed from the project team.

This code of conduct applies both within project spaces and in public spaces when an individual is representing the 
project or its community.

Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by opening an issue or contacting 
one or more of the project maintainers.

This Code of Conduct is adapted from the Contributor Covenant, version 1.2.0, available from 
http://contributor-covenant.org/version/1/2/0/
serializer/.github/ISSUE_TEMPLATE.md000064400000000732147361032420012766 0ustar00| Q                | A
| ---------------- | -----
| Bug report?      | yes/no
| Feature request? | yes/no
| BC Break report? | yes/no
| RFC?             | yes/no

<!--
- Please fill in this template according to your issue.
- For support request or how-tos, please have a look to the documentation
- Otherwise, replace this comment by the description of your issue.
-->


## Steps required to reproduce the problem

1. 
2. 
3. 

## Expected Result

* 

## Actual Result

* 
serializer/META.md000064400000000257147361032420007773 0ustar00# Generating changelog

Use: https://github.com/skywinder/Github-Changelog-Generator

```bash
github_changelog_generator --pull-requests --no-compare-link -t GITHUB-TOKEN
```
metadata/README.rst000064400000002351147361032420010016 0ustar00Metadata is a library for class/method/property metadata management in PHP
==========================================================================

Overview
--------

This library provides some commonly needed base classes for managing metadata
for classes, methods and properties. The metadata can come from many different
sources (annotations, YAML/XML/PHP configuration files).

The metadata classes are used to abstract away that source and provide a common
interface for all of them.

Usage
-----

The library provides three classes that you can extend to add your application
specific properties, and flags: ``ClassMetadata``, ``MethodMetadata``, and
``PropertyMetadata``

After you have added, your properties in sub-classes, you also need to add
``DriverInterface`` implementations which know how to populate these classes
from the different metadata sources.

Finally, you can use the ``MetadataFactory`` to retrieve the metadata::

    <?php
    
    use Metadata\MetadataFactory;
    use Metadata\Driver\DriverChain;
    
    $driver = new DriverChain(array(
        /** Annotation, YAML, XML, PHP, ... drivers */
    ));
    $factory = new MetadataFactory($driver);
    $metadata = $factory->getMetadataForClass('MyNamespace\MyObject');
    
metadata/src/Metadata/Driver/LazyLoadingDriver.php000064400000001110147361032420016163 0ustar00<?php

namespace Metadata\Driver;

use Symfony\Component\DependencyInjection\ContainerInterface;

class LazyLoadingDriver implements DriverInterface
{
    private $container;
    private $realDriverId;

    public function __construct(ContainerInterface $container, $realDriverId)
    {
        $this->container = $container;
        $this->realDriverId = $realDriverId;
    }

    /**
     * {@inheritDoc}
     */
    public function loadMetadataForClass(\ReflectionClass $class)
    {
        return $this->container->get($this->realDriverId)->loadMetadataForClass($class);
    }
}
metadata/src/Metadata/Driver/AbstractFileDriver.php000064400000002706147361032420016325 0ustar00<?php

namespace Metadata\Driver;

/**
 * Base file driver implementation.
 *
 * @author Johannes M. Schmitt <schmittjoh@gmail.com>
 */
abstract class AbstractFileDriver implements AdvancedDriverInterface
{
    /**
     * @var FileLocatorInterface|FileLocator
     */
    private $locator;

    public function __construct(FileLocatorInterface $locator)
    {
        $this->locator = $locator;
    }

    public function loadMetadataForClass(\ReflectionClass $class)
    {
        if (null === $path = $this->locator->findFileForClass($class, $this->getExtension())) {
            return null;
        }

        return $this->loadMetadataFromFile($class, $path);
    }

    /**
     * {@inheritDoc}
     */
    public function getAllClassNames()
    {
        if (!$this->locator instanceof AdvancedFileLocatorInterface) {
            throw new \RuntimeException('Locator "%s" must be an instance of "AdvancedFileLocatorInterface".');
        }

        return $this->locator->findAllClasses($this->getExtension());
    }

    /**
     * Parses the content of the file, and converts it to the desired metadata.
     *
     * @param \ReflectionClass $class
     * @param string           $file
     *
     * @return \Metadata\ClassMetadata|null
     */
    abstract protected function loadMetadataFromFile(\ReflectionClass $class, $file);

    /**
     * Returns the extension of the file.
     *
     * @return string
     */
    abstract protected function getExtension();
}
metadata/src/Metadata/Driver/DriverChain.php000064400000002555147361032420015006 0ustar00<?php

namespace Metadata\Driver;

final class DriverChain implements AdvancedDriverInterface
{
    private $drivers;

    public function __construct(array $drivers = array())
    {
        $this->drivers = $drivers;
    }
    
    public function addDriver(DriverInterface $driver)
    {
        $this->drivers[] = $driver;
    }

    public function loadMetadataForClass(\ReflectionClass $class)
    {
        foreach ($this->drivers as $driver) {
            if (null !== $metadata = $driver->loadMetadataForClass($class)) {
                return $metadata;
            }
        }

        return null;
    }

    /**
     * {@inheritDoc}
     */
    public function getAllClassNames()
    {
        $classes = array();
        foreach ($this->drivers as $driver) {
            if (!$driver instanceof AdvancedDriverInterface) {
                throw new \RuntimeException(
                    sprintf(
                        'Driver "%s" must be an instance of "AdvancedDriverInterface" to use '.
                        '"DriverChain::getAllClassNames()".',
                        get_class($driver)
                    )
                );
            }
            $driverClasses = $driver->getAllClassNames();
            if (!empty($driverClasses)) {
                $classes = array_merge($classes, $driverClasses);
            }
        }

        return $classes;
    }
}
metadata/src/Metadata/Driver/FileLocatorInterface.php000064400000000423147361032420016624 0ustar00<?php

namespace Metadata\Driver;

interface FileLocatorInterface
{
    /**
     * @param \ReflectionClass $class
     * @param string           $extension
     *
     * @return string|null
     */
    public function findFileForClass(\ReflectionClass $class, $extension);
}
metadata/src/Metadata/Driver/AdvancedDriverInterface.php000064400000000511147361032420017300 0ustar00<?php

namespace Metadata\Driver;

/**
 * Forces advanced logic to drivers.
 *
 * @author Jordan Stout <j@jrdn.org>
 */
interface AdvancedDriverInterface extends DriverInterface
{
    /**
     * Gets all the metadata class names known to this driver.
     *
     * @return array
     */
    public function getAllClassNames();
}
metadata/src/Metadata/Driver/FileLocator.php000064400000003323147361032420015005 0ustar00<?php

namespace Metadata\Driver;

class FileLocator implements AdvancedFileLocatorInterface
{
    private $dirs;

    public function __construct(array $dirs)
    {
        $this->dirs = $dirs;
    }

    public function getDirs()
    {
        return $this->dirs;
    }

    /**
     * @param \ReflectionClass $class
     * @param string           $extension
     *
     * @return string|null
     */
    public function findFileForClass(\ReflectionClass $class, $extension)
    {
        foreach ($this->dirs as $prefix => $dir) {
            if ('' !== $prefix && 0 !== strpos($class->getNamespaceName(), $prefix)) {
                continue;
            }

            $len = '' === $prefix ? 0 : strlen($prefix) + 1;
            $path = $dir.'/'.str_replace('\\', '.', substr($class->name, $len)).'.'.$extension;
            if (file_exists($path)) {
                return $path;
            }
        }

        return null;
    }

    /**
     * {@inheritDoc}
     */
    public function findAllClasses($extension)
    {
        $classes = array();
        foreach ($this->dirs as $prefix => $dir) {
            /** @var $iterator \RecursiveIteratorIterator|\SplFileInfo[] */
            $iterator = new \RecursiveIteratorIterator(
                new \RecursiveDirectoryIterator($dir),
                \RecursiveIteratorIterator::LEAVES_ONLY
            );
            $nsPrefix = $prefix !== '' ? $prefix.'\\' : '';
            foreach ($iterator as $file) {
                if (($fileName = $file->getBasename('.'.$extension)) == $file->getBasename()) {
                    continue;
                }

                $classes[] = $nsPrefix.str_replace('.', '\\', $fileName);
            }
        }

        return $classes;
    }
}
metadata/src/Metadata/Driver/DriverInterface.php000064400000000350147361032420015653 0ustar00<?php

namespace Metadata\Driver;

interface DriverInterface
{
    /**
     * @param \ReflectionClass $class
     *
     * @return \Metadata\ClassMetadata
     */
    public function loadMetadataForClass(\ReflectionClass $class);
}
metadata/src/Metadata/Driver/AdvancedFileLocatorInterface.php000064400000000564147361032420020260 0ustar00<?php

namespace Metadata\Driver;

/**
 * Forces advanced logic on a file locator.
 *
 * @author Jordan Stout <j@jrdn.org>
 */
interface AdvancedFileLocatorInterface extends FileLocatorInterface
{
    /**
     * Finds all possible metadata files.
     *
     * @param string $extension
     *
     * @return array
     */
    public function findAllClasses($extension);
}
metadata/src/Metadata/MetadataFactory.php000064400000013332147361032420014420 0ustar00<?php

namespace Metadata;

use Metadata\Driver\AdvancedDriverInterface;
use Metadata\Driver\DriverInterface;
use Metadata\Cache\CacheInterface;

class MetadataFactory implements AdvancedMetadataFactoryInterface
{
    private $driver;
    private $cache;
    private $loadedMetadata = array();
    private $loadedClassMetadata = array();
    private $hierarchyMetadataClass;
    private $includeInterfaces = false;
    private $debug;

    /**
     * @param DriverInterface $driver
     * @param string          $hierarchyMetadataClass
     * @param boolean         $debug
     */
    public function __construct(DriverInterface $driver, $hierarchyMetadataClass = 'Metadata\ClassHierarchyMetadata', $debug = false)
    {
        $this->driver = $driver;
        $this->hierarchyMetadataClass = $hierarchyMetadataClass;
        $this->debug = (Boolean) $debug;
    }

    /**
     * @param boolean $include
     */
    public function setIncludeInterfaces($include)
    {
        $this->includeInterfaces = (Boolean) $include;
    }

    public function setCache(CacheInterface $cache)
    {
        $this->cache = $cache;
    }

    /**
     * @param string $className
     *
     * @return ClassHierarchyMetadata|MergeableClassMetadata|null
     */
    public function getMetadataForClass($className)
    {
        if (isset($this->loadedMetadata[$className])) {
            return $this->filterNullMetadata($this->loadedMetadata[$className]);
        }

        $metadata = null;
        foreach ($this->getClassHierarchy($className) as $class) {
            if (isset($this->loadedClassMetadata[$name = $class->getName()])) {
                if (null !== $classMetadata = $this->filterNullMetadata($this->loadedClassMetadata[$name])) {
                    $this->addClassMetadata($metadata, $classMetadata);
                }
                continue;
            }

            // check the cache
            if (null !== $this->cache) {
                if (($classMetadata = $this->cache->loadClassMetadataFromCache($class)) instanceof NullMetadata) {
                    $this->loadedClassMetadata[$name] = $classMetadata;
                    continue;
                }

                if (null !== $classMetadata) {
                    if ( ! $classMetadata instanceof ClassMetadata) {
                        throw new \LogicException(sprintf('The cache must return instances of ClassMetadata, but got %s.', var_export($classMetadata, true)));
                    }

                    if ($this->debug && !$classMetadata->isFresh()) {
                        $this->cache->evictClassMetadataFromCache($classMetadata->reflection);
                    } else {
                        $this->loadedClassMetadata[$name] = $classMetadata;
                        $this->addClassMetadata($metadata, $classMetadata);
                        continue;
                    }
                }
            }

            // load from source
            if (null !== $classMetadata = $this->driver->loadMetadataForClass($class)) {
                $this->loadedClassMetadata[$name] = $classMetadata;
                $this->addClassMetadata($metadata, $classMetadata);

                if (null !== $this->cache) {
                    $this->cache->putClassMetadataInCache($classMetadata);
                }

                continue;
            }

            if (null !== $this->cache && !$this->debug) {
                $this->cache->putClassMetadataInCache(new NullMetadata($class->getName()));
            }
        }

        if (null === $metadata) {
            $metadata = new NullMetadata($className);
        }

        return $this->filterNullMetadata($this->loadedMetadata[$className] = $metadata);
    }

    /**
     * {@inheritDoc}
     */
    public function getAllClassNames()
    {
        if (!$this->driver instanceof AdvancedDriverInterface) {
            throw new \RuntimeException(
                sprintf('Driver "%s" must be an instance of "AdvancedDriverInterface".', get_class($this->driver))
            );
        }

        return $this->driver->getAllClassNames();
    }

    /**
     * @param ClassMetadata|null $metadata
     * @param ClassMetadata      $toAdd
     */
    private function addClassMetadata(&$metadata, $toAdd)
    {
        if ($toAdd instanceof MergeableInterface) {
            if (null === $metadata) {
                $metadata = clone $toAdd;
            } else {
                $metadata->merge($toAdd);
            }
        } else {
            if (null === $metadata) {
                $metadata = new $this->hierarchyMetadataClass;
            }

            $metadata->addClassMetadata($toAdd);
        }
    }

    /**
     * @param string $class
     */
    private function getClassHierarchy($class)
    {
        $classes = array();
        $refl = new \ReflectionClass($class);

        do {
            $classes[] = $refl;
            $refl = $refl->getParentClass();
        } while (false !== $refl);

        $classes = array_reverse($classes, false);

        if (!$this->includeInterfaces) {
            return $classes;
        }

        $addedInterfaces = array();
        $newHierarchy = array();

        foreach ($classes as $class) {
            foreach ($class->getInterfaces() as $interface) {
                if (isset($addedInterfaces[$interface->getName()])) {
                    continue;
                }
                $addedInterfaces[$interface->getName()] = true;

                $newHierarchy[] = $interface;
            }

            $newHierarchy[] = $class;
        }

        return $newHierarchy;
    }

    /**
     * @param NullMetadata|null $metadata
     *
     * @return ClassMetadata|null
     */
    private function filterNullMetadata($metadata = null)
    {
        return !$metadata instanceof NullMetadata ? $metadata : null;
    }
}
metadata/src/Metadata/Version.php000064400000000123147361032420012767 0ustar00<?php

namespace Metadata;

final class Version
{
    const VERSION = '1.6-DEV';
}
metadata/src/Metadata/AdvancedMetadataFactoryInterface.php000064400000000720147361032420017664 0ustar00<?php

namespace Metadata;

/**
 * Interface for advanced Metadata Factory implementations.
 *
 * @author Johannes M. Schmitt <schmittjoh@gmail.com>
 * @author Jordan Stout <j@jrdn.org>
 */
interface AdvancedMetadataFactoryInterface extends MetadataFactoryInterface
{
    /**
     * Gets all the possible classes.
     *
     * @throws \RuntimeException if driver does not an advanced driver.
     * @return array
     */
    public function getAllClassNames();
}
metadata/src/Metadata/MetadataFactoryInterface.php000064400000001323147361032420016236 0ustar00<?php

namespace Metadata;

/**
 * Interface for Metadata Factory implementations.
 *
 * @author Johannes M. Schmitt <schmittjoh@gmail.com>
 */
interface MetadataFactoryInterface
{
    /**
     * Returns the gathered metadata for the given class name.
     *
     * If the drivers return instances of MergeableClassMetadata, these will be
     * merged prior to returning. Otherwise, all metadata for the inheritance
     * hierarchy will be returned as ClassHierarchyMetadata unmerged.
     *
     * If no metadata is available, null is returned.
     *
     * @param string $className
     *
     * @return ClassHierarchyMetadata|MergeableClassMetadata|null
     */
    public function getMetadataForClass($className);
}
metadata/src/Metadata/MethodMetadata.php000064400000002172147361032420014231 0ustar00<?php

namespace Metadata;

/**
 * Base class for method metadata.
 *
 * This class is intended to be extended to add your application specific
 * properties, and flags.
 *
 * @author Johannes M. Schmitt <schmittjoh@gmail.com>
 */
class MethodMetadata implements \Serializable
{
    public $class;
    public $name;
    public $reflection;

    public function __construct($class, $name)
    {
        $this->class = $class;
        $this->name = $name;

        $this->reflection = new \ReflectionMethod($class, $name);
        $this->reflection->setAccessible(true);
    }

    /**
     * @param object $obj
     * @param array  $args
     *
     * @return mixed
     */
    public function invoke($obj, array $args = array())
    {
        return $this->reflection->invokeArgs($obj, $args);
    }

    public function serialize()
    {
        return serialize(array($this->class, $this->name));
    }

    public function unserialize($str)
    {
        list($this->class, $this->name) = unserialize($str);

        $this->reflection = new \ReflectionMethod($this->class, $this->name);
        $this->reflection->setAccessible(true);
    }
}
metadata/src/Metadata/Cache/CacheInterface.php000064400000001342147361032420015175 0ustar00<?php

namespace Metadata\Cache;

use Metadata\ClassMetadata;

interface CacheInterface
{
    /**
     * Loads a class metadata instance from the cache
     *
     * @param \ReflectionClass $class
     *
     * @return ClassMetadata
     */
    function loadClassMetadataFromCache(\ReflectionClass $class);

    /**
     * Puts a class metadata instance into the cache
     *
     * @param ClassMetadata $metadata
     *
     * @return void
     */
    function putClassMetadataInCache(ClassMetadata $metadata);

    /**
     * Evicts the class metadata for the given class from the cache.
     *
     * @param \ReflectionClass $class
     *
     * @return void
     */
    function evictClassMetadataFromCache(\ReflectionClass $class);
}metadata/src/Metadata/Cache/DoctrineCacheAdapter.php000064400000002203147361032420016342 0ustar00<?php

namespace Metadata\Cache;

use Doctrine\Common\Cache\Cache;
use Metadata\ClassMetadata;

/**
 * @author Henrik Bjornskov <henrik@bjrnskov.dk>
 */
class DoctrineCacheAdapter implements CacheInterface
{
    /**
     * @param string $prefix
     */
    private $prefix;

    /**
     * @var Cache $cache
     */
    private $cache;

    /**
     * @param string $prefix
     * @param Cache $cache
     */
    public function __construct($prefix, Cache $cache)
    {
        $this->prefix = $prefix;
        $this->cache = $cache;
    }

    /**
     * {@inheritDoc}
     */
    public function loadClassMetadataFromCache(\ReflectionClass $class)
    {
        $cache = $this->cache->fetch($this->prefix . $class->name);
        return false === $cache ? null : $cache;
    }

    /**
     * {@inheritDoc}
     */
    public function putClassMetadataInCache(ClassMetadata $metadata)
    {
        $this->cache->save($this->prefix . $metadata->name, $metadata);
    }

    /**
     * {@inheritDoc}
     */
    public function evictClassMetadataFromCache(\ReflectionClass $class)
    {
        $this->cache->delete($this->prefix . $class->name);
    }
}
metadata/src/Metadata/Cache/FileCache.php000064400000004574147361032420014166 0ustar00<?php

namespace Metadata\Cache;

use Metadata\ClassMetadata;

class FileCache implements CacheInterface
{
    private $dir;

    public function __construct($dir)
    {
        if (!is_dir($dir)) {
            throw new \InvalidArgumentException(sprintf('The directory "%s" does not exist.', $dir));
        }

        $this->dir = rtrim($dir, '\\/');
    }

    /**
     * {@inheritDoc}
     */
    public function loadClassMetadataFromCache(\ReflectionClass $class)
    {
        $path = $this->dir.'/'.strtr($class->name, '\\', '-').'.cache.php';
        if (!file_exists($path)) {
            return null;
        }

        return include $path;
    }

    /**
     * {@inheritDoc}
     */
    public function putClassMetadataInCache(ClassMetadata $metadata)
    {
        if (!is_writable($this->dir)) {
            throw new \InvalidArgumentException(sprintf('The directory "%s" is not writable.', $this->dir));
        }

        $path = $this->dir.'/'.strtr($metadata->name, '\\', '-').'.cache.php';

        $tmpFile = tempnam($this->dir, 'metadata-cache');
        file_put_contents($tmpFile, '<?php return unserialize('.var_export(serialize($metadata), true).');');

        // Let's not break filesystems which do not support chmod.
        @chmod($tmpFile, 0666 & ~umask());

        $this->renameFile($tmpFile, $path);
    }

    /**
     * Renames a file with fallback for windows
     *
     * @param string $source
     * @param string $target
     */
    private function renameFile($source, $target) {
        if (false === @rename($source, $target)) {
            if (defined('PHP_WINDOWS_VERSION_BUILD')) {
                if (false === copy($source, $target)) {
                    throw new \RuntimeException(sprintf('(WIN) Could not write new cache file to %s.', $target));
                }
                if (false === unlink($source)) {
                    throw new \RuntimeException(sprintf('(WIN) Could not delete temp cache file to %s.', $source));
                }
            } else {
                throw new \RuntimeException(sprintf('Could not write new cache file to %s.', $target));
            }
        }
    }

    /**
     * {@inheritDoc}
     */
    public function evictClassMetadataFromCache(\ReflectionClass $class)
    {
        $path = $this->dir.'/'.strtr($class->name, '\\', '-').'.cache.php';
        if (file_exists($path)) {
            unlink($path);
        }
    }
}
metadata/src/Metadata/Cache/PsrCacheAdapter.php000064400000002301147361032420015336 0ustar00<?php

namespace Metadata\Cache;

use Metadata\ClassMetadata;
use Psr\Cache\CacheItemPoolInterface;

class PsrCacheAdapter implements CacheInterface
{
    private $prefix;
    private $pool;
    private $lastItem;

    public function __construct($prefix, CacheItemPoolInterface $pool)
    {
        $this->prefix = $prefix;
        $this->pool = $pool;
    }

    /**
     * {@inheritDoc}
     */
    public function loadClassMetadataFromCache(\ReflectionClass $class)
    {
        $this->lastItem = $this->pool->getItem(strtr($this->prefix . $class->name, '\\', '.'));

        return $this->lastItem->get();
    }

    /**
     * {@inheritDoc}
     */
    public function putClassMetadataInCache(ClassMetadata $metadata)
    {
        $key = strtr($this->prefix . $metadata->name, '\\', '.');

        if (null === $this->lastItem || $this->lastItem->getKey() !== $key) {
            $this->lastItem = $this->pool->getItem($key);
        }

        $this->pool->save($this->lastItem->set($metadata));
    }

    /**
     * {@inheritDoc}
     */
    public function evictClassMetadataFromCache(\ReflectionClass $class)
    {
        $this->pool->deleteItem(strtr($this->prefix . $class->name, '\\', '.'));
    }
}
metadata/src/Metadata/PropertyMetadata.php000064400000002435147361032420014637 0ustar00<?php

namespace Metadata;

/**
 * Base class for property metadata.
 *
 * This class is intended to be extended to add your application specific
 * properties, and flags.
 *
 * @author Johannes M. Schmitt <schmittjoh@gmail.com>
 */
class PropertyMetadata implements \Serializable
{
    public $class;
    public $name;
    public $reflection;

    public function __construct($class, $name)
    {
        $this->class = $class;
        $this->name = $name;

        $this->reflection = new \ReflectionProperty($class, $name);
        $this->reflection->setAccessible(true);
    }

    /**
     * @param object $obj
     *
     * @return mixed
     */
    public function getValue($obj)
    {
        return $this->reflection->getValue($obj);
    }

    /**
     * @param object $obj
     * @param string $value
     */
    public function setValue($obj, $value)
    {
        $this->reflection->setValue($obj, $value);
    }

    public function serialize()
    {
        return serialize(array(
            $this->class,
            $this->name,
        ));
    }

    public function unserialize($str)
    {
        list($this->class, $this->name) = unserialize($str);

        $this->reflection = new \ReflectionProperty($this->class, $this->name);
        $this->reflection->setAccessible(true);
    }
}
metadata/src/Metadata/NullMetadata.php000064400000000306147361032420013720 0ustar00<?php

namespace Metadata;

/**
 * Represents the metadata for a class that has not metadata.
 *
 * @author Adrien Brault <adrien.brault@gmail.com>
 */
class NullMetadata extends ClassMetadata
{

}
metadata/src/Metadata/MergeableInterface.php000064400000000310147361032420015044 0ustar00<?php

namespace Metadata;

interface MergeableInterface
{
    /**
     * @param MergeableInterface $object
     *
     * @return void
     */
    public function merge(MergeableInterface $object);
}
metadata/src/Metadata/ClassHierarchyMetadata.php000064400000001427147361032420015717 0ustar00<?php

namespace Metadata;

/**
 * Represents the metadata for the entire class hierarchy.
 *
 * @author Johannes M. Schmitt <schmittjoh@gmail.com>
 */
class ClassHierarchyMetadata
{
    public $classMetadata = array();

    public function addClassMetadata(ClassMetadata $metadata)
    {
        $this->classMetadata[$metadata->name] = $metadata;
    }

    public function getRootClassMetadata()
    {
        return reset($this->classMetadata);
    }

    public function getOutsideClassMetadata()
    {
        return end($this->classMetadata);
    }

    public function isFresh($timestamp)
    {
        foreach ($this->classMetadata as $metadata) {
            if (!$metadata->isFresh($timestamp)) {
                return false;
            }
        }

        return true;
    }
}
metadata/src/Metadata/ClassMetadata.php000064400000003563147361032420014063 0ustar00<?php

namespace Metadata;

/**
 * Base class for class metadata.
 *
 * This class is intended to be extended to add your own application specific
 * properties, and flags.
 *
 * @author Johannes M. Schmitt <schmittjoh@gmail.com>
 */
class ClassMetadata implements \Serializable
{
    public $name;
    public $reflection;
    public $methodMetadata = array();
    public $propertyMetadata = array();
    public $fileResources = array();
    public $createdAt;

    public function __construct($name)
    {
        $this->name = $name;

        $this->reflection = new \ReflectionClass($name);
        $this->createdAt = time();
    }

    public function addMethodMetadata(MethodMetadata $metadata)
    {
        $this->methodMetadata[$metadata->name] = $metadata;
    }

    public function addPropertyMetadata(PropertyMetadata $metadata)
    {
        $this->propertyMetadata[$metadata->name] = $metadata;
    }

    public function isFresh($timestamp = null)
    {
        if (null === $timestamp) {
            $timestamp = $this->createdAt;
        }

        foreach ($this->fileResources as $filepath) {
            if (!file_exists($filepath)) {
                return false;
            }

            if ($timestamp < filemtime($filepath)) {
                return false;
            }
        }

        return true;
    }

    public function serialize()
    {
        return serialize(array(
            $this->name,
            $this->methodMetadata,
            $this->propertyMetadata,
            $this->fileResources,
            $this->createdAt,
        ));
    }

    public function unserialize($str)
    {
        list(
            $this->name,
            $this->methodMetadata,
            $this->propertyMetadata,
            $this->fileResources,
            $this->createdAt
        ) = unserialize($str);

        $this->reflection = new \ReflectionClass($this->name);
    }
}
metadata/src/Metadata/MergeableClassMetadata.php000064400000001505147361032420015661 0ustar00<?php

namespace Metadata;

class MergeableClassMetadata extends ClassMetadata implements MergeableInterface
{
    public function merge(MergeableInterface $object)
    {
        if (!$object instanceof MergeableClassMetadata) {
            throw new \InvalidArgumentException('$object must be an instance of MergeableClassMetadata.');
        }

        $this->name = $object->name;
        $this->reflection = $object->reflection;
        $this->methodMetadata = array_merge($this->methodMetadata, $object->methodMetadata);
        $this->propertyMetadata = array_merge($this->propertyMetadata, $object->propertyMetadata);
        $this->fileResources = array_merge($this->fileResources, $object->fileResources);

        if ($object->createdAt < $this->createdAt) {
            $this->createdAt = $object->createdAt;
        }
    }
}metadata/CHANGELOG.md000064400000002211147361032420010133 0ustar00CHANGELOG
=========

This changelog references all relevant changes:

* 1.7.0 (2018-10-26)
 * allow to run the metadata on read-only file systems
 * Change license to MIT
 * Composer improvements
 
* 1.6.0 (2016-12-05)
 * PRS cache adapter
 * other fixes
 
* 1.5.0 (2013-11-06)
 * adds ability to inject new drivers into the DriverChain after it has been constructed
 * improves performance by removing some superfluous filesystem calls
 * made MetadataFactory implementation non-final

* 1.4.1 (2013-08-26)
 * fixes a possible permission issue when using filesystem ACLs

* 1.4.0 (2013-08-25)
 * fixes a race condition when writing cache files

* 1.3.0 (2013-01-22)
 * added ability to retrieve all managed classes from the metadata factory 

* 1.2.0 (2012-08-21)
 * added a Doctrine Cache Adapter
 * better support for traits, and classes in the global namespace

* 1.1.0 (2011-10-04)

 * added support for metadata on interfaces
 * added support for non annotation-based drivers
 * added support for merging metadata

This release is fully backwards compatible with the 1.0.0 release. Therefore,
the 1.0.x branch has been discontinued.

* 1.0.0 (2011-07-09)
metadata/LICENSE000064400000002047147361032420007336 0ustar00Copyright (c) 2018 Johannes M. Schmitt

Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do
so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
parser-lib/.jms.yml000064400000000637147361032420010206 0ustar00filter:
    paths: [src/*, tests/*]
    excluded_paths: ["tests/*/Fixture/*"]

default_config:
    psr0_compliance: true
    checkstyle: true
    composer_config_check:
        publish_checks: true
        level: warning
    reflection_fixes: true
    use_statement_fixes: true

path_configs:
    tests:
        paths: [tests/*]
        psr0_compliance: false
        checkstyle: false
        phpunit_checks: true
parser-lib/src/JMS/Parser/AbstractParser.php000064400000007112147361032420014714 0ustar00<?php

/*
 * Copyright 2012 Johannes M. Schmitt <schmittjoh@gmail.com>
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

namespace JMS\Parser;

/**
 * Base Parser which provides some useful parsing methods intended for sub-classing.
 *
 * @author Johannes M. Schmitt <schmittjoh@gmail.com>
 */
abstract class AbstractParser
{
    protected $lexer;
    protected $context;

    public function __construct(AbstractLexer $lexer)
    {
        $this->lexer = $lexer;
    }

    /**
     * Parses the given input.
     *
     * @param string $str
     * @param string $context parsing context (allows to produce better error messages)
     *
     * @return mixed
     */
    public function parse($str, $context = null)
    {
        $this->lexer->setInput($str);
        $this->context = $context;

        $rs = $this->parseInternal();

        if (null !== $this->lexer->next) {
            $this->syntaxError('end of input');
        }

        return $rs;
    }

    /**
     * @return mixed
     */
    abstract protected function parseInternal();

    /**
     * Matches a token, and returns its value.
     *
     * @param integer $type
     *
     * @return mixed the value of the matched token
     */
    protected function match($type)
    {
        if ( ! $this->lexer->isNext($type)) {
            $this->syntaxError($this->lexer->getName($type));
        }

        $this->lexer->moveNext();

        return $this->lexer->token[0];
    }

    /**
     * Matches any of the passed tokens, and returns the matched token's value.
     *
     * @param array<integer> $types
     *
     * @return mixed
     */
    protected function matchAny(array $types)
    {
        if ( ! $this->lexer->isNextAny($types)) {
            $this->syntaxError('any of '.implode(' or ', array_map(array($this->lexer, 'getName'), $types)));
        }

        $this->lexer->moveNext();

        return $this->lexer->token[0];
    }

    /**
     * Raises a syntax error exception.
     *
     * @param string $expectedDesc A human understandable explanation what was expected
     * @param array $actualToken The token that was found. If not given, next token will be assumed.
     */
    protected function syntaxError($expectedDesc, $actualToken = null)
    {
        if (null === $actualToken) {
            $actualToken = $this->lexer->next;
        }
        if (null === $actualToken) {
            $actualDesc = 'end of input';
        } else if ($actualToken[1] === 0) {
            $actualDesc = sprintf('"%s" of type %s at beginning of input', $actualToken[0], $this->lexer->getName($actualToken[2]));
        } else {
            $actualDesc = sprintf('"%s" of type %s at position %d (0-based)', $actualToken[0], $this->lexer->getName($actualToken[2]), $actualToken[1]);
        }

        $ex = new SyntaxErrorException(sprintf('Expected %s, but got %s%s.', $expectedDesc, $actualDesc, $this->context ? ' '.$this->context : ''));
        if (null !== $actualToken) {
            $ex->setActualToken($actualToken);
        }
        if (null !== $this->context) {
            $ex->setContext($this->context);
        }

        throw $ex;
    }
}parser-lib/src/JMS/Parser/SyntaxErrorException.php000064400000002144147361032420016153 0ustar00<?php

/*
 * Copyright 2012 Johannes M. Schmitt <schmittjoh@gmail.com>
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

namespace JMS\Parser;

class SyntaxErrorException extends \RuntimeException
{
    private $actualToken;
    private $context;

    public function setActualToken(array $actualToken)
    {
        $this->actualToken = $actualToken;
    }

    public function setContext($context)
    {
        $this->context = $context;
    }

    public function getActualToken()
    {
        return $this->actualToken;
    }

    public function getContext()
    {
        return $this->context;
    }
}
parser-lib/src/JMS/Parser/AbstractLexer.php000064400000007746147361032420014554 0ustar00<?php

/*
 * Copyright 2012 Johannes M. Schmitt <schmittjoh@gmail.com>
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

namespace JMS\Parser;

/**
 * Abstract Lexer.
 *
 * @author Johannes M. Schmitt <schmittjoh@gmail.com>
 */
abstract class AbstractLexer
{
    public $token;
    public $next;

    private $i;
    private $peek;
    private $tokens;

    /**
     * Returns the name of the given token.
     *
     * @param integer $type
     *
     * @return string
     */
    public function getName($type)
    {
        $ref = new \ReflectionClass($this);
        foreach ($ref->getConstants() as $name => $value) {
            if ($value === $type) {
                return $name;
            }
        }

        throw new \InvalidArgumentException(sprintf('There is no token with value %s.', json_encode($type)));
    }

    public function setInput($str)
    {
        $tokens = preg_split($this->getRegex(), $str, null, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY | PREG_SPLIT_OFFSET_CAPTURE);

        $this->tokens = array();
        foreach ($tokens as $token) {
            list($token[2], $token[0]) = $this->determineTypeAndValue($token[0]);
            $this->tokens[] = $token;
        }

        $this->reset();
    }

    public function reset()
    {
        $this->i = -1;
        $this->peek = 0;
        $this->token = $this->next = null;
        $this->moveNext();
    }

    /**
     * Moves the pointer one token forward.
     *
     * @return boolean if we have not yet reached the end of the input
     */
    public function moveNext()
    {
        $this->peek = 0;
        $this->token = $this->next;
        $this->next = isset($this->tokens[++$this->i]) ? $this->tokens[$this->i] : null;

        return null !== $this->next;
    }

    /**
     * Skips the token stream until a token of the given type.
     *
     * @param integer $type
     *
     * @return boolean true if a token of the passed type was found, false otherwise.
     */
    public function skipUntil($type)
    {
        while ( ! $this->isNext($type) && $this->moveNext());

        if ( ! $this->isNext($type)) {
            throw new \RuntimeException(sprintf('Could not find the token %s.', $this->getName($type)));
        }
    }

    /**
     * @param integer $type
     *
     * @return boolean
     */
    public function isNext($type)
    {
        return null !== $this->next && $type === $this->next[2];
    }

    /**
     * @param array<integer> $types
     *
     * @return boolean
     */
    public function isNextAny(array $types)
    {
        if (null === $this->next) {
            return false;
        }

        foreach ($types as $type) {
            if ($type === $this->next[2]) {
                return true;
            }
        }

        return false;
    }

    /**
     * @return \PhpOption\Option<[string,integer,integer]>
     */
    public function peek()
    {
        if ( ! isset($this->tokens[$this->i + (++$this->peek)])) {
            return \PhpOption\None::create();
        }

        return new \PhpOption\Some($this->tokens[$this->i + $this->peek]);
    }

    /**
     * @return string
     */
    abstract protected function getRegex();

    /**
     * Determines the type of the given value.
     *
     * This method may also modify the passed value for example to cast them to
     * a different PHP type where necessary.
     *
     * @param string $value
     *
     * @return array a tupel of type and normalized value
     */
    abstract protected function determineTypeAndValue($value);
}
parser-lib/src/JMS/Parser/SimpleLexer.php000064400000003046147361032420014227 0ustar00<?php

/*
 * Copyright 2012 Johannes M. Schmitt <schmittjoh@gmail.com>
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

namespace JMS\Parser;

/**
 * The simple lexer is a fully usable lexer that does not require sub-classing.
 *
 * @author Johannes M. Schmitt <schmittjoh@gmail.com>
 */
class SimpleLexer extends AbstractLexer
{
    private $regex;
    private $callable;
    private $tokenNames;

    public function __construct($regex, array $tokenNames, $typeCallable)
    {
        $this->regex = $regex;
        $this->callable = $typeCallable;
        $this->tokenNames = $tokenNames;
    }

    public function getName($type)
    {
        if ( ! isset($this->tokenNames[$type])) {
            throw new \InvalidArgumentException(sprintf('There is no token with type %s.', json_encode($type)));
        }

        return $this->tokenNames[$type];
    }

    protected function getRegex()
    {
        return $this->regex;
    }

    protected function determineTypeAndValue($value)
    {
        return call_user_func($this->callable, $value);
    }
}parser-lib/README.md000064400000000156147361032420010067 0ustar00Parser Library
==============

Learn more about it in its [documentation](http://jmsyst.com/libs/parser-lib).
parser-lib/LICENSE000064400000026134147361032420007621 0ustar00                                 Apache License
                           Version 2.0, January 2004
                        http://www.apache.org/licenses/

   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION

   1. Definitions.

      "License" shall mean the terms and conditions for use, reproduction,
      and distribution as defined by Sections 1 through 9 of this document.

      "Licensor" shall mean the copyright owner or entity authorized by
      the copyright owner that is granting the License.

      "Legal Entity" shall mean the union of the acting entity and all
      other entities that control, are controlled by, or are under common
      control with that entity. For the purposes of this definition,
      "control" means (i) the power, direct or indirect, to cause the
      direction or management of such entity, whether by contract or
      otherwise, or (ii) ownership of fifty percent (50%) or more of the
      outstanding shares, or (iii) beneficial ownership of such entity.

      "You" (or "Your") shall mean an individual or Legal Entity
      exercising permissions granted by this License.

      "Source" form shall mean the preferred form for making modifications,
      including but not limited to software source code, documentation
      source, and configuration files.

      "Object" form shall mean any form resulting from mechanical
      transformation or translation of a Source form, including but
      not limited to compiled object code, generated documentation,
      and conversions to other media types.

      "Work" shall mean the work of authorship, whether in Source or
      Object form, made available under the License, as indicated by a
      copyright notice that is included in or attached to the work
      (an example is provided in the Appendix below).

      "Derivative Works" shall mean any work, whether in Source or Object
      form, that is based on (or derived from) the Work and for which the
      editorial revisions, annotations, elaborations, or other modifications
      represent, as a whole, an original work of authorship. For the purposes
      of this License, Derivative Works shall not include works that remain
      separable from, or merely link (or bind by name) to the interfaces of,
      the Work and Derivative Works thereof.

      "Contribution" shall mean any work of authorship, including
      the original version of the Work and any modifications or additions
      to that Work or Derivative Works thereof, that is intentionally
      submitted to Licensor for inclusion in the Work by the copyright owner
      or by an individual or Legal Entity authorized to submit on behalf of
      the copyright owner. For the purposes of this definition, "submitted"
      means any form of electronic, verbal, or written communication sent
      to the Licensor or its representatives, including but not limited to
      communication on electronic mailing lists, source code control systems,
      and issue tracking systems that are managed by, or on behalf of, the
      Licensor for the purpose of discussing and improving the Work, but
      excluding communication that is conspicuously marked or otherwise
      designated in writing by the copyright owner as "Not a Contribution."

      "Contributor" shall mean Licensor and any individual or Legal Entity
      on behalf of whom a Contribution has been received by Licensor and
      subsequently incorporated within the Work.

   2. Grant of Copyright License. Subject to the terms and conditions of
      this License, each Contributor hereby grants to You a perpetual,
      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
      copyright license to reproduce, prepare Derivative Works of,
      publicly display, publicly perform, sublicense, and distribute the
      Work and such Derivative Works in Source or Object form.

   3. Grant of Patent License. Subject to the terms and conditions of
      this License, each Contributor hereby grants to You a perpetual,
      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
      (except as stated in this section) patent license to make, have made,
      use, offer to sell, sell, import, and otherwise transfer the Work,
      where such license applies only to those patent claims licensable
      by such Contributor that are necessarily infringed by their
      Contribution(s) alone or by combination of their Contribution(s)
      with the Work to which such Contribution(s) was submitted. If You
      institute patent litigation against any entity (including a
      cross-claim or counterclaim in a lawsuit) alleging that the Work
      or a Contribution incorporated within the Work constitutes direct
      or contributory patent infringement, then any patent licenses
      granted to You under this License for that Work shall terminate
      as of the date such litigation is filed.

   4. Redistribution. You may reproduce and distribute copies of the
      Work or Derivative Works thereof in any medium, with or without
      modifications, and in Source or Object form, provided that You
      meet the following conditions:

      (a) You must give any other recipients of the Work or
          Derivative Works a copy of this License; and

      (b) You must cause any modified files to carry prominent notices
          stating that You changed the files; and

      (c) You must retain, in the Source form of any Derivative Works
          that You distribute, all copyright, patent, trademark, and
          attribution notices from the Source form of the Work,
          excluding those notices that do not pertain to any part of
          the Derivative Works; and

      (d) If the Work includes a "NOTICE" text file as part of its
          distribution, then any Derivative Works that You distribute must
          include a readable copy of the attribution notices contained
          within such NOTICE file, excluding those notices that do not
          pertain to any part of the Derivative Works, in at least one
          of the following places: within a NOTICE text file distributed
          as part of the Derivative Works; within the Source form or
          documentation, if provided along with the Derivative Works; or,
          within a display generated by the Derivative Works, if and
          wherever such third-party notices normally appear. The contents
          of the NOTICE file are for informational purposes only and
          do not modify the License. You may add Your own attribution
          notices within Derivative Works that You distribute, alongside
          or as an addendum to the NOTICE text from the Work, provided
          that such additional attribution notices cannot be construed
          as modifying the License.

      You may add Your own copyright statement to Your modifications and
      may provide additional or different license terms and conditions
      for use, reproduction, or distribution of Your modifications, or
      for any such Derivative Works as a whole, provided Your use,
      reproduction, and distribution of the Work otherwise complies with
      the conditions stated in this License.

   5. Submission of Contributions. Unless You explicitly state otherwise,
      any Contribution intentionally submitted for inclusion in the Work
      by You to the Licensor shall be under the terms and conditions of
      this License, without any additional terms or conditions.
      Notwithstanding the above, nothing herein shall supersede or modify
      the terms of any separate license agreement you may have executed
      with Licensor regarding such Contributions.

   6. Trademarks. This License does not grant permission to use the trade
      names, trademarks, service marks, or product names of the Licensor,
      except as required for reasonable and customary use in describing the
      origin of the Work and reproducing the content of the NOTICE file.

   7. Disclaimer of Warranty. Unless required by applicable law or
      agreed to in writing, Licensor provides the Work (and each
      Contributor provides its Contributions) on an "AS IS" BASIS,
      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
      implied, including, without limitation, any warranties or conditions
      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
      PARTICULAR PURPOSE. You are solely responsible for determining the
      appropriateness of using or redistributing the Work and assume any
      risks associated with Your exercise of permissions under this License.

   8. Limitation of Liability. In no event and under no legal theory,
      whether in tort (including negligence), contract, or otherwise,
      unless required by applicable law (such as deliberate and grossly
      negligent acts) or agreed to in writing, shall any Contributor be
      liable to You for damages, including any direct, indirect, special,
      incidental, or consequential damages of any character arising as a
      result of this License or out of the use or inability to use the
      Work (including but not limited to damages for loss of goodwill,
      work stoppage, computer failure or malfunction, or any and all
      other commercial damages or losses), even if such Contributor
      has been advised of the possibility of such damages.

   9. Accepting Warranty or Additional Liability. While redistributing
      the Work or Derivative Works thereof, You may choose to offer,
      and charge a fee for, acceptance of support, warranty, indemnity,
      or other liability obligations and/or rights consistent with this
      License. However, in accepting such obligations, You may act only
      on Your own behalf and on Your sole responsibility, not on behalf
      of any other Contributor, and only if You agree to indemnify,
      defend, and hold each Contributor harmless for any liability
      incurred by, or claims asserted against, such Contributor by reason
      of your accepting any such warranty or additional liability.

   END OF TERMS AND CONDITIONS

   APPENDIX: How to apply the Apache License to your work.

      To apply the Apache License to your work, attach the following
      boilerplate notice, with the fields enclosed by brackets "[]"
      replaced with your own identifying information. (Don't include
      the brackets!)  The text should be enclosed in the appropriate
      comment syntax for the file format. We also recommend that a
      file or class name and description of purpose be included on the
      same "printed page" as the copyright notice for easier
      identification within third-party archives.

   Copyright [yyyy] [name of copyright owner]

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.