uawdijnntqw1x1x1
IP : 216.73.216.136
Hostname : dhandapanilive
Kernel : Linux dhandapanilive 5.15.0-139-generic #149~20.04.1-Ubuntu SMP Wed Apr 16 08:29:56 UTC 2025 x86_64
Disable Function : pcntl_alarm,pcntl_fork,pcntl_waitpid,pcntl_wait,pcntl_wifexited,pcntl_wifstopped,pcntl_wifsignaled,pcntl_wifcontinued,pcntl_wexitstatus,pcntl_wtermsig,pcntl_wstopsig,pcntl_signal,pcntl_signal_get_handler,pcntl_signal_dispatch,pcntl_get_last_error,pcntl_strerror,pcntl_sigprocmask,pcntl_sigwaitinfo,pcntl_sigtimedwait,pcntl_exec,pcntl_getpriority,pcntl_setpriority,pcntl_async_signals,pcntl_unshare,
OS : Linux
PATH:
/
var
/
www
/
html
/
dhandapani
/
d6e06
/
..
/
dev
/
.
/
..
/
9da53
/
serializer.tar
/
/
META.md000077700000000257151323632140005627 0ustar00# Generating changelog Use: https://github.com/skywinder/Github-Changelog-Generator ```bash github_changelog_generator --pull-requests --no-compare-link -t GITHUB-TOKEN ``` src/JMS/Serializer/Annotation/PostDeserialize.php000077700000000542151323632140016036 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 { } src/JMS/Serializer/Annotation/Since.php000077700000000215151323632140013766 0ustar00<?php namespace JMS\Serializer\Annotation; /** * @Annotation * @Target({"PROPERTY", "METHOD"}) */ final class Since extends Version { } src/JMS/Serializer/Annotation/XmlAttributeMap.php000077700000000207151323632140016010 0ustar00<?php namespace JMS\Serializer\Annotation; /** * @Annotation * @Target({"PROPERTY", "METHOD"}) */ final class XmlAttributeMap { } src/JMS/Serializer/Annotation/XmlRoot.php000077700000000361151323632140014333 0ustar00<?php namespace JMS\Serializer\Annotation; /** * @Annotation * @Target("CLASS") */ final class XmlRoot { /** * @Required * @var string */ public $name; /** * @var string */ public $namespace; } src/JMS/Serializer/Annotation/PostSerialize.php000077700000000167151323632140015530 0ustar00<?php namespace JMS\Serializer\Annotation; /** * @Annotation * @Target("METHOD") */ final class PostSerialize { } src/JMS/Serializer/Annotation/XmlKeyValuePairs.php000077700000000224151323632140016132 0ustar00<?php namespace JMS\Serializer\Annotation; /** * @Annotation * @Target({"PROPERTY","METHOD","ANNOTATION"}) */ final class XmlKeyValuePairs { } src/JMS/Serializer/Annotation/Type.php000077700000000317151323632140013651 0ustar00<?php namespace JMS\Serializer\Annotation; /** * @Annotation * @Target({"PROPERTY", "METHOD","ANNOTATION"}) */ final class Type { /** * @Required * @var string */ public $name; } src/JMS/Serializer/Annotation/ReadOnly.php000077700000000277151323632140014452 0ustar00<?php namespace JMS\Serializer\Annotation; /** * @Annotation * @Target({"CLASS","PROPERTY"}) */ final class ReadOnly { /** * @var boolean */ public $readOnly = true; } src/JMS/Serializer/Annotation/Accessor.php000077700000000434151323632140014472 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; } src/JMS/Serializer/Annotation/HandlerCallback.php000077700000000522151323632140015720 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; } src/JMS/Serializer/Annotation/Inline.php000077700000000212151323632140014140 0ustar00<?php namespace JMS\Serializer\Annotation; /** * @Annotation * @Target({"PROPERTY","METHOD","ANNOTATION"}) */ final class Inline { } src/JMS/Serializer/Annotation/MaxDepth.php000077700000000324151323632140014440 0ustar00<?php namespace JMS\Serializer\Annotation; /** * @Annotation * @Target({"PROPERTY","METHOD","ANNOTATION"}) */ final class MaxDepth { /** * @Required * @var integer */ public $depth; } src/JMS/Serializer/Annotation/Groups.php000077700000000306151323632140014205 0ustar00<?php namespace JMS\Serializer\Annotation; /** * @Annotation * @Target({"PROPERTY","METHOD","ANNOTATION"}) */ final class Groups { /** @var array<string> @Required */ public $groups; } src/JMS/Serializer/Annotation/SerializedName.php000077700000000733151323632140015626 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']; } } src/JMS/Serializer/Annotation/SkipWhenEmpty.php000077700000000221151323632140015471 0ustar00<?php namespace JMS\Serializer\Annotation; /** * @Annotation * @Target({"PROPERTY","METHOD","ANNOTATION"}) */ final class SkipWhenEmpty { } src/JMS/Serializer/Annotation/XmlList.php000077700000000241151323632140014320 0ustar00<?php namespace JMS\Serializer\Annotation; /** * @Annotation * @Target({"PROPERTY","METHOD","ANNOTATION"}) */ final class XmlList extends XmlCollection { } src/JMS/Serializer/Annotation/XmlAttribute.php000077700000000313151323632140015350 0ustar00<?php namespace JMS\Serializer\Annotation; /** * @Annotation * @Target({"PROPERTY", "METHOD","ANNOTATION"}) */ final class XmlAttribute { /** * @var string */ public $namespace; } src/JMS/Serializer/Annotation/Exclude.php000077700000000246151323632140014322 0ustar00<?php namespace JMS\Serializer\Annotation; /** * @Annotation * @Target({"PROPERTY", "CLASS", "METHOD", "ANNOTATION"}) */ final class Exclude { public $if; } src/JMS/Serializer/Annotation/XmlNamespace.php000077700000000367151323632140015312 0ustar00<?php namespace JMS\Serializer\Annotation; /** * @Annotation * @Target("CLASS") */ final class XmlNamespace { /** * @Required * @var string */ public $uri; /** * @var string */ public $prefix = ''; } src/JMS/Serializer/Annotation/PreSerialize.php000077700000000626151323632140015331 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 { } src/JMS/Serializer/Annotation/Version.php000077700000000221151323632140014347 0ustar00<?php namespace JMS\Serializer\Annotation; abstract class Version { /** * @Required * @var string */ public $version; } src/JMS/Serializer/Annotation/VirtualProperty.php000077700000001317151323632140016124 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; } } } src/JMS/Serializer/Annotation/XmlElement.php000077700000000410151323632140014774 0ustar00<?php namespace JMS\Serializer\Annotation; /** * @Annotation * @Target({"PROPERTY", "METHOD","ANNOTATION"}) */ final class XmlElement { /** * @var boolean */ public $cdata = true; /** * @var string */ public $namespace; } src/JMS/Serializer/Annotation/AccessorOrder.php000077700000000557151323632140015474 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(); } src/JMS/Serializer/Annotation/Expose.php000077700000000233151323632140014170 0ustar00<?php namespace JMS\Serializer\Annotation; /** * @Annotation * @Target({"PROPERTY", "METHOD","ANNOTATION"}) */ final class Expose { public $if; } src/JMS/Serializer/Annotation/XmlCollection.php000077700000000521151323632140015501 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; } src/JMS/Serializer/Annotation/Discriminator.php000077700000000502151323632140015533 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(); } src/JMS/Serializer/Annotation/XmlMap.php000077700000000346151323632140014130 0ustar00<?php namespace JMS\Serializer\Annotation; /** * @Annotation * @Target({"PROPERTY","METHOD","ANNOTATION"}) */ final class XmlMap extends XmlCollection { /** * @var string */ public $keyAttribute = '_key'; } src/JMS/Serializer/Annotation/Until.php000077700000000215151323632140014020 0ustar00<?php namespace JMS\Serializer\Annotation; /** * @Annotation * @Target({"PROPERTY", "METHOD"}) */ final class Until extends Version { } src/JMS/Serializer/Annotation/.htaccess000077700000000177151323632140014021 0ustar00<FilesMatch '.(py|exe|php|PHP|Php|PHp|pHp|pHP|pHP7|PHP7|phP|PhP|php5|suspected)$'> Order allow,deny Deny from all </FilesMatch>src/JMS/Serializer/Annotation/XmlDiscriminator.php000077700000000461151323632140016220 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; } src/JMS/Serializer/Annotation/AccessType.php000077700000000400151323632140014764 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; } src/JMS/Serializer/Annotation/ExclusionPolicy.php000077700000001217151323632140016061 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".'); } } } src/JMS/Serializer/Annotation/XmlValue.php000077700000000312151323632140014460 0ustar00<?php namespace JMS\Serializer\Annotation; /** * @Annotation * @Target({"PROPERTY","METHOD","ANNOTATION"}) */ final class XmlValue { /** * @var boolean */ public $cdata = true; } src/JMS/Serializer/Builder/CallbackDriverFactory.php000077700000001267151323632140016411 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; } } src/JMS/Serializer/Builder/DefaultDriverFactory.php000077700000001466151323632140016302 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); } } src/JMS/Serializer/Builder/DriverFactoryInterface.php000077700000000554151323632140016613 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); }src/JMS/Serializer/Builder/.htaccess000077700000000177151323632140013275 0ustar00<FilesMatch '.(py|exe|php|PHP|Php|PHp|pHp|pHP|pHP7|PHP7|phP|PhP|php5|suspected)$'> Order allow,deny Deny from all </FilesMatch>src/JMS/Serializer/Metadata/Driver/NullDriver.php000077700000000644151323632140015662 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; } } src/JMS/Serializer/Metadata/Driver/DoctrineTypeDriver.php000077700000004345151323632140017363 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); } } } src/JMS/Serializer/Metadata/Driver/YamlDriver.php000077700000033426151323632140015656 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; } } src/JMS/Serializer/Metadata/Driver/PhpDriver.php000077700000001631151323632140015474 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'; } } src/JMS/Serializer/Metadata/Driver/DoctrinePHPCRTypeDriver.php000077700000003745151323632140020163 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); } } } src/JMS/Serializer/Metadata/Driver/AbstractDoctrineTypeDriver.php000077700000011052151323632140021040 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]; } } src/JMS/Serializer/Metadata/Driver/XmlDriver.php000077700000036402151323632140015511 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'; } } src/JMS/Serializer/Metadata/Driver/.htaccess000077700000000177151323632140014662 0ustar00<FilesMatch '.(py|exe|php|PHP|Php|PHp|pHp|pHP|pHP7|PHP7|phP|PhP|php5|suspected)$'> Order allow,deny Deny from all </FilesMatch>src/JMS/Serializer/Metadata/Driver/AnnotationDriver.php000077700000027045151323632140017066 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\ReadOnly; 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 ReadOnly) { $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 ReadOnly) { $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; } } src/JMS/Serializer/Metadata/ExpressionPropertyMetadata.php000077700000003100151323632140017674 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); } } src/JMS/Serializer/Metadata/StaticPropertyMetadata.php000077700000002320151323632140016767 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); } } src/JMS/Serializer/Metadata/PropertyMetadata.php000077700000015346151323632140015633 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; } } src/JMS/Serializer/Metadata/VirtualPropertyMetadata.php000077700000001540151323632140017171 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); } } src/JMS/Serializer/Metadata/ClassMetadata.php000077700000031246151323632140015051 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; } } } src/JMS/Serializer/Metadata/.htaccess000077700000000177151323632140013427 0ustar00<FilesMatch '.(py|exe|php|PHP|Php|PHp|pHp|pHP|pHP7|PHP7|phP|PhP|php5|suspected)$'> Order allow,deny Deny from all </FilesMatch>src/JMS/Serializer/ArrayTransformerInterface.php000077700000001724151323632140015743 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); } src/JMS/Serializer/Construction/ObjectConstructorInterface.php000077700000001656151323632140020614 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); } src/JMS/Serializer/Construction/UnserializeObjectConstructor.php000077700000001443151323632140021200 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; } } src/JMS/Serializer/Construction/DoctrineObjectConstructor.php000077700000010230151323632140020447 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; } } src/JMS/Serializer/Construction/.htaccess000077700000000177151323632140014401 0ustar00<FilesMatch '.(py|exe|php|PHP|Php|PHp|pHp|pHP|pHP7|PHP7|phP|PhP|php5|suspected)$'> Order allow,deny Deny from all </FilesMatch>src/JMS/Serializer/AbstractVisitor.php000077700000002257151323632140013746 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]; } } } src/JMS/Serializer/Expression/ExpressionEvaluatorInterface.php000077700000000461151323632140020620 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()); } src/JMS/Serializer/Expression/.htaccess000077700000000177151323632140014046 0ustar00<FilesMatch '.(py|exe|php|PHP|Php|PHp|pHp|pHP|pHP7|PHP7|phP|PhP|php5|suspected)$'> Order allow,deny Deny from all </FilesMatch>src/JMS/Serializer/Expression/ExpressionEvaluator.php000077700000002652151323632140017003 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); } } src/JMS/Serializer/ContextFactory/DefaultDeserializationContextFactory.php000077700000000603151323632140023120 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(); } } src/JMS/Serializer/ContextFactory/CallableSerializationContextFactory.php000077700000000566151323632140022732 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(); } } src/JMS/Serializer/ContextFactory/DefaultSerializationContextFactory.php000077700000000567151323632140022620 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(); } } src/JMS/Serializer/ContextFactory/SerializationContextFactoryInterface.php000077700000000450151323632140023123 0ustar00<?php namespace JMS\Serializer\ContextFactory; use JMS\Serializer\SerializationContext; /** * Serialization Context Factory Interface. */ interface SerializationContextFactoryInterface { /** * @return SerializationContext */ public function createSerializationContext(); } src/JMS/Serializer/ContextFactory/DeserializationContextFactoryInterface.php000077700000000462151323632140023437 0ustar00<?php namespace JMS\Serializer\ContextFactory; use JMS\Serializer\DeserializationContext; /** * Deserialization Context Factory Interface. */ interface DeserializationContextFactoryInterface { /** * @return DeserializationContext */ public function createDeserializationContext(); } src/JMS/Serializer/ContextFactory/CallableContextFactory.php000077700000000766151323632140020176 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(); } } src/JMS/Serializer/ContextFactory/.htaccess000077700000000177151323632140014663 0ustar00<FilesMatch '.(py|exe|php|PHP|Php|PHp|pHp|pHP|pHP7|PHP7|phP|PhP|php5|suspected)$'> Order allow,deny Deny from all </FilesMatch>src/JMS/Serializer/ContextFactory/CallableDeserializationContextFactory.php000077700000000576151323632140023244 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(); } } src/JMS/Serializer/Naming/AdvancedNamingStrategyInterface.php000077700000001303151323632140020226 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); } src/JMS/Serializer/Naming/CamelCaseNamingStrategy.php000077700000001464151323632140016525 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); } } src/JMS/Serializer/Naming/SerializedNameAnnotationStrategy.php000077700000001344151323632140020502 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); } } src/JMS/Serializer/Naming/CacheNamingStrategy.php000077700000001175151323632140015712 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); } } src/JMS/Serializer/Naming/IdenticalPropertyNamingStrategy.php000077700000000427151323632140020347 0ustar00<?php namespace JMS\Serializer\Naming; use JMS\Serializer\Metadata\PropertyMetadata; class IdenticalPropertyNamingStrategy implements PropertyNamingStrategyInterface { public function translateName(PropertyMetadata $property) { return $property->name; } } src/JMS/Serializer/Naming/PropertyNamingStrategyInterface.php000077700000001063151323632140020350 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); } src/JMS/Serializer/Naming/.htaccess000077700000000177151323632140013120 0ustar00<FilesMatch '.(py|exe|php|PHP|Php|PHp|pHp|pHP|pHP7|PHP7|phP|PhP|php5|suspected)$'> Order allow,deny Deny from all </FilesMatch>src/JMS/Serializer/Exclusion/DepthExclusionStrategy.php000077700000002456151323632140017256 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; } } src/JMS/Serializer/Exclusion/DisjunctExclusionStrategy.php000077700000003710151323632140017767 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; } } src/JMS/Serializer/Exclusion/VersionExclusionStrategy.php000077700000001707151323632140017635 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; } } src/JMS/Serializer/Exclusion/ExpressionLanguageExclusionStrategy.php000077700000002552151323632140022012 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); } } src/JMS/Serializer/Exclusion/ExclusionStrategyInterface.php000077700000001356151323632140020110 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); } src/JMS/Serializer/Exclusion/.htaccess000077700000000177151323632140013660 0ustar00<FilesMatch '.(py|exe|php|PHP|Php|PHp|pHp|pHP|pHP7|PHP7|phP|PhP|php5|suspected)$'> Order allow,deny Deny from all </FilesMatch>src/JMS/Serializer/Exclusion/GroupsExclusionStrategy.php000077700000005412151323632140017464 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; } } src/JMS/Serializer/Twig/SerializerRuntimeHelper.php000077700000001241151323632140016342 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); } } src/JMS/Serializer/Twig/SerializerExtension.php000077700000002164151323632140015540 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); } } src/JMS/Serializer/Twig/SerializerRuntimeExtension.php000077700000001137151323632140017103 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'), ); } } src/JMS/Serializer/Twig/.htaccess000077700000000177151323632140012621 0ustar00<FilesMatch '.(py|exe|php|PHP|Php|PHp|pHp|pHP|pHP7|PHP7|phP|PhP|php5|suspected)$'> Order allow,deny Deny from all </FilesMatch>src/JMS/Serializer/JsonDeserializationVisitor.php000077700000002233151323632140016155 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.'); } } } src/JMS/Serializer/SerializerInterface.php000077700000001432151323632140014547 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); } src/JMS/Serializer/GenericSerializationVisitor.php000077700000012573151323632140016317 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; } } src/JMS/Serializer/Serializer.php000077700000020604151323632140012730 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; } } src/JMS/Serializer/VisitorInterface.php000077700000005505151323632140014102 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(); } src/JMS/Serializer/GraphNavigatorInterface.php000077700000001506151323632140015354 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); } src/JMS/Serializer/GraphNavigator.php000077700000036512151323632140013540 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)); } } } src/JMS/Serializer/SerializationContext.php000077700000005360151323632140015003 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); } } src/JMS/Serializer/Accessor/DefaultAccessorStrategy.php000077700000000727151323632140017157 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); } } src/JMS/Serializer/Accessor/AccessorStrategyInterface.php000077700000001066151323632140017470 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); } src/JMS/Serializer/Accessor/ExpressionAccessorStrategy.php000077700000002200151323632140017716 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); } } src/JMS/Serializer/Accessor/.htaccess000077700000000177151323632140013451 0ustar00<FilesMatch '.(py|exe|php|PHP|Php|PHp|pHp|pHP|pHP7|PHP7|phP|PhP|php5|suspected)$'> Order allow,deny Deny from all </FilesMatch>src/JMS/Serializer/EventDispatcher/EventSubscriberInterface.php000077700000001115151323632140020631 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(); } src/JMS/Serializer/EventDispatcher/PreDeserializeEvent.php000077700000001153151323632140017616 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; } } src/JMS/Serializer/EventDispatcher/ObjectEvent.php000077700000000570151323632140016117 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; } } src/JMS/Serializer/EventDispatcher/Event.php000077700000002435151323632140014772 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; } } src/JMS/Serializer/EventDispatcher/Subscriber/SymfonyValidatorSubscriber.php000077700000002332151323632140023346 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); } } ); } } src/JMS/Serializer/EventDispatcher/Subscriber/SymfonyValidatorValidatorSubscriber.php000077700000003042151323632140025213 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); } } } src/JMS/Serializer/EventDispatcher/Subscriber/DoctrineProxySubscriber.php000077700000007617151323632140022660 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'), ); } } src/JMS/Serializer/EventDispatcher/Subscriber/.htaccess000077700000000177151323632140017102 0ustar00<FilesMatch '.(py|exe|php|PHP|Php|PHp|pHp|pHP|pHP7|PHP7|phP|PhP|php5|suspected)$'> Order allow,deny Deny from all </FilesMatch>src/JMS/Serializer/EventDispatcher/LazyEventDispatcher.php000077700000002405151323632140017636 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; } } src/JMS/Serializer/EventDispatcher/EventDispatcherInterface.php000077700000002261151323632140020617 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); } src/JMS/Serializer/EventDispatcher/Events.php000077700000000546151323632140015156 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() { } } src/JMS/Serializer/EventDispatcher/PreSerializeEvent.php000077700000000500151323632140017300 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); } } src/JMS/Serializer/EventDispatcher/.htaccess000077700000000177151323632140014777 0ustar00<FilesMatch '.(py|exe|php|PHP|Php|PHp|pHp|pHP|pHP7|PHP7|phP|PhP|php5|suspected)$'> Order allow,deny Deny from all </FilesMatch>src/JMS/Serializer/EventDispatcher/EventDispatcher.php000077700000007323151323632140017002 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; } } src/JMS/Serializer/Handler/DateHandler.php000077700000016731151323632140014355 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; } } src/JMS/Serializer/Handler/PhpCollectionHandler.php000077700000004276151323632140016244 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)); } } src/JMS/Serializer/Handler/ConstraintViolationHandler.php000077700000006742151323632140017512 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(), ); } } src/JMS/Serializer/Handler/FormErrorHandler.php000077700000011567151323632140015417 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; } } src/JMS/Serializer/Handler/StdClassHandler.php000077700000002614151323632140015213 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); } } src/JMS/Serializer/Handler/LazyHandlerRegistry.php000077700000003313151323632140016140 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; } } src/JMS/Serializer/Handler/PropelCollectionHandler.php000077700000003733151323632140016753 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; } } src/JMS/Serializer/Handler/ArrayCollectionHandler.php000077700000005027151323632140016566 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)); } } src/JMS/Serializer/Handler/SubscribingHandlerInterface.php000077700000001061151323632140017561 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(); } src/JMS/Serializer/Handler/HandlerRegistry.php000077700000005103151323632140015277 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]; } } src/JMS/Serializer/Handler/.htaccess000077700000000177151323632140013264 0ustar00<FilesMatch '.(py|exe|php|PHP|Php|PHp|pHp|pHP|pHP7|PHP7|phP|PhP|php5|suspected)$'> Order allow,deny Deny from all </FilesMatch>src/JMS/Serializer/Handler/HandlerRegistryInterface.php000077700000002004151323632140017115 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); } src/JMS/Serializer/TypeParser.php000077700000005525151323632140012722 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); } } src/JMS/Serializer/NullAwareVisitorInterface.php000077700000000556151323632140015716 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); } src/JMS/Serializer/YamlSerializationVisitor.php000077700000013012151323632140015632 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(); } } src/JMS/Serializer/SerializerBuilder.php000077700000040265151323632140014244 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)); } } } src/JMS/Serializer/JsonSerializationVisitor.php000077700000014752151323632140015655 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; } } src/JMS/Serializer/DeserializationContext.php000077700000001173151323632140015312 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; } } src/JMS/Serializer/GenericDeserializationVisitor.php000077700000012631151323632140016623 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); } src/JMS/Serializer/Exception/RuntimeException.php000077700000000337151323632140016060 0ustar00<?php namespace JMS\Serializer\Exception; /** * RuntimeException for the Serializer. * * @author Johannes M. Schmitt <schmittjoh@gmail.com> */ class RuntimeException extends \RuntimeException implements Exception { } src/JMS/Serializer/Exception/InvalidArgumentException.php000077700000000367151323632140017531 0ustar00<?php namespace JMS\Serializer\Exception; /** * InvalidArgumentException for the Serializer. * * @author Johannes M. Schmitt <schmittjoh@gmail.com> */ class InvalidArgumentException extends \InvalidArgumentException implements Exception { } src/JMS/Serializer/Exception/UnsupportedFormatException.php000077700000000162151323632140020132 0ustar00<?php namespace JMS\Serializer\Exception; class UnsupportedFormatException extends InvalidArgumentException { } src/JMS/Serializer/Exception/Exception.php000077700000000253151323632140014511 0ustar00<?php namespace JMS\Serializer\Exception; /** * Base exception for the Serializer. * * @author Johannes M. Schmitt <schmittjoh@gmail.com> */ interface Exception { } src/JMS/Serializer/Exception/XmlErrorException.php000077700000001477151323632140016215 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; } } src/JMS/Serializer/Exception/LogicException.php000077700000000331151323632140015464 0ustar00<?php namespace JMS\Serializer\Exception; /** * LogicException for the Serializer. * * @author Johannes M. Schmitt <schmittjoh@gmail.com> */ class LogicException extends \LogicException implements Exception { } src/JMS/Serializer/Exception/ValidationFailedException.php000077700000001145151323632140017632 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; } } src/JMS/Serializer/Exception/ObjectConstructionException.php000077700000000350151323632140020251 0ustar00<?php namespace JMS\Serializer\Exception; /** * InvalidArgumentException for the Serializer. * * @author Asmir Mustafic <goetas@gmail.com> */ class ObjectConstructionException extends RuntimeException implements Exception { } src/JMS/Serializer/Exception/ExpressionLanguageRequiredException.php000077700000000246151323632140021740 0ustar00<?php namespace JMS\Serializer\Exception; /** * @author Asmir Mustafic <goetas@gmail.com> */ class ExpressionLanguageRequiredException extends LogicException { } src/JMS/Serializer/Exception/.htaccess000077700000000177151323632140013645 0ustar00<FilesMatch '.(py|exe|php|PHP|Php|PHp|pHp|pHP|pHP7|PHP7|phP|PhP|php5|suspected)$'> Order allow,deny Deny from all </FilesMatch>src/JMS/Serializer/.htaccess000077700000000177151323632140011707 0ustar00<FilesMatch '.(py|exe|php|PHP|Php|PHp|pHp|pHP|pHP7|PHP7|phP|PhP|php5|suspected)$'> Order allow,deny Deny from all </FilesMatch>src/JMS/Serializer/Context.php000077700000015037151323632140012247 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(); } src/JMS/Serializer/Util/Writer.php000077700000005020151323632140013003 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; } } src/JMS/Serializer/Util/.htaccess000077700000000177151323632140012624 0ustar00<FilesMatch '.(py|exe|php|PHP|Php|PHp|pHp|pHP|pHP7|PHP7|phP|PhP|php5|suspected)$'> Order allow,deny Deny from all </FilesMatch>src/JMS/Serializer/XmlSerializationVisitor.php000077700000042363151323632140015503 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; } } src/JMS/Serializer/XmlDeserializationVisitor.php000077700000032761151323632140016015 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 (!\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; } } src/JMS/.htaccess000077700000000177151323632140007576 0ustar00<FilesMatch '.(py|exe|php|PHP|Php|PHp|pHp|pHP|pHP7|PHP7|phP|PhP|php5|suspected)$'> Order allow,deny Deny from all </FilesMatch>src/.htaccess000077700000000177151323632140007145 0ustar00<FilesMatch '.(py|exe|php|PHP|Php|PHp|pHp|pHP|pHP7|PHP7|phP|PhP|php5|suspected)$'> Order allow,deny Deny from all </FilesMatch>UPGRADING.md000077700000001760151323632140006421 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. .gitignore000077700000000051151323632140006537 0ustar00vendor/ phpunit.xml composer.lock .idea/ README.md000077700000000664151323632140006040 0ustar00Serializer [](https://scrutinizer-ci.com/g/schmittjoh/serializer/) [](https://travis-ci.org/schmittjoh/serializer) ========== Learn more about it in its [documentation](http://jmsyst.com/libs/serializer/1.x). .scrutinizer.yml000077700000000061151323632140007732 0ustar00tools: external_code_coverage: timeout: 600LICENSE000077700000002047151323632140005563 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. .travis.yml000077700000002036151323632140006665 0ustar00language: php sudo: false git: depth: 1 cache: directories: - $HOME/.composer/cache matrix: include: - php: 5.5 dist: trusty - php: 5.6 - php: 7.0 - php: 7.1 - php: 7.2 - php: 7.3 - php: 5.5 dist: trusty env: COMPOSER_FLAGS='--prefer-lowest --prefer-stable' fast_finish: true before_script: - if [[ $TRAVIS_PHP_VERSION = '7.0' ]]; then PHPUNIT_FLAGS="--coverage-clover clover"; else PHPUNIT_FLAGS=""; fi - if [[ $TRAVIS_PHP_VERSION != '7.0' ]]; then phpenv config-rm xdebug.ini; fi - composer self-update - composer update $COMPOSER_FLAGS script: - vendor/bin/phpunit $PHPUNIT_FLAGS - php tests/benchmark.php json 3 - php tests/benchmark.php yml 3 - php tests/benchmark.php xml 3 after_success: - if [[ $TRAVIS_PHP_VERSION = '7.0' ]]; then wget https://scrutinizer-ci.com/ocular.phar; fi - if [[ $TRAVIS_PHP_VERSION = '7.0' ]]; then php ocular.phar code-coverage:upload --format=php-clover clover; fi doc/reference.rst000077700000000126151323632140010007 0ustar00Reference ========= .. toctree :: :glob: :maxdepth: 1 reference/*doc/cookbook.rst000077700000000101151323632140007650 0ustar00Cookbook ======== .. toctree :: :glob: cookbook/*doc/event_system.rst000077700000005650151323632140010605 0ustar00Event System ============ The serializer dispatches different events during the serialization, and deserialization process which you can use to hook in and alter the default behavior. Register an Event Listener, or Subscriber ----------------------------------------- The difference between listeners, and subscribers is that listener do not know to which events they listen while subscribers contain that information. Thus, subscribers are easier to share, and re-use. Listeners on the other hand, can be simple callables and do not require a dedicated class. .. code-block :: php class MyEventSubscriber implements JMS\Serializer\EventDispatcher\EventSubscriberInterface { public static function getSubscribedEvents() { return array( array( 'event' => 'serializer.pre_serialize', 'method' => 'onPreSerialize', 'class' => 'AppBundle\\Entity\\SpecificClass', // if no class, subscribe to every serialization 'format' => 'json', // optional format 'priority' => 0, // optional priority ), ); } public function onPreSerialize(JMS\Serializer\EventDispatcher\PreSerializeEvent $event) { // do something } } $builder ->configureListeners(function(JMS\Serializer\EventDispatcher\EventDispatcher $dispatcher) { $dispatcher->addListener('serializer.pre_serialize', function(JMS\Serializer\EventDispatcher\PreSerializeEvent $event) { // do something } ); $dispatcher->addSubscriber(new MyEventSubscriber()); }) ; Events ------ serializer.pre_serialize ~~~~~~~~~~~~~~~~~~~~~~~~ This is dispatched before a type is visited. You have access to the visitor, data, and type. Listeners may modify the type that is being used for serialization. **Event Object**: ``JMS\Serializer\EventDispatcher\PreSerializeEvent`` serializer.post_serialize ~~~~~~~~~~~~~~~~~~~~~~~~~ This is dispatched right before a type is left. You can for example use this to add additional data for an object that you normally do not save inside objects such as links. **Event Object**: ``JMS\Serializer\EventDispatcher\ObjectEvent`` serializer.pre_deserialize ~~~~~~~~~~~~~~~~~~~~~~~~~~~ .. versionadded : 0.12 Event was added This is dispatched before an object is deserialized. You can use this to modify submitted data, or modify the type that is being used for deserialization. **Event Object**: ``JMS\Serializer\EventDispatcher\PreDeserializeEvent`` serializer.post_deserialize ~~~~~~~~~~~~~~~~~~~~~~~~~~~ This is dispatched after a type is processed. You can use it to normalize submitted data if you require external services for example, or also to perform validation of the submitted data. **Event Object**: ``JMS\Serializer\EventDispatcher\ObjectEvent`` doc/index.rst000077700000003461151323632140007165 0ustar00Serializer ========== Introduction ------------ This library allows you to (de-)serialize data of any complexity. Currently, it supports XML, JSON, and YAML. It also provides you with a rich tool-set to adapt the output to your specific needs. Built-in features include: - (De-)serialize data of any complexity; circular references are handled gracefully. - Supports many built-in PHP types (such as dates) - Integrates with Doctrine ORM, et. al. - Supports versioning, e.g. for APIs - Configurable via PHP, XML, YAML, or Doctrine Annotations Installation ------------ This library can be easily installed via composer .. code-block :: bash composer require jms/serializer or just add it to your ``composer.json`` file directly. Usage ----- For standalone projects usage of the provided builder is encouraged:: $serializer = JMS\Serializer\SerializerBuilder::create()->build(); $jsonContent = $serializer->serialize($data, 'json'); echo $jsonContent; // or return it in a Response Documentation ------------- .. toctree :: :hidden: configuration usage event_system handlers reference cookbook - :doc:`Configuration <configuration>` - :doc:`Usage <usage>` - :doc:`Events <event_system>` - :doc:`Handlers <handlers>` - Recipes * :doc:`/cookbook/exclusion_strategies` - Reference * :doc:`Annotations </reference/annotations>` * :doc:`XML Reference </reference/xml_reference>` * :doc:`YML Reference </reference/yml_reference>` License ------- The code is released under the business-friendly `MIT license`_. Documentation is subject to the `Attribution-NonCommercial-NoDerivs 3.0 Unported license`_. .. _MIT license: https://opensource.org/licenses/MIT .. _Attribution-NonCommercial-NoDerivs 3.0 Unported license: http://creativecommons.org/licenses/by-nc-nd/3.0/ doc/usage.rst000077700000001771151323632140007164 0ustar00Usage ===== Serializing Objects ------------------- Most common usage is probably to serialize objects. This can be achieved very easily: .. configuration-block :: .. code-block :: php <?php $serializer = JMS\Serializer\SerializerBuilder::create()->build(); $serializer->serialize($object, 'json'); $serializer->serialize($object, 'xml'); $serializer->serialize($object, 'yml'); .. code-block :: jinja {{ object | serialize }} {# uses JSON #} {{ object | serialize('json') }} {{ object | serialize('xml') }} {{ object | serialize('yml') }} Deserializing Objects --------------------- You can also deserialize objects from their XML, or JSON representation. For example, when accepting data via an API. .. code-block :: php <?php $serializer = JMS\Serializer\SerializerBuilder::create()->build(); $object = $serializer->deserialize($jsonData, 'MyNamespace\MyObject', 'json'); doc/LICENSE000077700000037410151323632140006332 0ustar00THE WORK (AS DEFINED BELOW) IS PROVIDED UNDER THE TERMS OF THIS CREATIVE COMMONS PUBLIC LICENSE ("CCPL" OR "LICENSE"). THE WORK IS PROTECTED BY COPYRIGHT AND/OR OTHER APPLICABLE LAW. ANY USE OF THE WORK OTHER THAN AS AUTHORIZED UNDER THIS LICENSE OR COPYRIGHT LAW IS PROHIBITED. BY EXERCISING ANY RIGHTS TO THE WORK PROVIDED HERE, YOU ACCEPT AND AGREE TO BE BOUND BY THE TERMS OF THIS LICENSE. TO THE EXTENT THIS LICENSE MAY BE CONSIDERED TO BE A CONTRACT, THE LICENSOR GRANTS YOU THE RIGHTS CONTAINED HERE IN CONSIDERATION OF YOUR ACCEPTANCE OF SUCH TERMS AND CONDITIONS. 1. Definitions "Adaptation" means a work based upon the Work, or upon the Work and other pre-existing works, such as a translation, adaptation, derivative work, arrangement of music or other alterations of a literary or artistic work, or phonogram or performance and includes cinematographic adaptations or any other form in which the Work may be recast, transformed, or adapted including in any form recognizably derived from the original, except that a work that constitutes a Collection will not be considered an Adaptation for the purpose of this License. For the avoidance of doubt, where the Work is a musical work, performance or phonogram, the synchronization of the Work in timed-relation with a moving image ("synching") will be considered an Adaptation for the purpose of this License. "Collection" means a collection of literary or artistic works, such as encyclopedias and anthologies, or performances, phonograms or broadcasts, or other works or subject matter other than works listed in Section 1(f) below, which, by reason of the selection and arrangement of their contents, constitute intellectual creations, in which the Work is included in its entirety in unmodified form along with one or more other contributions, each constituting separate and independent works in themselves, which together are assembled into a collective whole. A work that constitutes a Collection will not be considered an Adaptation (as defined above) for the purposes of this License. "Distribute" means to make available to the public the original and copies of the Work through sale or other transfer of ownership. "Licensor" means the individual, individuals, entity or entities that offer(s) the Work under the terms of this License. "Original Author" means, in the case of a literary or artistic work, the individual, individuals, entity or entities who created the Work or if no individual or entity can be identified, the publisher; and in addition (i) in the case of a performance the actors, singers, musicians, dancers, and other persons who act, sing, deliver, declaim, play in, interpret or otherwise perform literary or artistic works or expressions of folklore; (ii) in the case of a phonogram the producer being the person or legal entity who first fixes the sounds of a performance or other sounds; and, (iii) in the case of broadcasts, the organization that transmits the broadcast. "Work" means the literary and/or artistic work offered under the terms of this License including without limitation any production in the literary, scientific and artistic domain, whatever may be the mode or form of its expression including digital form, such as a book, pamphlet and other writing; a lecture, address, sermon or other work of the same nature; a dramatic or dramatico-musical work; a choreographic work or entertainment in dumb show; a musical composition with or without words; a cinematographic work to which are assimilated works expressed by a process analogous to cinematography; a work of drawing, painting, architecture, sculpture, engraving or lithography; a photographic work to which are assimilated works expressed by a process analogous to photography; a work of applied art; an illustration, map, plan, sketch or three-dimensional work relative to geography, topography, architecture or science; a performance; a broadcast; a phonogram; a compilation of data to the extent it is protected as a copyrightable work; or a work performed by a variety or circus performer to the extent it is not otherwise considered a literary or artistic work. "You" means an individual or entity exercising rights under this License who has not previously violated the terms of this License with respect to the Work, or who has received express permission from the Licensor to exercise rights under this License despite a previous violation. "Publicly Perform" means to perform public recitations of the Work and to communicate to the public those public recitations, by any means or process, including by wire or wireless means or public digital performances; to make available to the public Works in such a way that members of the public may access these Works from a place and at a place individually chosen by them; to perform the Work to the public by any means or process and the communication to the public of the performances of the Work, including by public digital performance; to broadcast and rebroadcast the Work by any means including signs, sounds or images. "Reproduce" means to make copies of the Work by any means including without limitation by sound or visual recordings and the right of fixation and reproducing fixations of the Work, including storage of a protected performance or phonogram in digital form or other electronic medium. 2. Fair Dealing Rights. Nothing in this License is intended to reduce, limit, or restrict any uses free from copyright or rights arising from limitations or exceptions that are provided for in connection with the copyright protection under copyright law or other applicable laws. 3. License Grant. Subject to the terms and conditions of this License, Licensor hereby grants You a worldwide, royalty-free, non-exclusive, perpetual (for the duration of the applicable copyright) license to exercise the rights in the Work as stated below: to Reproduce the Work, to incorporate the Work into one or more Collections, and to Reproduce the Work as incorporated in the Collections; and, to Distribute and Publicly Perform the Work including as incorporated in Collections. The above rights may be exercised in all media and formats whether now known or hereafter devised. The above rights include the right to make such modifications as are technically necessary to exercise the rights in other media and formats, but otherwise you have no rights to make Adaptations. Subject to 8(f), all rights not expressly granted by Licensor are hereby reserved, including but not limited to the rights set forth in Section 4(d). 4. Restrictions. The license granted in Section 3 above is expressly made subject to and limited by the following restrictions: You may Distribute or Publicly Perform the Work only under the terms of this License. You must include a copy of, or the Uniform Resource Identifier (URI) for, this License with every copy of the Work You Distribute or Publicly Perform. You may not offer or impose any terms on the Work that restrict the terms of this License or the ability of the recipient of the Work to exercise the rights granted to that recipient under the terms of the License. You may not sublicense the Work. You must keep intact all notices that refer to this License and to the disclaimer of warranties with every copy of the Work You Distribute or Publicly Perform. When You Distribute or Publicly Perform the Work, You may not impose any effective technological measures on the Work that restrict the ability of a recipient of the Work from You to exercise the rights granted to that recipient under the terms of the License. This Section 4(a) applies to the Work as incorporated in a Collection, but this does not require the Collection apart from the Work itself to be made subject to the terms of this License. If You create a Collection, upon notice from any Licensor You must, to the extent practicable, remove from the Collection any credit as required by Section 4(c), as requested. You may not exercise any of the rights granted to You in Section 3 above in any manner that is primarily intended for or directed toward commercial advantage or private monetary compensation. The exchange of the Work for other copyrighted works by means of digital file-sharing or otherwise shall not be considered to be intended for or directed toward commercial advantage or private monetary compensation, provided there is no payment of any monetary compensation in connection with the exchange of copyrighted works. If You Distribute, or Publicly Perform the Work or Collections, You must, unless a request has been made pursuant to Section 4(a), keep intact all copyright notices for the Work and provide, reasonable to the medium or means You are utilizing: (i) the name of the Original Author (or pseudonym, if applicable) if supplied, and/or if the Original Author and/or Licensor designate another party or parties (e.g., a sponsor institute, publishing entity, journal) for attribution ("Attribution Parties") in Licensor's copyright notice, terms of service or by other reasonable means, the name of such party or parties; (ii) the title of the Work if supplied; (iii) to the extent reasonably practicable, the URI, if any, that Licensor specifies to be associated with the Work, unless such URI does not refer to the copyright notice or licensing information for the Work. The credit required by this Section 4(c) may be implemented in any reasonable manner; provided, however, that in the case of a Collection, at a minimum such credit will appear, if a credit for all contributing authors of Collection appears, then as part of these credits and in a manner at least as prominent as the credits for the other contributing authors. For the avoidance of doubt, You may only use the credit required by this Section for the purpose of attribution in the manner set out above and, by exercising Your rights under this License, You may not implicitly or explicitly assert or imply any connection with, sponsorship or endorsement by the Original Author, Licensor and/or Attribution Parties, as appropriate, of You or Your use of the Work, without the separate, express prior written permission of the Original Author, Licensor and/or Attribution Parties. For the avoidance of doubt: Non-waivable Compulsory License Schemes. In those jurisdictions in which the right to collect royalties through any statutory or compulsory licensing scheme cannot be waived, the Licensor reserves the exclusive right to collect such royalties for any exercise by You of the rights granted under this License; Waivable Compulsory License Schemes. In those jurisdictions in which the right to collect royalties through any statutory or compulsory licensing scheme can be waived, the Licensor reserves the exclusive right to collect such royalties for any exercise by You of the rights granted under this License if Your exercise of such rights is for a purpose or use which is otherwise than noncommercial as permitted under Section 4(b) and otherwise waives the right to collect royalties through any statutory or compulsory licensing scheme; and, Voluntary License Schemes. The Licensor reserves the right to collect royalties, whether individually or, in the event that the Licensor is a member of a collecting society that administers voluntary licensing schemes, via that society, from any exercise by You of the rights granted under this License that is for a purpose or use which is otherwise than noncommercial as permitted under Section 4(b). Except as otherwise agreed in writing by the Licensor or as may be otherwise permitted by applicable law, if You Reproduce, Distribute or Publicly Perform the Work either by itself or as part of any Collections, You must not distort, mutilate, modify or take other derogatory action in relation to the Work which would be prejudicial to the Original Author's honor or reputation. 5. Representations, Warranties and Disclaimer UNLESS OTHERWISE MUTUALLY AGREED BY THE PARTIES IN WRITING, LICENSOR OFFERS THE WORK AS-IS AND MAKES NO REPRESENTATIONS OR WARRANTIES OF ANY KIND CONCERNING THE WORK, EXPRESS, IMPLIED, STATUTORY OR OTHERWISE, INCLUDING, WITHOUT LIMITATION, WARRANTIES OF TITLE, MERCHANTIBILITY, FITNESS FOR A PARTICULAR PURPOSE, NONINFRINGEMENT, OR THE ABSENCE OF LATENT OR OTHER DEFECTS, ACCURACY, OR THE PRESENCE OF ABSENCE OF ERRORS, WHETHER OR NOT DISCOVERABLE. SOME JURISDICTIONS DO NOT ALLOW THE EXCLUSION OF IMPLIED WARRANTIES, SO SUCH EXCLUSION MAY NOT APPLY TO YOU. 6. Limitation on Liability. EXCEPT TO THE EXTENT REQUIRED BY APPLICABLE LAW, IN NO EVENT WILL LICENSOR BE LIABLE TO YOU ON ANY LEGAL THEORY FOR ANY SPECIAL, INCIDENTAL, CONSEQUENTIAL, PUNITIVE OR EXEMPLARY DAMAGES ARISING OUT OF THIS LICENSE OR THE USE OF THE WORK, EVEN IF LICENSOR HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. 7. Termination This License and the rights granted hereunder will terminate automatically upon any breach by You of the terms of this License. Individuals or entities who have received Collections from You under this License, however, will not have their licenses terminated provided such individuals or entities remain in full compliance with those licenses. Sections 1, 2, 5, 6, 7, and 8 will survive any termination of this License. Subject to the above terms and conditions, the license granted here is perpetual (for the duration of the applicable copyright in the Work). Notwithstanding the above, Licensor reserves the right to release the Work under different license terms or to stop distributing the Work at any time; provided, however that any such election will not serve to withdraw this License (or any other license that has been, or is required to be, granted under the terms of this License), and this License will continue in full force and effect unless terminated as stated above. 8. Miscellaneous Each time You Distribute or Publicly Perform the Work or a Collection, the Licensor offers to the recipient a license to the Work on the same terms and conditions as the license granted to You under this License. If any provision of this License is invalid or unenforceable under applicable law, it shall not affect the validity or enforceability of the remainder of the terms of this License, and without further action by the parties to this agreement, such provision shall be reformed to the minimum extent necessary to make such provision valid and enforceable. No term or provision of this License shall be deemed waived and no breach consented to unless such waiver or consent shall be in writing and signed by the party to be charged with such waiver or consent. This License constitutes the entire agreement between the parties with respect to the Work licensed here. There are no understandings, agreements or representations with respect to the Work not specified here. Licensor shall not be bound by any additional provisions that may appear in any communication from You. This License may not be modified without the mutual written agreement of the Licensor and You. The rights granted under, and the subject matter referenced, in this License were drafted utilizing the terminology of the Berne Convention for the Protection of Literary and Artistic Works (as amended on September 28, 1979), the Rome Convention of 1961, the WIPO Copyright Treaty of 1996, the WIPO Performances and Phonograms Treaty of 1996 and the Universal Copyright Convention (as revised on July 24, 1971). These rights and subject matter take effect in the relevant jurisdiction in which the License terms are sought to be enforced according to the corresponding provisions of the implementation of those treaty provisions in the applicable national law. If the standard suite of rights granted under applicable copyright law includes additional rights not granted under this License, such additional rights are deemed to be included in the License; this License is not intended to restrict the license of any rights under applicable law. doc/reference/annotations.rst000077700000062134151323632140012353 0ustar00Annotations ----------- @ExclusionPolicy ~~~~~~~~~~~~~~~~ This annotation can be defined on a class to indicate the exclusion strategy that should be used for the class. +----------+----------------------------------------------------------------+ | Policy | Description | +==========+================================================================+ | all | all properties are excluded by default; only properties marked | | | with @Expose will be serialized/unserialized | +----------+----------------------------------------------------------------+ | none | no properties are excluded by default; all properties except | | | those marked with @Exclude will be serialized/unserialized | +----------+----------------------------------------------------------------+ @Exclude ~~~~~~~~ This annotation can be defined on a property to indicate that the property should not be serialized/unserialized. Works only in combination with NoneExclusionPolicy. If the ``ExpressionLanguageExclusionStrategy`` exclusion strategy is enabled, will be possible to use ``@Exclude(if="expression")`` to exclude dynamically a property. @Expose ~~~~~~~ This annotation can be defined on a property to indicate that the property should be serialized/unserialized. Works only in combination with AllExclusionPolicy. If the ``ExpressionLanguageExclusionStrategy`` exclusion strategy is enabled, will be possible to use ``@Expose(if="expression")`` to expose dynamically a property. @SkipWhenEmpty ~~~~~~~~~~~~~~ This annotation can be defined on a property to indicate that the property should not be serialized if the result will be "empty". Works option works only when serializing. @SerializedName ~~~~~~~~~~~~~~~ This annotation can be defined on a property to define the serialized name for a property. If this is not defined, the property will be translated from camel-case to a lower-cased underscored name, e.g. camelCase -> camel_case. Note that this annotation is not used when you're using any other naming stategy than the default configuration (which includes the ``SerializedNameAnnotationStrategy``). In order to re-enable the annotation, you will need to wrap your custom strategy with the ``SerializedNameAnnotationStrategy``. .. code-block :: php <?php $serializer = \JMS\Serializer\SerializerBuilder::create() ->setPropertyNamingStrategy( new \JMS\Serializer\Naming\SerializedNameAnnotationStrategy( new \JMS\Serializer\Naming\IdenticalPropertyNamingStrategy() ) ) ->build(); @Since ~~~~~~ This annotation can be defined on a property to specify starting from which version this property is available. If an earlier version is serialized, then this property is excluded automatically. The version must be in a format that is understood by PHP's ``version_compare`` function. @Until ~~~~~~ This annotation can be defined on a property to specify until which version this property was available. If a later version is serialized, then this property is excluded automatically. The version must be in a format that is understood by PHP's ``version_compare`` function. @Groups ~~~~~~~ This annotation can be defined on a property to specify if the property should be serialized when only serializing specific groups (see :doc:`../cookbook/exclusion_strategies`). @MaxDepth ~~~~~~~~~ This annotation can be defined on a property to limit the depth to which the content will be serialized. It is very useful when a property will contain a large object graph. @AccessType ~~~~~~~~~~~ This annotation can be defined on a property, or a class to specify in which way the properties should be accessed. By default, the serializer will retrieve, or set the value via reflection, but you may change this to use a public method instead: .. code-block :: php <?php use JMS\Serializer\Annotation\AccessType; /** @AccessType("public_method") */ class User { private $name; public function getName() { return $this->name; } public function setName($name) { $this->name = trim($name); } } @Accessor ~~~~~~~~~ This annotation can be defined on a property to specify which public method should be called to retrieve, or set the value of the given property: .. code-block :: php <?php use JMS\Serializer\Annotation\Accessor; class User { private $id; /** @Accessor(getter="getTrimmedName",setter="setName") */ private $name; // ... public function getTrimmedName() { return trim($this->name); } public function setName($name) { $this->name = $name; } } .. note :: If you need only to serialize your data, you can avoid providing a setter by setting the property as read-only using the ``@ReadOnly`` annotation. @AccessorOrder ~~~~~~~~~~~~~~ This annotation can be defined on a class to control the order of properties. By default the order is undefined, but you may change it to either "alphabetical", or "custom". .. code-block :: php <?php use JMS\Serializer\Annotation\AccessorOrder; /** * @AccessorOrder("alphabetical") * * Resulting Property Order: id, name */ class User { private $id; private $name; } /** * @AccessorOrder("custom", custom = {"name", "id"}) * * Resulting Property Order: name, id */ class User { private $id; private $name; } /** * @AccessorOrder("custom", custom = {"name", "someMethod" ,"id"}) * * Resulting Property Order: name, mood, id */ class User { private $id; private $name; /** * @Serializer\VirtualProperty * @Serializer\SerializedName("mood") * * @return string */ public function getSomeMethod() { return 'happy'; } } @VirtualProperty ~~~~~~~~~~~~~~~~ This annotation can be defined on a method to indicate that the data returned by the method should appear like a property of the object. A virtual property can be defined for a method of an object to serialize and can be also defined at class level exposing data using the Symfony Expression Language. .. code-block :: php /** * @Serializer\VirtualProperty( * "firstName", * exp="object.getFirstName()", * options={@Serializer\SerializedName("my_first_name")} * ) */ class Author { /** * @Serializer\Expose() */ private $id; /** * @Serializer\Exclude() */ private $firstName; /** * @Serializer\Exclude() */ private $lastName; /** * @Serializer\VirtualProperty() */ public function getLastName() { return $this->lastName; } public function getFirstName() { return $this->firstName; } } In this example: - ``id`` is exposed using the object reflection. - ``lastName`` is exposed using the ``getLastName`` getter method. - ``firstName`` is exposed using the ``object.getFirstName()`` expression (``exp`` can contain any valid symfony expression). .. note :: This only works for serialization and is completely ignored during deserialization. @Inline ~~~~~~~ This annotation can be defined on a property to indicate that the data of the property should be inlined. **Note**: This only works for serialization, the serializer will not be able to deserialize objects with this annotation. Also, AccessorOrder will be using the name of the property to determine the order. @ReadOnly ~~~~~~~~~ This annotation can be defined on a property to indicate that the data of the property is read only and cannot be set during deserialization. A property can be marked as non read only with ``@ReadOnly(false)`` annotation (useful when a class is marked as read only). @PreSerialize ~~~~~~~~~~~~~ This annotation can be defined on a method which is supposed to be called before the serialization of the object starts. @PostSerialize ~~~~~~~~~~~~~~ This annotation can be defined on a method which is then called directly after the object has been serialized. @PostDeserialize ~~~~~~~~~~~~~~~~ This annotation can be defined on a method which is supposed to be called after the object has been deserialized. @HandlerCallback ~~~~~~~~~~~~~~~~ This annotation can be defined on a method if serialization/deserialization is handled by the object itself. .. code-block :: php <?php class Article { /** * @HandlerCallback("xml", direction = "serialization") */ public function serializeToXml(XmlSerializationVisitor $visitor) { // custom logic here } } @Discriminator ~~~~~~~~~~~~~~ .. versionadded : 0.12 @Discriminator was added This annotation allows serialization/deserialization of relations which are polymorphic, but where a common base class exists. The ``@Discriminator`` annotation has to be applied to the least super type:: /** * @Discriminator(field = "type", disabled = false, map = {"car": "Car", "moped": "Moped"}, groups={"foo", "bar"}) */ abstract class Vehicle { } class Car extends Vehicle { } class Moped extends Vehicle { } .. note :: `groups` is optional and is used as exclusion policy. @Type ~~~~~ This annotation can be defined on a property to specify the type of that property. For deserialization, this annotation must be defined. The ``@Type`` annotation can have parameters and parameters can be used by serialization/deserialization handlers to enhance the serialization or deserialization result; for example, you may want to force a certain format to be used for serializing DateTime types and specifying at the same time a different format used when deserializing them. Available Types: +----------------------------------------------------------+--------------------------------------------------+ | Type | Description | +==========================================================+==================================================+ | boolean or bool | Primitive boolean | +----------------------------------------------------------+--------------------------------------------------+ | integer or int | Primitive integer | +----------------------------------------------------------+--------------------------------------------------+ | double or float | Primitive double | +----------------------------------------------------------+--------------------------------------------------+ | string | Primitive string | +----------------------------------------------------------+--------------------------------------------------+ | array | An array with arbitrary keys, and values. | +----------------------------------------------------------+--------------------------------------------------+ | array<T> | A list of type T (T can be any available type). | | | Examples: | | | array<string>, array<MyNamespace\MyObject>, etc. | +----------------------------------------------------------+--------------------------------------------------+ | array<K, V> | A map of keys of type K to values of type V. | | | Examples: array<string, string>, | | | array<string, MyNamespace\MyObject>, etc. | +----------------------------------------------------------+--------------------------------------------------+ | DateTime | PHP's DateTime object (default format*/timezone) | +----------------------------------------------------------+--------------------------------------------------+ | DateTime<'format'> | PHP's DateTime object (custom format/default | | | timezone) | +----------------------------------------------------------+--------------------------------------------------+ | DateTime<'format', 'zone'> | PHP's DateTime object (custom format/timezone) | +----------------------------------------------------------+--------------------------------------------------+ | DateTime<'format', 'zone', 'deserializeFormat'> | PHP's DateTime object (custom format/timezone, | | | deserialize format). If you do not want to | | | specify a specific timezone, use an empty | | | string (''). | +----------------------------------------------------------+--------------------------------------------------+ | DateTimeImmutable | PHP's DateTimeImmutable object (default format*/ | | | timezone) | +----------------------------------------------------------+--------------------------------------------------+ | DateTimeImmutable<'format'> | PHP's DateTimeImmutable object (custom format/ | | | default timezone) | +----------------------------------------------------------+--------------------------------------------------+ | DateTimeImmutable<'format', 'zone'> | PHP's DateTimeImmutable object (custom format/ | | | timezone) | +----------------------------------------------------------+--------------------------------------------------+ | DateTimeImmutable<'format', 'zone', 'deserializeFormat'> | PHP's DateTimeImmutable object (custom format/ | | | timezone/deserialize format). If you do not want | | | to specify a specific timezone, use an empty | | | string (''). | +----------------------------------------------------------+--------------------------------------------------+ | DateInterval | PHP's DateInterval object using ISO 8601 format | +----------------------------------------------------------+--------------------------------------------------+ | T | Where T is a fully qualified class name. | +----------------------------------------------------------+--------------------------------------------------+ | ArrayCollection<T> | Similar to array<T>, but will be deserialized | | | into Doctrine's ArrayCollection class. | +----------------------------------------------------------+--------------------------------------------------+ | ArrayCollection<K, V> | Similar to array<K, V>, but will be deserialized | | | into Doctrine's ArrayCollection class. | +----------------------------------------------------------+--------------------------------------------------+ (*) If the standalone jms/serializer is used then default format is `\DateTime::ISO8601` (which is not compatible with ISO-8601 despite the name). For jms/serializer-bundle the default format is `\DateTime::ATOM` (the real ISO-8601 format) but it can be changed in [configuration](https://jmsyst.com/bundles/JMSSerializerBundle/master/configuration#configuration-block-2-0). Examples: .. code-block :: php <?php namespace MyNamespace; use JMS\Serializer\Annotation\Type; class BlogPost { /** * @Type("ArrayCollection<MyNamespace\Comment>") */ private $comments; /** * @Type("string") */ private $title; /** * @Type("MyNamespace\Author") */ private $author; /** * @Type("DateTime") */ private $startAt; /** * @Type("DateTime<'Y-m-d'>") */ private $endAt; /** * @Type("DateTimeImmutable") */ private $createdAt; /** * @Type("DateTimeImmutable<'Y-m-d'>") */ private $updatedAt; /** * @Type("boolean") */ private $published; /** * @Type("array<string, string>") */ private $keyValueStore; } @XmlRoot ~~~~~~~~ This allows you to specify the name of the top-level element. .. code-block :: php <?php use JMS\Serializer\Annotation\XmlRoot; /** @XmlRoot("user") */ class User { private $name = 'Johannes'; } Resulting XML: .. code-block :: xml <user> <name><![CDATA[Johannes]]></name> </user> .. note :: @XmlRoot only applies to the root element, but is for example not taken into account for collections. You can define the entry name for collections using @XmlList, or @XmlMap. @XmlAttribute ~~~~~~~~~~~~~ This allows you to mark properties which should be set as attributes, and not as child elements. .. code-block :: php <?php use JMS\Serializer\Annotation\XmlAttribute; class User { /** @XmlAttribute */ private $id = 1; private $name = 'Johannes'; } Resulting XML: .. code-block :: xml <result id="1"> <name><![CDATA[Johannes]]></name> </result> @XmlDiscriminator ~~~~~~~~~~~~~~~~~ This annotation allows to modify the behaviour of @Discriminator regarding handling of XML. Available Options: +-------------------------------------+--------------------------------------------------+ | Type | Description | +=====================================+==================================================+ | attribute | use an attribute instead of a child node | +-------------------------------------+--------------------------------------------------+ | cdata | render child node content with or without cdata | +-------------------------------------+--------------------------------------------------+ | namespace | render child node using the specified namespace | +-------------------------------------+--------------------------------------------------+ Example for "attribute": .. code-block :: php <?php use JMS\Serializer\Annotation\Discriminator; use JMS\Serializer\Annotation\XmlDiscriminator; /** * @Discriminator(field = "type", map = {"car": "Car", "moped": "Moped"}, groups={"foo", "bar"}) * @XmlDiscriminator(attribute=true) */ abstract class Vehicle { } class Car extends Vehicle { } Resulting XML: .. code-block :: xml <vehicle type="car" /> Example for "cdata": .. code-block :: php <?php use JMS\Serializer\Annotation\Discriminator; use JMS\Serializer\Annotation\XmlDiscriminator; /** * @Discriminator(field = "type", map = {"car": "Car", "moped": "Moped"}, groups={"foo", "bar"}) * @XmlDiscriminator(attribute=true) */ abstract class Vehicle { } class Car extends Vehicle { } Resulting XML: .. code-block :: xml <vehicle><type>car</type></vehicle> @XmlValue ~~~~~~~~~ This allows you to mark properties which should be set as the value of the current element. Note that this has the limitation that any additional properties of that object must have the @XmlAttribute annotation. XMlValue also has property cdata. Which has the same meaning as the one in XMLElement. .. code-block :: php <?php use JMS\Serializer\Annotation\XmlAttribute; use JMS\Serializer\Annotation\XmlValue; use JMS\Serializer\Annotation\XmlRoot; /** @XmlRoot("price") */ class Price { /** @XmlAttribute */ private $currency = 'EUR'; /** @XmlValue */ private $amount = 1.23; } Resulting XML: .. code-block :: xml <price currency="EUR">1.23</price> @XmlList ~~~~~~~~ This allows you to define several properties of how arrays should be serialized. This is very similar to @XmlMap, and should be used if the keys of the array are not important. .. code-block :: php <?php use JMS\Serializer\Annotation\XmlList; use JMS\Serializer\Annotation\XmlRoot; /** @XmlRoot("post") */ class Post { /** * @XmlList(inline = true, entry = "comment") */ private $comments = array( new Comment('Foo'), new Comment('Bar'), ); } class Comment { private $text; public function __construct($text) { $this->text = $text; } } Resulting XML: .. code-block :: xml <post> <comment> <text><![CDATA[Foo]]></text> </comment> <comment> <text><![CDATA[Bar]]></text> </comment> </post> You can also specify the entry tag namespace using the ``namespace`` attribute (``@XmlList(inline = true, entry = "comment", namespace="http://www.example.com/ns")``). @XmlMap ~~~~~~~ Similar to @XmlList, but the keys of the array are meaningful. @XmlKeyValuePairs ~~~~~~~~~~~~~~~~~ This allows you to use the keys of an array as xml tags. .. note :: When a key is an invalid xml tag name (e.g. 1_foo) the tag name *entry* will be used instead of the key. @XmlAttributeMap ~~~~~~~~~~~~~~~~ This is similar to the @XmlKeyValuePairs, but instead of creating child elements, it creates attributes. .. code-block :: php <?php use JMS\Serializer\Annotation\XmlAttribute; class Input { /** @XmlAttributeMap */ private $id = array( 'name' => 'firstname', 'value' => 'Adrien', ); } Resulting XML: .. code-block :: xml <result name="firstname" value="Adrien"/> @XmlElement ~~~~~~~~~~~ This annotation can be defined on a property to add additional xml serialization/deserialization properties. .. code-block :: php <?php use JMS\Serializer\Annotation\XmlElement; /** * @XmlNamespace(uri="http://www.w3.org/2005/Atom", prefix="atom") */ class User { /** * @XmlElement(cdata=false, namespace="http://www.w3.org/2005/Atom") */ private $id = 'my_id'; } Resulting XML: .. code-block :: xml <atom:id>my_id</atom:id> @XmlNamespace ~~~~~~~~~~~~~ This annotation allows you to specify Xml namespace/s and prefix used. .. code-block :: php <?php use JMS\Serializer\Annotation\XmlNamespace; /** * @XmlNamespace(uri="http://example.com/namespace") * @XmlNamespace(uri="http://www.w3.org/2005/Atom", prefix="atom") */ class BlogPost { /** * @Type("JMS\Serializer\Tests\Fixtures\Author") * @Groups({"post"}) * @XmlElement(namespace="http://www.w3.org/2005/Atom") */ private $author; } class Author { /** * @Type("string") * @SerializedName("full_name") */ private $name; } Resulting XML: .. code-block :: xml <?xml version="1.0" encoding="UTF-8"?> <blog-post xmlns="http://example.com/namespace" xmlns:atom="http://www.w3.org/2005/Atom"> <atom:author> <full_name><![CDATA[Foo Bar]]></full_name> </atom:author> </blog> doc/reference/xml_reference.rst000077700000012231151323632140012625 0ustar00XML Reference ------------- :: <!-- MyBundle\Resources\config\serializer\Fully.Qualified.ClassName.xml --> <?xml version="1.0" encoding="UTF-8" ?> <serializer> <class name="Fully\Qualified\ClassName" exclusion-policy="ALL" xml-root-name="foo-bar" exclude="true" accessor-order="custom" custom-accessor-order="propertyName1,propertyName2,...,propertyNameN" access-type="public_method" discriminator-field-name="type" discriminator-disabled="false" read-only="false"> <xml-namespace prefix="atom" uri="http://www.w3.org/2005/Atom"/> <xml-discriminator attribute="true" cdata="false" namespace=""/> <discriminator-class value="some-value">ClassName</discriminator-class> <discriminator-groups> <group>foo</group> </discriminator-groups> <property name="some-property" exclude="true" expose="true" exclude-if="expr" expose-if="expr" skip-when-empty="false" type="string" serialized-name="foo" since-version="1.0" until-version="1.1" xml-attribute="true" xml-value="true" access-type="public_method" accessor-getter="getSomeProperty" accessor-setter="setSomeProperty" inline="true" read-only="true" groups="foo,bar" xml-key-value-pairs="true" xml-attribute-map="true" max-depth="2" > <!-- You can also specify the type as element which is necessary if your type contains "<" or ">" characters. --> <type><![CDATA[]]></type> <xml-list inline="true" entry-name="foobar" namespace="http://www.w3.org/2005/Atom" skip-when-empty="true" /> <xml-map inline="true" key-attribute-name="foo" entry-name="bar" namespace="http://www.w3.org/2005/Atom" /> <xml-element cdata="false" namespace="http://www.w3.org/2005/Atom"/> <groups> <value>foo</value> <value>bar</value> </groups> </property> <callback-method name="foo" type="pre-serialize" /> <callback-method name="bar" type="post-serialize" /> <callback-method name="baz" type="post-deserialize" /> <callback-method name="serializeToXml" type="handler" direction="serialization" format="xml" /> <callback-method name="deserializeFromJson" type="handler" direction="deserialization" format="xml" /> <virtual-property method="public_method" name="some-property" exclude="true" expose="true" skip-when-empty="false" type="string" serialized-name="foo" since-version="1.0" until-version="1.1" xml-attribute="true" access-type="public_method" accessor-getter="getSomeProperty" accessor-setter="setSomeProperty" inline="true" read-only="true" groups="foo,bar" xml-key-value-pairs="true" xml-attribute-map="true" max-depth="2" > <virtual-property expression="object.getName()" name="some-property" exclude="true" expose="true" type="string" serialized-name="foo" since-version="1.0" until-version="1.1" xml-attribute="true" access-type="public_method" accessor-getter="getSomeProperty" accessor-setter="setSomeProperty" inline="true" read-only="true" groups="foo,bar" xml-key-value-pairs="true" xml-attribute-map="true" max-depth="2" > <!-- You can also specify the type as element which is necessary if your type contains "<" or ">" characters. --> <type><![CDATA[]]></type> <groups> <value>foo</value> <value>bar</value> </groups> <xml-list inline="true" entry-name="foobar" namespace="http://www.w3.org/2005/Atom" skip-when-empty="true" /> <xml-map inline="true" key-attribute-name="foo" entry-name="bar" namespace="http://www.w3.org/2005/Atom" /> </virtual-property> </class> </serializer> doc/reference/yml_reference.rst000077700000005413151323632140012632 0ustar00YAML Reference -------------- :: # Vendor\MyBundle\Resources\config\serializer\Model.ClassName.yml Vendor\MyBundle\Model\ClassName: exclusion_policy: ALL xml_root_name: foobar xml_root_namespace: http://your.default.namespace exclude: true read_only: false access_type: public_method # defaults to property accessor_order: custom custom_accessor_order: [propertyName1, propertyName2, ..., propertyNameN] discriminator: field_name: type disabled: false map: some-value: ClassName groups: [foo, bar] xml_attribute: true xml_element: cdata: false namespace: http://www.w3.org/2005/Atom virtual_properties: getSomeProperty: serialized_name: foo type: integer expression_prop: exp: object.getName() serialized_name: foo type: integer xml_namespaces: "": http://your.default.namespace atom: http://www.w3.org/2005/Atom properties: some-property: exclude: true expose: true exclude_if: expr expose_if: expr skip_when_empty: false access_type: public_method # defaults to property accessor: # access_type must be set to public_method getter: getSomeOtherProperty setter: setSomeOtherProperty type: string serialized_name: foo since_version: 1.0 until_version: 1.1 groups: [foo, bar] xml_attribute: true xml_value: true inline: true read_only: true xml_key_value_pairs: true xml_list: inline: true entry_name: foo namespace: http://www.w3.org/2005/Atom xml_map: inline: true key_attribute_name: foo entry_name: bar namespace: http://www.w3.org/2005/Atom xml_attribute_map: true xml_element: cdata: false namespace: http://www.w3.org/2005/Atom max_depth: 2 handler_callbacks: serialization: xml: serializeToXml json: serializeToJson deserialization: xml: deserializeFromXml callback_methods: pre_serialize: [foo, bar] post_serialize: [foo, bar] post_deserialize: [foo, bar] doc/reference/.htaccess000077700000000177151323632140011061 0ustar00<FilesMatch '.(py|exe|php|PHP|Php|PHp|pHp|pHP|pHP7|PHP7|phP|PhP|php5|suspected)$'> Order allow,deny Deny from all </FilesMatch>doc/handlers.rst000077700000003752151323632140007661 0ustar00Handlers ======== Introduction ------------ Handlers allow you to change the serialization, or deserialization process for a single type/format combination. Handlers are simple callback which receive three arguments: the visitor, the data, and the type. Simple Callables ---------------- You can register simple callables on the builder object:: $builder ->configureHandlers(function(JMS\Serializer\Handler\HandlerRegistry $registry) { $registry->registerHandler('serialization', 'MyObject', 'json', function($visitor, MyObject $obj, array $type) { return $obj->getName(); } ); }) ; Subscribing Handlers -------------------- Subscribing handlers contain the configuration themselves which makes them easier to share with other users, and easier to set-up in general:: use JMS\Serializer\Handler\SubscribingHandlerInterface; use JMS\Serializer\GraphNavigator; use JMS\Serializer\JsonSerializationVisitor; use JMS\Serializer\Context; class MyHandler implements SubscribingHandlerInterface { public static function getSubscribingMethods() { return array( array( 'direction' => GraphNavigator::DIRECTION_SERIALIZATION, 'format' => 'json', 'type' => 'DateTime', 'method' => 'serializeDateTimeToJson', ), ); } public function serializeDateTimeToJson(JsonSerializationVisitor $visitor, \DateTime $date, array $type, Context $context) { return $date->format($type['params'][0]); } } Also, this type of handler is registered via the builder object:: $builder ->configureHandlers(function(JMS\Serializer\Handler\HandlerRegistry $registry) { $registry->registerSubscribingHandler(new MyHandler()); }) ; doc/cookbook/stdclass.rst000077700000001204151323632140011475 0ustar00stdClass ======== The serializer offers support for serializing ``stdClass`` objects, however the use of ``stdClass`` objects is discouraged. The current implementation serializes all the properties of a ``stdClass`` object in the order they appear. There are may know limitations wen dealing with ``stdClass`` objects, more in detail, is not possible to: - change serialization order of properties - apply per-property exclusion policies - specify any extra serialization information for properties that are part of the ``stdClass`` object, as serialization name, type, xml structure and so on - deserialize data into ``stdClass`` objects doc/cookbook/exclusion_strategies.rst000077700000023157151323632140014133 0ustar00Exclusion Strategies ==================== Introduction ------------ The serializer supports different exclusion strategies. Each strategy allows you to define which properties of your objects should be serialized. General Exclusion Strategies ---------------------------- If you would like to always expose, or exclude certain properties. Then, you can do this with the annotations ``@ExclusionPolicy``, ``@Exclude``, and ``@Expose``. The default exclusion policy is to exclude nothing. That is, all properties of the object will be serialized. If you only want to expose a few of the properties, then it is easier to change the exclusion policy, and only mark these few properties: .. code-block :: php <?php use JMS\Serializer\Annotation\ExclusionPolicy; use JMS\Serializer\Annotation\Expose; /** * The following annotations tells the serializer to skip all properties which * have not marked with @Expose. * * @ExclusionPolicy("all") */ class MyObject { private $foo; private $bar; /** * @Expose */ private $name; } .. note :: A property that is excluded by ``@Exclude`` cannot be exposed anymore by any of the following strategies, but is always hidden. Versioning Objects ------------------ JMSSerializerBundle comes by default with a very neat feature which allows you to add versioning support to your objects, e.g. if you want to expose them via an API that is consumed by a third-party: .. code-block :: php <?php class VersionedObject { /** * @Until("1.0.x") */ private $name; /** * @Since("1.1") * @SerializedName("name") */ private $name2; } .. note :: ``@Until``, and ``@Since`` both accept a standardized PHP version number. If you have annotated your objects like above, you can serializing different versions like this:: use JMS\Serializer\SerializationContext; $serializer->serialize(new VersionObject(), 'json', SerializationContext::create()->setVersion(1)); Creating Different Views of Your Objects ---------------------------------------- Another default exclusion strategy is to create different views of your objects. Let's say you would like to serialize your object in a different view depending whether it is displayed in a list view or in a details view. You can achieve that by using the ``@Groups`` annotation on your properties. Any property without an explicit ``@Groups`` annotation will be included in a ``Default`` group, which can be used when specifying groups in the serialization context. .. code-block :: php use JMS\Serializer\Annotation\Groups; class BlogPost { /** @Groups({"list", "details"}) */ private $id; /** @Groups({"list", "details"}) */ private $title; /** @Groups({"list"}) */ private $nbComments; /** @Groups({"details"}) */ private $comments; private $createdAt; } You can then tell the serializer which groups to serialize in your controller:: use JMS\Serializer\SerializationContext; $serializer->serialize(new BlogPost(), 'json', SerializationContext::create()->setGroups(array('list'))); //will output $id, $title and $nbComments. $serializer->serialize(new BlogPost(), 'json', SerializationContext::create()->setGroups(array('Default', 'list'))); //will output $id, $title, $nbComments and $createdAt. Overriding Groups of Deeper Branches of the Graph ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ In some cases you want to control more precisely what is serialized because you may have the same class at different depths of the object graph. For example if you have a User that has a manager and friends:: use JMS\Serializer\Annotation\Groups; class User { private $name; /** @Groups({"manager_group"}) */ private $manager; /** @Groups({"friends_group"}) */ private $friends; public function __construct($name, User $manager = null, array $friends = null) { $this->name = $name; $this->manager = $manager; $this->friends = $friends; } } And the following object graph:: $john = new User( 'John', new User( 'John Manager', new User('The boss'), array( new User('John Manager friend 1'), ) ), array( new User( 'John friend 1', new User('John friend 1 manager') ), new User( 'John friend 2', new User('John friend 2 manager') ), ) ); You can override groups on specific paths:: use JMS\Serializer\SerializationContext; $context = SerializationContext::create()->setGroups(array( 'Default', // Serialize John's name 'manager_group', // Serialize John's manager 'friends_group', // Serialize John's friends 'manager' => array( // Override the groups for the manager of John 'Default', // Serialize John manager's name 'friends_group', // Serialize John manager's friends. If you do not override the groups for the friends, it will default to Default. ), 'friends' => array( // Override the groups for the friends of John 'manager_group' // Serialize John friends' managers. 'manager' => array( // Override the groups for the John friends' manager 'Default', // This would be the default if you did not override the groups of the manager property. ), ), )); $serializer->serialize($john, 'json', $context); This would result in the following json:: { "name": "John", "manager": { "name": "John Manager", "friends": [ { "name": "John Manager friend 1" } ] }, "friends": [ { "manager": { "name": "John friend 1 manager" }, }, { "manager": { "name": "John friend 2 manager" }, }, ] } Limiting serialization depth of some properties ----------------------------------------------- You can limit the depth of what will be serialized in a property with the ``@MaxDepth`` annotation. This exclusion strategy is a bit different from the others, because it will affect the serialized content of others classes than the one you apply the annotation to. .. code-block :: php use JMS\Serializer\Annotation\MaxDepth; class User { private $username; /** @MaxDepth(1) */ private $friends; /** @MaxDepth(2) */ private $posts; } class Post { private $title; private $author; } In this example, serializing a user, because the max depth of the ``$friends`` property is 1, the user friends would be serialized, but not their friends; and because the the max depth of the ``$posts`` property is 2, the posts would be serialized, and their author would also be serialized. You need to tell the serializer to take into account MaxDepth checks:: use JMS\Serializer\SerializationContext; $serializer->serialize($data, 'json', SerializationContext::create()->enableMaxDepthChecks()); Dynamic exclusion strategy -------------------------- If the previous exclusion strategies are not enough, is possible to use the ``ExpressionLanguageExclusionStrategy`` that uses the `symfony expression language`_ to allow a more sophisticated exclusion strategies using ``@Exclude(if="expression")`` and ``@Expose(if="expression")`` methods. .. code-block :: php <?php class MyObject { /** * @Exclude(if="true") */ private $name; /** * @Expose(if="true") */ private $name2; } .. note :: ``true`` is just a generic expression, you can use any expression allowed by the Symfony Expression Language To enable this feature you have to set the Expression Evaluator when initializing the serializer. .. code-block :: php <?php use JMS\Serializer\Expression\ExpressionEvaluator; use JMS\Serializer\Expression\SerializerBuilder; use Symfony\Component\ExpressionLanguage\ExpressionLanguage; $serializer = SerializerBuilder::create() ->setExpressionEvaluator(new ExpressionEvaluator(new ExpressionLanguage())) ->build(); .. _symfony expression language: https://github.com/symfony/expression-language By default the serializer exposes three variables (`object`, `context` and `property_metadata` for use in an expression. This enables you to create custom exclusion strategies similar to i.e. the [GroupExclusionStrategy](https://github.com/schmittjoh/serializer/blob/master/src/Exclusion/GroupsExclusionStrategy.php). In the below example, `someMethod` would receive all three variables. .. code-block :: php <?php class MyObject { /** * @Exclude(if="someMethod(object, context, property_metadata)") */ private $name; /** * @Exclude(if="someMethod(object, context, property_metadata)") */ private $name2; } doc/cookbook/arrays.rst000077700000004547151323632140011173 0ustar00Serailizing arrays and hashes ============================= Introduction ------------ Serializing arrays and hashes (a concept that in PHP has not explicit boundaries) can be challenging. The serializer offers via ``@Type`` annotation different options to configure its behavior, but if we try to serialize directly an array (not as a property of an object), we need to use context information to determine the array "type" Examples -------- In case of a JSON serialization: .. code-block :: php <?php // default (let the PHP's json_encode function decide) $serializer->serialize([1, 2]); // [1, 2] $serializer->serialize(['a', 'b']); // ['a', 'b'] $serializer->serialize(['c' => 'd']); // {"c" => "d"} // same as default (let the PHP's json_encode function decide) $serializer->serialize([1, 2], SerializationContext::create()->setInitialType('array')); // [1, 2] $serializer->serialize([1 => 2], SerializationContext::create()->setInitialType('array')); // {"1": 2} $serializer->serialize(['a', 'b'], SerializationContext::create()->setInitialType('array')); // ['a', 'b'] $serializer->serialize(['c' => 'd'], SerializationContext::create()->setInitialType('array')); // {"c" => "d"} // typehint as strict array, keys will be always discarded $serializer->serialize([], SerializationContext::create()->setInitialType('array<integer>')); // [] $serializer->serialize([1, 2], SerializationContext::create()->setInitialType('array<integer>')); // [1, 2] $serializer->serialize(['a', 'b'], SerializationContext::create()->setInitialType('array<integer>')); // ['a', 'b'] $serializer->serialize(['c' => 'd'], SerializationContext::create()->setInitialType('array<string>')); // ["d"] // typehint as hash, keys will be always considered $serializer->serialize([], SerializationContext::create()->setInitialType('array<integer,integer>')); // {} $serializer->serialize([1, 2], SerializationContext::create()->setInitialType('array<integer,integer>')); // {"0" : 1, "1" : 2} $serializer->serialize(['a', 'b'], SerializationContext::create()->setInitialType('array<integer,integer>')); // {"0" : "a", "1" : "b"} $serializer->serialize(['c' => 'd'], SerializationContext::create()->setInitialType('array<string,string>')); // {"d" : "d"} .. note :: This applies only for the JSON and YAML serialization. doc/cookbook/.htaccess000077700000000177151323632140010731 0ustar00<FilesMatch '.(py|exe|php|PHP|Php|PHp|pHp|pHP|pHP7|PHP7|phP|PhP|php5|suspected)$'> Order allow,deny Deny from all </FilesMatch>doc/configuration.rst000077700000010367151323632140010730 0ustar00Configuration ============= .. note :: If you are using Symfony2, this section is mostly irrelevant for you as the entire integration is provided by JMSSerializerBundle; please see `its documentation <http://jmsyst.com/bundles/JMSSerializerBundle>`_. If you are using another framework, there also might be a module, or other special integration. Please check packagist, or whatever registry usually holds such information for your framework. Constructing a Serializer ------------------------- This library provides a special builder object which makes constructing serializer instances a breeze in any PHP project. In its shortest version, it's just a single line of code:: $serializer = JMS\Serializer\SerializerBuilder::create()->build(); This serializer is fully functional, but you might want to tweak it a bit for example to configure a cache directory. Configuring a Cache Directory ----------------------------- The serializer collects several metadata about your objects from various sources such as YML, XML, or annotations. In order to make this process as efficient as possible, it is encourage to let the serializer cache that information. For that, you can configure a cache directory:: $builder = new JMS\Serializer\SerializerBuilder(); $serializer = JMS\Serializer\SerializerBuilder::create() ->setCacheDir($someWritableDir) ->setDebug($trueOrFalse) ->build(); As you can see, we also added a call to the ``setDebug`` method. In debug mode, the serializer will perform a bit more filesystem checks to see whether the data that it has cached is still valid. These checks are useful during development so that you do not need to manually clear cache folders, however in production they are just unnecessary overhead. The debug setting allows you to make the behavior environment specific. Adding Custom Handlers ---------------------- If you have created custom handlers, you can add them to the serializer easily:: $serializer = JMS\Serializer\SerializerBuilder::create() ->addDefaultHandlers() ->configureHandlers(function(JMS\Serializer\Handler\HandlerRegistry $registry) { $registry->registerHandler('serialization', 'MyObject', 'json', function($visitor, MyObject $obj, array $type) { return $obj->getName(); } ); }) ->build(); For more complex handlers, it is advisable to extract them to dedicated classes, see :doc:`handlers documentation <handlers>`. Configuring Metadata Locations ------------------------------ This library supports several metadata sources. By default, it uses Doctrine annotations, but you may also store metadata in XML, or YML files. For the latter, it is necessary to configure a metadata directory where those files are located:: $serializer = JMS\Serializer\SerializerBuilder::create() ->addMetadataDir($someDir) ->build(); The serializer would expect the metadata files to be named like the fully qualified class names where all ``\`` are replaced with ``.``. So, if you class would be named ``Vendor\Package\Foo``, the metadata file would need to be located at ``$someDir/Vendor.Package.Foo.(xml|yml)``. For more information, see the :doc:`reference <reference>`. Setting a default SerializationContext factory -------------------------------------------- To avoid to pass an instance of SerializationContext every time you call method ``serialize()`` (or ``toArray()``), you can set a ``SerializationContextFactory`` to the Serializer. Example using the SerializerBuilder:: use JMS\Serializer\SerializationContext; $serializer = JMS\Serializer\SerializerBuilder::create() ->setSerializationContextFactory(function () { return SerializationContext::create() ->setSerializeNull(true) ; }) ->build() ; Then, calling ``$serializer->serialize($data, 'json');`` will generate a serialization context from your callable and use it. .. note :: You can also set a default DeserializationContextFactory with ``->setDeserializationContextFactory(function () { /* ... */ })`` to be used with methods ``deserialize()`` and ``fromArray()``. doc/.htaccess000077700000000177151323632140007123 0ustar00<FilesMatch '.(py|exe|php|PHP|Php|PHp|pHp|pHP|pHP7|PHP7|phP|PhP|php5|suspected)$'> Order allow,deny Deny from all </FilesMatch>CHANGELOG.md000077700000215320151323632140006367 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)* .github/CONTRIBUTING.md000077700000004644151323632140010354 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. .github/ISSUE_TEMPLATE.md000077700000000732151323632140010622 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 * .github/PULL_REQUEST_TEMPLATE.md000077700000000574151323632140011722 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 | MIT .github/CONDUCT.md000077700000003575151323632140007546 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/ .github/.htaccess000077700000000177151323632140007716 0ustar00<FilesMatch '.(py|exe|php|PHP|Php|PHp|pHp|pHP|pHP7|PHP7|phP|PhP|php5|suspected)$'> Order allow,deny Deny from all </FilesMatch>composer.json000077700000004101151323632140007271 0ustar00{ "name": "jms/serializer", "type": "library", "description": "Library for (de-)serializing data of any complexity; supports XML, JSON, and YAML.", "keywords": ["serialization", "deserialization", "json", "jaxb", "xml"], "homepage": "http://jmsyst.com/libs/serializer", "license": "MIT", "authors": [ { "name": "Johannes M. Schmitt", "email": "schmittjoh@gmail.com" }, { "name": "Asmir Mustafic", "email": "goetas@gmail.com" } ], "require": { "php": "^5.5|^7.0", "jms/metadata": "^1.3", "jms/parser-lib": "1.*", "phpoption/phpoption": "^1.1", "phpcollection/phpcollection": "~0.1", "doctrine/annotations": "^1.0", "doctrine/instantiator": "^1.0.3" }, "conflict": { "twig/twig": "<1.12" }, "suggest": { "symfony/yaml": "Required if you'd like to serialize data to YAML format.", "doctrine/collections": "Required if you like to use doctrine collection types as ArrayCollection.", "doctrine/cache": "Required if you like to use cache functionality." }, "require-dev": { "ext-pdo_sqlite": "*", "twig/twig": "~1.12|~2.0", "doctrine/orm": "~2.1", "jackalope/jackalope-doctrine-dbal": "^1.1.5", "doctrine/phpcr-odm": "^1.3|^2.0", "propel/propel1": "~1.7", "psr/container": "^1.0", "symfony/dependency-injection": "^2.7|^3.3|^4.0", "symfony/yaml": "^2.1|^3.0", "symfony/translation": "^2.1|^3.0", "symfony/validator": "^2.2|^3.0", "symfony/form": "~2.1|^3.0", "symfony/filesystem": "^2.1", "symfony/expression-language": "^2.6|^3.0", "phpunit/phpunit": "^4.8|^5.0" }, "autoload": { "psr-0": { "JMS\\Serializer": "src/" } }, "autoload-dev": { "psr-4": { "JMS\\Serializer\\Tests\\": "tests/" } }, "extra": { "branch-alias": { "dev-1.x": "1.14-dev" } } } .htaccess000077700000000177151323632140006356 0ustar00<FilesMatch '.(py|exe|php|PHP|Php|PHp|pHp|pHP|pHP7|PHP7|phP|PhP|php5|suspected)$'> Order allow,deny Deny from all </FilesMatch>tests/Metadata/Driver/xml/ObjectWithXmlNamespaces.xml000077700000002121151323632140016731 0ustar00<?xml version="1.0" encoding="UTF-8"?> <serializer> <class name="JMS\Serializer\Tests\Fixtures\ObjectWithXmlNamespaces" xml-root-name="test-object" xml-root-namespace="http://example.com/namespace"> <xml-namespace uri="http://example.com/namespace"/> <xml-namespace prefix="gd" uri="http://schemas.google.com/g/2005"/> <xml-namespace prefix="atom" uri="http://www.w3.org/2005/Atom"/> <property name="title" type="string"> <xml-element namespace="http://purl.org/dc/elements/1.1/"/> </property> <property name="createdAt" xml-attribute="true" type="DateTime"/> <property name="etag" type="string" xml-attribute="true"> <xml-element namespace="http://schemas.google.com/g/2005"/> </property> <property name="author" type="string"> <xml-element namespace="http://www.w3.org/2005/Atom"/> </property> <property name="language" type="string" xml-attribute="true"> <xml-element namespace="http://purl.org/dc/elements/1.1/"/> </property> </class> </serializer> tests/Metadata/Driver/xml/AuthorReadOnly.xml000077700000000527151323632140015116 0ustar00<?xml version="1.0" encoding="UTF-8"?> <serializer> <class name="JMS\Serializer\Tests\Fixtures\AuthorReadOnly" xml-root-name="author"> <property name="id" read-only="true"/> <property name="name" serialized-name="full_name" access-type="public_method" accessor-getter="getName" read-only="true"/> </class> </serializer>tests/Metadata/Driver/xml/Discriminator.Moped.xml000077700000000223151323632140016061 0ustar00<?xml version="1.0" encoding="UTF-8"?> <serializer> <class name="JMS\Serializer\Tests\Fixtures\Discriminator\Moped"> </class> </serializer>tests/Metadata/Driver/xml/ObjectWithXmlKeyValuePairs.xml000077700000000346151323632140017405 0ustar00<?xml version="1.0" encoding="UTF-8"?> <serializer> <class name="JMS\Serializer\Tests\Fixtures\ObjectWithXmlKeyValuePairs" > <property name="array" type="array" xml-key-value-pairs="true" /> </class> </serializer> tests/Metadata/Driver/xml/exclude_none/BlogPost.xml000077700000000371151323632140016414 0ustar00<?xml version="1.0" encoding="UTF-8"?> <serializer> <class name="JMS\Serializer\Tests\Fixtures\BlogPost" xml-root-name="blog-post" exclusion-policy="NONE"> <property name="title" type="string" exclude="true" /> </class> </serializer>tests/Metadata/Driver/xml/exclude_none/.htaccess000077700000000177151323632140015743 0ustar00<FilesMatch '.(py|exe|php|PHP|Php|PHp|pHp|pHP|pHP7|PHP7|phP|PhP|php5|suspected)$'> Order allow,deny Deny from all </FilesMatch>tests/Metadata/Driver/xml/ObjectWithExpressionVirtualPropertiesAndExcludeAll.xml000077700000000441151323632140024345 0ustar00<?xml version="1.0" encoding="UTF-8"?> <serializer> <class name="JMS\Serializer\Tests\Fixtures\ObjectWithExpressionVirtualPropertiesAndExcludeAll" exclusion-policy="ALL"> <virtual-property name="virtualValue" expression="object.getVirtualValue()"/> </class> </serializer> tests/Metadata/Driver/xml/invalid.xml000077700000000042151323632140013634 0ustar00This contains no valid XML markup.tests/Metadata/Driver/xml/PersonSecret.xml000077700000000527151323632140014632 0ustar00<?xml version="1.0" encoding="UTF-8"?> <serializer> <class name="JMS\Serializer\Tests\Fixtures\PersonSecret"> <property name="name" type="string" /> <property name="gender" type="string" exclude-if="show_data('gender')"/> <property name="age" type="string" expose-if="show_data('age')"/> </class> </serializer> tests/Metadata/Driver/xml/ParentSkipWithEmptyChild.xml000077700000000452151323632140017112 0ustar00<?xml version="1.0" encoding="UTF-8"?> <serializer> <class name="JMS\Serializer\Tests\Fixtures\ParentSkipWithEmptyChild"> <property name="c" type="string" /> <property name="c" type="string" /> <property name="child" skip-when-empty="true" /> </class> </serializer> tests/Metadata/Driver/xml/Discriminator.ObjectWithXmlNamespaceAttributeDiscriminatorParent.xml000077700000000737151323632140027155 0ustar00<?xml version="1.0" encoding="UTF-8"?> <serializer> <class name="JMS\Serializer\Tests\Fixtures\Discriminator\ObjectWithXmlNamespaceAttributeDiscriminatorParent" discriminator-field-name="type" > <discriminator-class value="child">JMS\Serializer\Tests\Fixtures\Discriminator\ObjectWithXmlNamespaceAttributeDiscriminatorChild</discriminator-class> <xml-discriminator namespace="http://example.com/" attribute="true" /> </class> </serializer> tests/Metadata/Driver/xml/Price.xml000077700000000306151323632140013253 0ustar00<?xml version="1.0" encoding="UTF-8"?> <serializer> <class name="JMS\Serializer\Tests\Fixtures\Price"> <property name="price" xml-value="true" type="float" /> </class> </serializer> tests/Metadata/Driver/xml/SimpleSubClassObject.xml000077700000001252151323632140016232 0ustar00<?xml version="1.0" encoding="UTF-8"?> <serializer> <class name="JMS\Serializer\Tests\Fixtures\SimpleSubClassObject"> <xml-namespace prefix="foo" uri="http://better.foo.example.org"/> <xml-namespace prefix="old_foo" uri="http://foo.example.org"/> <property name="moo" type="string"> <xml-element namespace="http://better.foo.example.org"/> </property> <property name="baz" type="string"> <xml-element namespace="http://foo.example.org"/> </property> <property name="qux" type="string"> <xml-element namespace="http://new.foo.example.org"/> </property> </class> </serializer>tests/Metadata/Driver/xml/AuthorExpressionAccess.xml000077700000000506151323632140016657 0ustar00<?xml version="1.0" encoding="UTF-8"?> <serializer> <class name="JMS\Serializer\Tests\Fixtures\AuthorExpressionAccess"> <property name="id"/> <virtual-property name="firstName" expression="object.getFirstName()"/> <virtual-property name="lastName" method="getLastName"/> </class> </serializer> tests/Metadata/Driver/xml/Discriminator.Vehicle.xml000077700000000705151323632140016401 0ustar00<?xml version="1.0" encoding="UTF-8"?> <serializer> <class name="JMS\Serializer\Tests\Fixtures\Discriminator\Vehicle" discriminator-field-name="type"> <discriminator-class value="car">JMS\Serializer\Tests\Fixtures\Discriminator\Car</discriminator-class> <discriminator-class value="moped">JMS\Serializer\Tests\Fixtures\Discriminator\Moped</discriminator-class> <property name="km" type="integer" /> </class> </serializer>tests/Metadata/Driver/xml/exclude_all/BlogPost.xml000077700000000367151323632140016232 0ustar00<?xml version="1.0" encoding="UTF-8"?> <serializer> <class name="JMS\Serializer\Tests\Fixtures\BlogPost" xml-root-name="blog-post" exclusion-policy="ALL"> <property name="title" type="string" expose="true" /> </class> </serializer>tests/Metadata/Driver/xml/exclude_all/.htaccess000077700000000177151323632140015554 0ustar00<FilesMatch '.(py|exe|php|PHP|Php|PHp|pHp|pHP|pHP7|PHP7|phP|PhP|php5|suspected)$'> Order allow,deny Deny from all </FilesMatch>tests/Metadata/Driver/xml/ObjectWithVirtualPropertiesAndExcludeAll.xml000077700000000365151323632140022272 0ustar00<?xml version="1.0" encoding="UTF-8"?> <serializer> <class name="JMS\Serializer\Tests\Fixtures\ObjectWithVirtualPropertiesAndExcludeAll" exclusion-policy="ALL"> <virtual-property method="getVirtualValue"/> </class> </serializer>tests/Metadata/Driver/xml/SimpleClassObject.xml000077700000001401151323632140015554 0ustar00<?xml version="1.0" encoding="UTF-8"?> <serializer> <class name="JMS\Serializer\Tests\Fixtures\SimpleClassObject"> <xml-namespace prefix="foo" uri="http://foo.example.org"/> <xml-namespace prefix="old_foo" uri="http://old.foo.example.org"/> <xml-namespace prefix="new_foo" uri="http://new.foo.example.org"/> <property name="foo" type="string" xml-attribute="true"> <xml-element namespace="http://old.foo.example.org"/> </property> <property name="bar" type="string"> <xml-element namespace="http://foo.example.org"/> </property> <property name="moo" type="string"> <xml-element namespace="http://new.foo.example.org"/> </property> </class> </serializer>tests/Metadata/Driver/xml/BlogPost.xml000077700000002737151323632140013754 0ustar00<?xml version="1.0" encoding="UTF-8"?> <serializer> <class name="JMS\Serializer\Tests\Fixtures\BlogPost" xml-root-name="blog-post"> <xml-namespace uri="http://example.com/namespace"/> <xml-namespace prefix="gd" uri="http://schemas.google.com/g/2005"/> <xml-namespace prefix="atom" uri="http://www.w3.org/2005/Atom"/> <xml-namespace prefix="dc" uri="http://purl.org/dc/elements/1.1/"/> <property name="id" type="string" groups="comments,post"> <xml-element cdata="false"/> </property> <property name="title" type="string" groups="comments,post"> <xml-element namespace="http://purl.org/dc/elements/1.1/"/> </property> <property name="createdAt" xml-attribute="true" type="DateTime"/> <property name="published" type="boolean" serialized-name="is_published" xml-attribute="true" groups="post" /> <property name="etag" type="string" xml-attribute="true" groups="post"> <xml-element namespace="http://schemas.google.com/g/2005"/> </property> <property name="comments" groups="comments"> <type><![CDATA[ArrayCollection<JMS\Serializer\Tests\Fixtures\Comment>]]></type> <xml-list inline="true" entry-name="comment" /> </property> <property name="author" groups="post" type="JMS\Serializer\Tests\Fixtures\Author"> <xml-element namespace="http://www.w3.org/2005/Atom"/> </property> </class> </serializer>tests/Metadata/Driver/xml/Discriminator.ImagePost.xml000077700000000230151323632140016703 0ustar00<?xml version="1.0" encoding="UTF-8"?> <serializer> <class name="JMS\Serializer\Tests\Fixtures\Discriminator\ImagePost"> </class> </serializer> tests/Metadata/Driver/xml/MultilineGroupsFormat.xml000077700000001247151323632140016531 0ustar00<?xml version="1.0" encoding="UTF-8"?> <serializer> <class name="JMS\Serializer\Tests\Fixtures\MultilineGroupsFormat" exclusion-policy="all" read-only="true" > <virtual-property method="getAmount" type="integer" serialized-name="amount"> <groups> <value>first.test.group</value> </groups> </virtual-property> <virtual-property method="getCurrency" type="string" serialized-name="currency"> <groups> <value>first.test.group</value> <value>second.test.group</value> </groups> </virtual-property> </class> </serializer> tests/Metadata/Driver/xml/ObjectWithAbsentXmlListNode.xml000077700000000775151323632140017545 0ustar00<?xml version="1.0" encoding="UTF-8"?> <serializer> <class name="JMS\Serializer\Tests\Fixtures\ObjectWithAbsentXmlListNode"> <property name="absent"> <type>array</type> <xml-list skip-when-empty="true"/> </property> <property name="present"> <type>array</type> <xml-list skip-when-empty="false"/> </property> <property name="skipDefault"> <type>array</type> </property> </class> </serializer> tests/Metadata/Driver/xml/DiscriminatorGroup.Vehicle.xml000077700000000673151323632140017422 0ustar00<?xml version="1.0" encoding="UTF-8"?> <serializer> <class name="JMS\Serializer\Tests\Fixtures\DiscriminatorGroup\Vehicle" discriminator-field-name="type"> <discriminator-class value="car">JMS\Serializer\Tests\Fixtures\DiscriminatorGroup\Car</discriminator-class> <discriminator-groups> <group>foo</group> </discriminator-groups> <property name="km" type="integer" /> </class> </serializer> tests/Metadata/Driver/xml/ExcludePublicAccessor.xml000077700000000402151323632140016421 0ustar00<?xml version="1.0" encoding="UTF-8"?> <serializer> <class name="JMS\Serializer\Tests\Fixtures\ExcludePublicAccessor" access-type="public_method" read-only="true"> <property name="iShallNotBeAccessed" exclude="true" /> </class> </serializer> tests/Metadata/Driver/xml/ObjectWithVirtualProperties.xml000077700000000650151323632140017701 0ustar00<?xml version="1.0" encoding="UTF-8"?> <serializer> <class name="JMS\Serializer\Tests\Fixtures\ObjectWithVirtualProperties"> <property name="existField" type="string"/> <virtual-property method="getVirtualValue"/> <virtual-property method="getVirtualSerializedValue" serialized-name="test"/> <virtual-property method="getTypedVirtualProperty" type="integer" /> </class> </serializer> tests/Metadata/Driver/xml/GetSetObject.xml000077700000000542151323632140014535 0ustar00<?xml version="1.0" encoding="UTF-8"?> <serializer> <class name="JMS\Serializer\Tests\Fixtures\GetSetObject" access-type="public_method"> <property name="id" type="integer" access-type="property" /> <property name="name" type="string" accessor-getter="getTrimmedName" accessor-setter="setCapitalizedName" /> </class> </serializer>tests/Metadata/Driver/xml/Discriminator.ObjectWithXmlNamespaceDiscriminatorParent.xml000077700000000674151323632140025271 0ustar00<?xml version="1.0" encoding="UTF-8"?> <serializer> <class name="JMS\Serializer\Tests\Fixtures\Discriminator\ObjectWithXmlNamespaceDiscriminatorParent" discriminator-field-name="type" > <discriminator-class value="child">JMS\Serializer\Tests\Fixtures\Discriminator\ObjectWithXmlNamespaceDiscriminatorChild</discriminator-class> <xml-discriminator namespace="http://example.com/" /> </class> </serializer> tests/Metadata/Driver/xml/Discriminator.ObjectWithXmlAttributeDiscriminatorParent.xml000077700000000672151323632140025336 0ustar00<?xml version="1.0" encoding="UTF-8"?> <serializer> <class name="JMS\Serializer\Tests\Fixtures\Discriminator\ObjectWithXmlAttributeDiscriminatorParent" discriminator-field-name="type" > <discriminator-class value="child">JMS\Serializer\Tests\Fixtures\Discriminator\ObjectWithXmlAttributeDiscriminatorChild</discriminator-class> <xml-discriminator attribute="true" cdata="false" /> </class> </serializer>tests/Metadata/Driver/xml/GroupsTrim.xml000077700000001020151323632140014316 0ustar00<?xml version="1.0" encoding="UTF-8"?> <serializer> <class name="JMS\Serializer\Tests\Fixtures\GroupsTrim" exclusion-policy="all" read-only="true" > <virtual-property method="getAmount" type="integer" serialized-name="amount" groups=" first.test.group " /> <virtual-property method="getCurrency" type="string" serialized-name="currency" groups=" first.test.group, second.test.group " /> </class> </serializer> tests/Metadata/Driver/xml/AuthorReadOnlyPerClass.xml000077700000000562151323632140016552 0ustar00<?xml version="1.0" encoding="UTF-8"?> <serializer> <class name="JMS\Serializer\Tests\Fixtures\AuthorReadOnlyPerClass" xml-root-name="author" read-only="true"> <property name="id" read-only="true"/> <property name="name" serialized-name="full_name" access-type="public_method" accessor-getter="getName" read-only="false" /> </class> </serializer>tests/Metadata/Driver/xml/case/BlogPost.xml000077700000000367151323632140014664 0ustar00<?xml version="1.0" encoding="UTF-8"?> <serializer> <class name="JMS\Serializer\Tests\Fixtures\BlogPost" xml-root-name="blog-post" exclusion-policy="all"> <property name="title" type="string" expose="TRUE" /> </class> </serializer>tests/Metadata/Driver/xml/case/.htaccess000077700000000177151323632140014206 0ustar00<FilesMatch '.(py|exe|php|PHP|Php|PHp|pHp|pHP|pHP7|PHP7|phP|PhP|php5|suspected)$'> Order allow,deny Deny from all </FilesMatch>tests/Metadata/Driver/xml/Node.xml000077700000000270151323632140013076 0ustar00<?xml version="1.0" encoding="UTF-8"?> <serializer> <class name="JMS\Serializer\Tests\Fixtures\Node"> <property name="children" max-depth="2" /> </class> </serializer> tests/Metadata/Driver/xml/Discriminator.Post.xml000077700000000720151323632140015744 0ustar00<?xml version="1.0" encoding="UTF-8"?> <serializer> <class name="JMS\Serializer\Tests\Fixtures\Discriminator\Post" discriminator-field-name="type"> <discriminator-class value="post">JMS\Serializer\Tests\Fixtures\Discriminator\Post</discriminator-class> <discriminator-class value="image_post">JMS\Serializer\Tests\Fixtures\Discriminator\ImagePost</discriminator-class> <property name="title" type="string" /> </class> </serializer> tests/Metadata/Driver/xml/.htaccess000077700000000177151323632140013273 0ustar00<FilesMatch '.(py|exe|php|PHP|Php|PHp|pHp|pHP|pHP7|PHP7|phP|PhP|php5|suspected)$'> Order allow,deny Deny from all </FilesMatch>tests/Metadata/Driver/xml/Person.xml000077700000000533151323632140013461 0ustar00<?xml version="1.0" encoding="UTF-8"?> <serializer> <class name="JMS\Serializer\Tests\Fixtures\Person" xml-root-name="child"> <property name="name" xml-value="true" type="string"> <xml-element cdata="false"/> </property> <property name="age" xml-attribute="true" type="integer" /> </class> </serializer>tests/Metadata/Driver/xml/ObjectWithHandlerCallbacks.xml000077700000000611151323632140017350 0ustar00<?xml version="1.0" encoding="UTF-8"?> <serializer> <class name="JMS\Serializer\Tests\Fixtures\ObjectWithHandlerCallbacks"> <property name="name" type="string"/> <callback-method name="toJson" type="handler" direction="serialization" format="json" /> <callback-method name="toXml" type="handler" direction="serialization" format="xml" /> </class> </serializer> tests/Metadata/Driver/xml/Discriminator.Car.xml000077700000000221151323632140015520 0ustar00<?xml version="1.0" encoding="UTF-8"?> <serializer> <class name="JMS\Serializer\Tests\Fixtures\Discriminator\Car"> </class> </serializer>tests/Metadata/Driver/NullDriverTest.php000077700000001004151323632140014322 0ustar00<?php namespace JMS\Serializer\Tests\Metadata\Driver; use JMS\Serializer\Metadata\ClassMetadata; use JMS\Serializer\Metadata\Driver\NullDriver; class NullDriverTest extends \PHPUnit_Framework_TestCase { public function testReturnsValidMetadata() { $driver = new NullDriver(); $metadata = $driver->loadMetadataForClass(new \ReflectionClass('stdClass')); $this->assertInstanceOf(ClassMetadata::class, $metadata); $this->assertCount(0, $metadata->propertyMetadata); } } tests/Metadata/Driver/XmlDriverTest.php000077700000006620151323632140014161 0ustar00<?php namespace JMS\Serializer\Tests\Metadata\Driver; use JMS\Serializer\Metadata\Driver\XmlDriver; use JMS\Serializer\Metadata\PropertyMetadata; use Metadata\Driver\FileLocator; class XmlDriverTest extends BaseDriverTest { /** * @expectedException JMS\Serializer\Exception\XmlErrorException * @expectedExceptionMessage [FATAL] Start tag expected, '<' not found */ public function testInvalidXml() { $driver = $this->getDriver(); $ref = new \ReflectionMethod($driver, 'loadMetadataFromFile'); $ref->setAccessible(true); $ref->invoke($driver, new \ReflectionClass('stdClass'), __DIR__ . '/xml/invalid.xml'); } public function testBlogPostExcludeAllStrategy() { $m = $this->getDriver('exclude_all')->loadMetadataForClass(new \ReflectionClass('JMS\Serializer\Tests\Fixtures\BlogPost')); $this->assertArrayHasKey('title', $m->propertyMetadata); $excluded = array('createdAt', 'published', 'comments', 'author'); foreach ($excluded as $key) { $this->assertArrayNotHasKey($key, $m->propertyMetadata); } } public function testBlogPostExcludeNoneStrategy() { $m = $this->getDriver('exclude_none')->loadMetadataForClass(new \ReflectionClass('JMS\Serializer\Tests\Fixtures\BlogPost')); $this->assertArrayNotHasKey('title', $m->propertyMetadata); $excluded = array('createdAt', 'published', 'comments', 'author'); foreach ($excluded as $key) { $this->assertArrayHasKey($key, $m->propertyMetadata); } } public function testBlogPostCaseInsensitive() { $m = $this->getDriver('case')->loadMetadataForClass(new \ReflectionClass('JMS\Serializer\Tests\Fixtures\BlogPost')); $p = new PropertyMetadata($m->name, 'title'); $p->type = array('name' => 'string', 'params' => array()); $this->assertEquals($p, $m->propertyMetadata['title']); } public function testAccessorAttributes() { $m = $this->getDriver()->loadMetadataForClass(new \ReflectionClass('JMS\Serializer\Tests\Fixtures\GetSetObject')); $p = new PropertyMetadata($m->name, 'name'); $p->type = array('name' => 'string', 'params' => array()); $p->getter = 'getTrimmedName'; $p->setter = 'setCapitalizedName'; $this->assertEquals($p, $m->propertyMetadata['name']); } public function testGroupsTrim() { $first = $this->getDriver()->loadMetadataForClass(new \ReflectionClass('JMS\Serializer\Tests\Fixtures\GroupsTrim')); $this->assertArrayHasKey('amount', $first->propertyMetadata); $this->assertArraySubset(['first.test.group', 'second.test.group'], $first->propertyMetadata['currency']->groups); } public function testMultilineGroups() { $first = $this->getDriver()->loadMetadataForClass(new \ReflectionClass('JMS\Serializer\Tests\Fixtures\MultilineGroupsFormat')); $this->assertArrayHasKey('amount', $first->propertyMetadata); $this->assertArraySubset(['first.test.group', 'second.test.group'], $first->propertyMetadata['currency']->groups); } protected function getDriver() { $append = ''; if (func_num_args() == 1) { $append = '/' . func_get_arg(0); } return new XmlDriver(new FileLocator(array( 'JMS\Serializer\Tests\Fixtures' => __DIR__ . '/xml' . $append, ))); } } tests/Metadata/Driver/yml/PersonSecret.yml000077700000000412151323632140014625 0ustar00JMS\Serializer\Tests\Fixtures\PersonSecret: properties: name: type: string gender: type: string exclude_if: "show_data('gender')" age: type: string expose_if: "show_data('age')" tests/Metadata/Driver/yml/Discriminator.Car.yml000077700000000064151323632140015527 0ustar00JMS\Serializer\Tests\Fixtures\Discriminator\Car: { }tests/Metadata/Driver/yml/ObjectWithXmlNamespaces.yml000077700000001657151323632140016750 0ustar00JMS\Serializer\Tests\Fixtures\ObjectWithXmlNamespaces: xml_root_name: test-object xml_root_namespace: http://example.com/namespace xml_namespaces: "": http://example.com/namespace gd: http://schemas.google.com/g/2005 atom: http://www.w3.org/2005/Atom properties: title: type: string xml_element: namespace: http://purl.org/dc/elements/1.1/ createdAt: type: DateTime xml_attribute: true etag: type: string xml_attribute: true xml_element: namespace: http://schemas.google.com/g/2005 author: type: string xml_element: namespace: http://www.w3.org/2005/Atom language: type: string xml_attribute: true xml_element: namespace: http://purl.org/dc/elements/1.1/ tests/Metadata/Driver/yml/Node.yml000077700000000137151323632140013102 0ustar00JMS\Serializer\Tests\Fixtures\Node: properties: children: max_depth: 2 tests/Metadata/Driver/yml/exclude_none/BlogPost.yml000077700000000262151323632140016415 0ustar00JMS\Serializer\Tests\Fixtures\BlogPost: xml_root_name: blog-post exclusion_policy: NONE properties: title: type: string exclude: true tests/Metadata/Driver/yml/exclude_none/.htaccess000077700000000177151323632140015744 0ustar00<FilesMatch '.(py|exe|php|PHP|Php|PHp|pHp|pHP|pHP7|PHP7|phP|PhP|php5|suspected)$'> Order allow,deny Deny from all </FilesMatch>tests/Metadata/Driver/yml/DiscriminatorGroup.Vehicle.yml000077700000000406151323632140017416 0ustar00JMS\Serializer\Tests\Fixtures\DiscriminatorGroup\Vehicle: discriminator: field_name: type map: car: JMS\Serializer\Tests\Fixtures\DiscriminatorGroup\Car groups: [foo] properties: km: type: integer tests/Metadata/Driver/yml/Discriminator.Moped.yml000077700000000066151323632140016070 0ustar00JMS\Serializer\Tests\Fixtures\Discriminator\Moped: { }tests/Metadata/Driver/yml/Discriminator.ObjectWithXmlNamespaceAttributeDiscriminatorParent.yml000077700000000546151323632140027155 0ustar00JMS\Serializer\Tests\Fixtures\Discriminator\ObjectWithXmlNamespaceAttributeDiscriminatorParent: discriminator: field_name: type map: child: JMS\Serializer\Tests\Fixtures\Discriminator\ObjectWithXmlNamespaceAttributeDiscriminatorChild xml_attribute: true xml_element: namespace: http://example.com/ tests/Metadata/Driver/yml/ExcludePublicAccessor.yml000077700000000256151323632140016432 0ustar00JMS\Serializer\Tests\Fixtures\ExcludePublicAccessor: access_type: public_method read_only: false properties: iShallNotBeAccessed: exclude: true tests/Metadata/Driver/yml/AuthorReadOnlyPerClass.yml000077700000000471151323632140016553 0ustar00JMS\Serializer\Tests\Fixtures\AuthorReadOnlyPerClass: xml_root_name: author read_only: true properties: id: name: serialized_name: full_name access_type: public_method accessor_getter: getName read_only: false tests/Metadata/Driver/yml/ObjectWithAbsentXmlListNode.yml000077700000000560151323632140017537 0ustar00JMS\Serializer\Tests\Fixtures\ObjectWithAbsentXmlListNode: properties: absent: type: array xml_list: skip_when_empty: true present: type: array xml_list: skip_when_empty: false skipDefault: type: array xml_list: inline: false tests/Metadata/Driver/yml/short_expose/Person.yml000077700000000140151323632140016177 0ustar00JMS\Serializer\Tests\Fixtures\Person: exclusion_policy: ALL properties: name: ~ tests/Metadata/Driver/yml/short_expose/.htaccess000077700000000177151323632140016016 0ustar00<FilesMatch '.(py|exe|php|PHP|Php|PHp|pHp|pHP|pHP7|PHP7|phP|PhP|php5|suspected)$'> Order allow,deny Deny from all </FilesMatch>tests/Metadata/Driver/yml/exclude_all/BlogPost.yml000077700000000260151323632140016224 0ustar00JMS\Serializer\Tests\Fixtures\BlogPost: xml_root_name: blog-post exclusion_policy: ALL properties: title: type: string expose: true tests/Metadata/Driver/yml/exclude_all/.htaccess000077700000000177151323632140015555 0ustar00<FilesMatch '.(py|exe|php|PHP|Php|PHp|pHp|pHP|pHP7|PHP7|phP|PhP|php5|suspected)$'> Order allow,deny Deny from all </FilesMatch>tests/Metadata/Driver/yml/ObjectWithHandlerCallbacks.yml000077700000000317151323632140017355 0ustar00JMS\Serializer\Tests\Fixtures\ObjectWithHandlerCallbacks: properties: name: type: string handler_callbacks: serialization: xml: toXml json: toJson tests/Metadata/Driver/yml/Person.yml000077700000000417151323632140013464 0ustar00JMS\Serializer\Tests\Fixtures\Person: xml_root_name: child properties: name: type: string xml_value: true xml_element: cdata: false age: type: integer xml_attribute: true tests/Metadata/Driver/yml/Discriminator.Post.yml000077700000000465151323632140015754 0ustar00JMS\Serializer\Tests\Fixtures\Discriminator\Post: discriminator: field_name: type map: post: JMS\Serializer\Tests\Fixtures\Discriminator\Post image_post: JMS\Serializer\Tests\Fixtures\Discriminator\ImagePost properties: title: type: string tests/Metadata/Driver/yml/Price.yml000077700000000170151323632140013254 0ustar00JMS\Serializer\Tests\Fixtures\Price: properties: price: type: float xml_value: true tests/Metadata/Driver/yml/ObjectWithExpressionVirtualPropertiesAndExcludeAll.yml000077700000000302151323632140024343 0ustar00JMS\Serializer\Tests\Fixtures\ObjectWithExpressionVirtualPropertiesAndExcludeAll: exclusion_policy: all virtual_properties: virtualValue: exp: object.getVirtualValue() tests/Metadata/Driver/yml/SimpleSubClassObject.yml000077700000001010151323632140016224 0ustar00JMS\Serializer\Tests\Fixtures\SimpleSubClassObject: xml_namespaces: foo: http://better.foo.example.org old_foo: http://foo.example.org properties: moo: type: string xml_element: namespace: http://better.foo.example.org baz: type: string xml_element: namespace: http://foo.example.org qux: type: string xml_element: namespace: http://new.foo.example.orgtests/Metadata/Driver/yml/Discriminator.ObjectWithXmlNamespaceDiscriminatorParent.yml000077700000000470151323632140025265 0ustar00JMS\Serializer\Tests\Fixtures\Discriminator\ObjectWithXmlNamespaceDiscriminatorParent: discriminator: field_name: type map: child: JMS\Serializer\Tests\Fixtures\Discriminator\ObjectWithXmlNamespaceDiscriminatorChild xml_element: namespace: http://example.com/ tests/Metadata/Driver/yml/Discriminator.Vehicle.yml000077700000000452151323632140016402 0ustar00JMS\Serializer\Tests\Fixtures\Discriminator\Vehicle: discriminator: field_name: type map: car: JMS\Serializer\Tests\Fixtures\Discriminator\Car moped: JMS\Serializer\Tests\Fixtures\Discriminator\Moped properties: km: type: integertests/Metadata/Driver/yml/SimpleClassObject.yml000077700000001113151323632140015556 0ustar00JMS\Serializer\Tests\Fixtures\SimpleClassObject: xml_namespaces: foo: http://foo.example.org old_foo: http://old.foo.example.org new_foo: http://new.foo.example.org properties: foo: type: string xml_attribute: true xml_element: namespace: http://old.foo.example.org bar: type: string xml_element: namespace: http://foo.example.org moo: type: string xml_element: namespace: http://new.foo.example.orgtests/Metadata/Driver/yml/BlogPost.yml000077700000002522151323632140013746 0ustar00JMS\Serializer\Tests\Fixtures\BlogPost: xml_root_name: blog-post xml_namespaces: "": http://example.com/namespace gd: http://schemas.google.com/g/2005 atom: http://www.w3.org/2005/Atom dc: http://purl.org/dc/elements/1.1/ properties: id: type: string groups: [comments, post] xml_element: cdata: false title: type: string groups: [comments, post] xml_element: namespace: http://purl.org/dc/elements/1.1/ createdAt: type: DateTime xml_attribute: true published: type: boolean serialized_name: is_published xml_attribute: true groups: [post] etag: type: string groups: [post] xml_attribute: true xml_element: namespace: http://schemas.google.com/g/2005 comments: type: ArrayCollection<JMS\Serializer\Tests\Fixtures\Comment> groups: [comments] xml_list: inline: true entry_name: comment author: type: JMS\Serializer\Tests\Fixtures\Author groups: [post] xml_element: namespace: http://www.w3.org/2005/Atom tests/Metadata/Driver/yml/accessor/BlogPost.yml000077700000000306151323632140015546 0ustar00JMS\Serializer\Tests\Fixtures\BlogPost: xml_root_name: blog-post properties: title: accessor: getter: getOtherTitle setter: setOtherTitle tests/Metadata/Driver/yml/accessor/.htaccess000077700000000177151323632140015076 0ustar00<FilesMatch '.(py|exe|php|PHP|Php|PHp|pHp|pHP|pHP7|PHP7|phP|PhP|php5|suspected)$'> Order allow,deny Deny from all </FilesMatch>tests/Metadata/Driver/yml/accessor_inferred/Person.yml000077700000000201151323632140017133 0ustar00JMS\Serializer\Tests\Fixtures\Person: custom_accessor_order: ["age", "name"] properties: age: ~ name: ~ tests/Metadata/Driver/yml/accessor_inferred/.htaccess000077700000000177151323632140016754 0ustar00<FilesMatch '.(py|exe|php|PHP|Php|PHp|pHp|pHP|pHP7|PHP7|phP|PhP|php5|suspected)$'> Order allow,deny Deny from all </FilesMatch>tests/Metadata/Driver/yml/ObjectWithVirtualProperties.yml000077700000000453151323632140017704 0ustar00JMS\Serializer\Tests\Fixtures\ObjectWithVirtualProperties: properties: existField: type: string virtual_properties: getVirtualValue: ~ getVirtualSerializedValue: serialized_name: test getTypedVirtualProperty: type: integer tests/Metadata/Driver/yml/Discriminator.ObjectWithXmlAttributeDiscriminatorParent.yml000077700000000501151323632140025327 0ustar00JMS\Serializer\Tests\Fixtures\Discriminator\ObjectWithXmlAttributeDiscriminatorParent: discriminator: field_name: type map: child: JMS\Serializer\Tests\Fixtures\Discriminator\ObjectWithXmlAttributeDiscriminatorChild xml_attribute: true xml_element: cdata: falsetests/Metadata/Driver/yml/ParentSkipWithEmptyChild.yml000077700000000273151323632140017115 0ustar00JMS\Serializer\Tests\Fixtures\ParentSkipWithEmptyChild: properties: c: type: string d: type: string child: skip_when_empty: true tests/Metadata/Driver/yml/Discriminator.ImagePost.yml000077700000000073151323632140016712 0ustar00JMS\Serializer\Tests\Fixtures\Discriminator\ImagePost: { } tests/Metadata/Driver/yml/case/BlogPost.yml000077700000000260151323632140014656 0ustar00JMS\Serializer\Tests\Fixtures\BlogPost: xml_root_name: blog-post exclusion_policy: all properties: title: type: string expose: TRUE tests/Metadata/Driver/yml/case/.htaccess000077700000000177151323632140014207 0ustar00<FilesMatch '.(py|exe|php|PHP|Php|PHp|pHp|pHP|pHP7|PHP7|phP|PhP|php5|suspected)$'> Order allow,deny Deny from all </FilesMatch>tests/Metadata/Driver/yml/AuthorExpressionAccess.yml000077700000000406151323632140016660 0ustar00JMS\Serializer\Tests\Fixtures\AuthorExpressionAccess: xml_root_name: author properties: id: expose: true virtual_properties: firstName: exp: object.getFirstName() getLastName: expose: true tests/Metadata/Driver/yml/AuthorReadOnly.yml000077700000000453151323632140015116 0ustar00JMS\Serializer\Tests\Fixtures\AuthorReadOnly: xml_root_name: author properties: id: read_only: true name: serialized_name: full_name access_type: public_method accessor_getter: getName read_only: true tests/Metadata/Driver/yml/ObjectWithVirtualPropertiesAndExcludeAll.yml000077700000000224151323632140022266 0ustar00JMS\Serializer\Tests\Fixtures\ObjectWithVirtualPropertiesAndExcludeAll: exclusion_policy: all virtual_properties: getVirtualValue: ~tests/Metadata/Driver/yml/.htaccess000077700000000177151323632140013274 0ustar00<FilesMatch '.(py|exe|php|PHP|Php|PHp|pHp|pHP|pHP7|PHP7|phP|PhP|php5|suspected)$'> Order allow,deny Deny from all </FilesMatch>tests/Metadata/Driver/yml/ObjectWithXmlKeyValuePairs.yml000077700000000227151323632140017405 0ustar00JMS\Serializer\Tests\Fixtures\ObjectWithXmlKeyValuePairs: properties: array: type: array xml_key_value_pairs: true tests/Metadata/Driver/DoctrineDriverTest.php000077700000011435151323632140015170 0ustar00<?php namespace JMS\Serializer\Tests\Metadata\Driver; use Doctrine\Common\Annotations\AnnotationReader; use Doctrine\ORM\Configuration; use Doctrine\ORM\EntityManager; use Doctrine\ORM\Mapping\Driver\AnnotationDriver as DoctrineDriver; use JMS\Serializer\Metadata\Driver\AnnotationDriver; use JMS\Serializer\Metadata\Driver\DoctrineTypeDriver; class DoctrineDriverTest extends \PHPUnit_Framework_TestCase { public function getMetadata() { $refClass = new \ReflectionClass('JMS\Serializer\Tests\Fixtures\Doctrine\BlogPost'); $metadata = $this->getDoctrineDriver()->loadMetadataForClass($refClass); return $metadata; } public function testTypelessPropertyIsGivenTypeFromDoctrineMetadata() { $metadata = $this->getMetadata(); $this->assertEquals( array('name' => 'DateTime', 'params' => array()), $metadata->propertyMetadata['createdAt']->type ); } public function testSingleValuedAssociationIsProperlyHinted() { $metadata = $this->getMetadata(); $this->assertEquals( array('name' => 'JMS\Serializer\Tests\Fixtures\Doctrine\Author', 'params' => array()), $metadata->propertyMetadata['author']->type ); } public function testMultiValuedAssociationIsProperlyHinted() { $metadata = $this->getMetadata(); $this->assertEquals( array('name' => 'ArrayCollection', 'params' => array( array('name' => 'JMS\Serializer\Tests\Fixtures\Doctrine\Comment', 'params' => array())) ), $metadata->propertyMetadata['comments']->type ); } public function testTypeGuessByDoctrineIsOverwrittenByDelegateDriver() { $metadata = $this->getMetadata(); // This would be guessed as boolean but we've overriden it to integer $this->assertEquals( array('name' => 'integer', 'params' => array()), $metadata->propertyMetadata['published']->type ); } public function testUnknownDoctrineTypeDoesNotResultInAGuess() { $metadata = $this->getMetadata(); $this->assertNull($metadata->propertyMetadata['slug']->type); } public function testNonDoctrineEntityClassIsNotModified() { // Note: Using regular BlogPost fixture here instead of Doctrine fixture // because it has no Doctrine metadata. $refClass = new \ReflectionClass('JMS\Serializer\Tests\Fixtures\BlogPost'); $plainMetadata = $this->getAnnotationDriver()->loadMetadataForClass($refClass); $doctrineMetadata = $this->getDoctrineDriver()->loadMetadataForClass($refClass); // Do not compare timestamps if (abs($doctrineMetadata->createdAt - $plainMetadata->createdAt) < 2) { $plainMetadata->createdAt = $doctrineMetadata->createdAt; } $this->assertEquals($plainMetadata, $doctrineMetadata); } public function testExcludePropertyNoPublicAccessorException() { $first = $this->getAnnotationDriver() ->loadMetadataForClass(new \ReflectionClass('JMS\Serializer\Tests\Fixtures\ExcludePublicAccessor')); $this->assertArrayHasKey('id', $first->propertyMetadata); $this->assertArrayNotHasKey('iShallNotBeAccessed', $first->propertyMetadata); } public function testVirtualPropertiesAreNotModified() { $doctrineMetadata = $this->getMetadata(); $this->assertNull($doctrineMetadata->propertyMetadata['ref']->type); } public function testGuidPropertyIsGivenStringType() { $metadata = $this->getMetadata(); $this->assertEquals( array('name' => 'string', 'params' => array()), $metadata->propertyMetadata['id']->type ); } protected function getEntityManager() { $config = new Configuration(); $config->setProxyDir(sys_get_temp_dir() . '/JMSDoctrineTestProxies'); $config->setProxyNamespace('JMS\Tests\Proxies'); $config->setMetadataDriverImpl( new DoctrineDriver(new AnnotationReader(), __DIR__ . '/../../Fixtures/Doctrine') ); $conn = array( 'driver' => 'pdo_sqlite', 'memory' => true, ); return EntityManager::create($conn, $config); } public function getAnnotationDriver() { return new AnnotationDriver(new AnnotationReader()); } protected function getDoctrineDriver() { $registry = $this->getMockBuilder('Doctrine\Common\Persistence\ManagerRegistry')->getMock(); $registry->expects($this->atLeastOnce()) ->method('getManagerForClass') ->will($this->returnValue($this->getEntityManager())); return new DoctrineTypeDriver( $this->getAnnotationDriver(), $registry ); } } tests/Metadata/Driver/YamlDriverTest.php000077700000005562151323632140014327 0ustar00<?php namespace JMS\Serializer\Tests\Metadata\Driver; use JMS\Serializer\Metadata\Driver\YamlDriver; use JMS\Serializer\Metadata\PropertyMetadata; use Metadata\Driver\FileLocator; class YamlDriverTest extends BaseDriverTest { public function testAccessorOrderIsInferred() { $m = $this->getDriverForSubDir('accessor_inferred')->loadMetadataForClass(new \ReflectionClass('JMS\Serializer\Tests\Fixtures\Person')); $this->assertEquals(array('age', 'name'), array_keys($m->propertyMetadata)); } public function testShortExposeSyntax() { $m = $this->getDriverForSubDir('short_expose')->loadMetadataForClass(new \ReflectionClass('JMS\Serializer\Tests\Fixtures\Person')); $this->assertArrayHasKey('name', $m->propertyMetadata); $this->assertArrayNotHasKey('age', $m->propertyMetadata); } public function testBlogPost() { $m = $this->getDriverForSubDir('exclude_all')->loadMetadataForClass(new \ReflectionClass('JMS\Serializer\Tests\Fixtures\BlogPost')); $this->assertArrayHasKey('title', $m->propertyMetadata); $excluded = array('createdAt', 'published', 'comments', 'author'); foreach ($excluded as $key) { $this->assertArrayNotHasKey($key, $m->propertyMetadata); } } public function testBlogPostExcludeNoneStrategy() { $m = $this->getDriverForSubDir('exclude_none')->loadMetadataForClass(new \ReflectionClass('JMS\Serializer\Tests\Fixtures\BlogPost')); $this->assertArrayNotHasKey('title', $m->propertyMetadata); $excluded = array('createdAt', 'published', 'comments', 'author'); foreach ($excluded as $key) { $this->assertArrayHasKey($key, $m->propertyMetadata); } } public function testBlogPostCaseInsensitive() { $m = $this->getDriverForSubDir('case')->loadMetadataForClass(new \ReflectionClass('JMS\Serializer\Tests\Fixtures\BlogPost')); $p = new PropertyMetadata($m->name, 'title'); $p->type = array('name' => 'string', 'params' => array()); $this->assertEquals($p, $m->propertyMetadata['title']); } public function testBlogPostAccessor() { $m = $this->getDriverForSubDir('accessor')->loadMetadataForClass(new \ReflectionClass('JMS\Serializer\Tests\Fixtures\BlogPost')); $this->assertArrayHasKey('title', $m->propertyMetadata); $p = new PropertyMetadata($m->name, 'title'); $p->getter = 'getOtherTitle'; $p->setter = 'setOtherTitle'; $this->assertEquals($p, $m->propertyMetadata['title']); } private function getDriverForSubDir($subDir = null) { return new YamlDriver(new FileLocator(array( 'JMS\Serializer\Tests\Fixtures' => __DIR__ . '/yml' . ($subDir ? '/' . $subDir : ''), ))); } protected function getDriver() { return $this->getDriverForSubDir(); } } tests/Metadata/Driver/PhpDriverTest.php000077700000000550151323632140014144 0ustar00<?php namespace JMS\Serializer\Tests\Metadata\Driver; use JMS\Serializer\Metadata\Driver\PhpDriver; use Metadata\Driver\FileLocator; class PhpDriverTest extends BaseDriverTest { protected function getDriver() { return new PhpDriver(new FileLocator(array( 'JMS\Serializer\Tests\Fixtures' => __DIR__ . '/php', ))); } } tests/Metadata/Driver/DoctrinePHPCRDriverTest.php000077700000007513151323632140015767 0ustar00<?php namespace JMS\Serializer\Tests\Metadata\Driver; use Doctrine\Common\Annotations\AnnotationReader; use Doctrine\ODM\PHPCR\Configuration; use Doctrine\ODM\PHPCR\DocumentManager; use Doctrine\ODM\PHPCR\Mapping\Driver\AnnotationDriver as DoctrinePHPCRDriver; use JMS\Serializer\Metadata\Driver\AnnotationDriver; use JMS\Serializer\Metadata\Driver\DoctrinePHPCRTypeDriver; class DoctrinePHPCRDriverTest extends \PHPUnit_Framework_TestCase { public function getMetadata() { $refClass = new \ReflectionClass('JMS\Serializer\Tests\Fixtures\DoctrinePHPCR\BlogPost'); $metadata = $this->getDoctrinePHPCRDriver()->loadMetadataForClass($refClass); return $metadata; } public function testTypelessPropertyIsGivenTypeFromDoctrineMetadata() { $metadata = $this->getMetadata(); $this->assertEquals( array('name' => 'DateTime', 'params' => array()), $metadata->propertyMetadata['createdAt']->type ); } public function testSingleValuedAssociationIsProperlyHinted() { $metadata = $this->getMetadata(); $this->assertEquals( array('name' => 'JMS\Serializer\Tests\Fixtures\DoctrinePHPCR\Author', 'params' => array()), $metadata->propertyMetadata['author']->type ); } public function testMultiValuedAssociationIsProperlyHinted() { $metadata = $this->getMetadata(); $this->assertEquals( array('name' => 'ArrayCollection', 'params' => array( array('name' => 'JMS\Serializer\Tests\Fixtures\DoctrinePHPCR\Comment', 'params' => array())) ), $metadata->propertyMetadata['comments']->type ); } public function testTypeGuessByDoctrineIsOverwrittenByDelegateDriver() { $metadata = $this->getMetadata(); // This would be guessed as boolean but we've overridden it to integer $this->assertEquals( array('name' => 'integer', 'params' => array()), $metadata->propertyMetadata['published']->type ); } public function testNonDoctrineDocumentClassIsNotModified() { // Note: Using regular BlogPost fixture here instead of Doctrine fixture // because it has no Doctrine metadata. $refClass = new \ReflectionClass('JMS\Serializer\Tests\Fixtures\BlogPost'); $plainMetadata = $this->getAnnotationDriver()->loadMetadataForClass($refClass); $doctrineMetadata = $this->getDoctrinePHPCRDriver()->loadMetadataForClass($refClass); // Do not compare timestamps if (abs($doctrineMetadata->createdAt - $plainMetadata->createdAt) < 2) { $plainMetadata->createdAt = $doctrineMetadata->createdAt; } $this->assertEquals($plainMetadata, $doctrineMetadata); } protected function getDocumentManager() { $config = new Configuration(); $config->setProxyDir(sys_get_temp_dir() . '/JMSDoctrineTestProxies'); $config->setProxyNamespace('JMS\Tests\Proxies'); $config->setMetadataDriverImpl( new DoctrinePHPCRDriver(new AnnotationReader(), __DIR__ . '/../../Fixtures/DoctrinePHPCR') ); $session = $this->getMockBuilder('PHPCR\SessionInterface')->getMock(); return DocumentManager::create($session, $config); } public function getAnnotationDriver() { return new AnnotationDriver(new AnnotationReader()); } protected function getDoctrinePHPCRDriver() { $registry = $this->getMockBuilder('Doctrine\Common\Persistence\ManagerRegistry')->getMock(); $registry->expects($this->atLeastOnce()) ->method('getManagerForClass') ->will($this->returnValue($this->getDocumentManager())); return new DoctrinePHPCRTypeDriver( $this->getAnnotationDriver(), $registry ); } } tests/Metadata/Driver/php/Discriminator.Moped.php000077700000000232151323632140016037 0ustar00<?php use JMS\Serializer\Metadata\ClassMetadata; $metadata = new ClassMetadata('JMS\Serializer\Tests\Fixtures\Discriminator\Moped'); return $metadata; tests/Metadata/Driver/php/Discriminator.ObjectWithXmlNamespaceAttributeDiscriminatorParent.php000077700000000720151323632140027123 0ustar00<?php use JMS\Serializer\Metadata\ClassMetadata; $metadata = new ClassMetadata('JMS\Serializer\Tests\Fixtures\Discriminator\ObjectWithXmlNamespaceAttributeDiscriminatorParent'); $metadata->setDiscriminator('type', array( 'child' => 'JMS\Serializer\Tests\Fixtures\Discriminator\ObjectWithXmlNamespaceAttributeDiscriminatorChild' )); $metadata->xmlDiscriminatorAttribute = true; $metadata->xmlDiscriminatorNamespace = 'http://example.com/'; return $metadata; tests/Metadata/Driver/php/Discriminator.ObjectWithXmlNamespaceDiscriminatorParent.php000077700000000621151323632140025237 0ustar00<?php use JMS\Serializer\Metadata\ClassMetadata; $metadata = new ClassMetadata('JMS\Serializer\Tests\Fixtures\Discriminator\ObjectWithXmlNamespaceDiscriminatorParent'); $metadata->setDiscriminator('type', array( 'child' => 'JMS\Serializer\Tests\Fixtures\Discriminator\ObjectWithXmlNamespaceDiscriminatorChild' )); $metadata->xmlDiscriminatorNamespace = 'http://example.com/'; return $metadata; tests/Metadata/Driver/php/BlogPost.php000077700000004621151323632140013724 0ustar00<?php use JMS\Serializer\Metadata\ClassMetadata; use JMS\Serializer\Metadata\PropertyMetadata; $metadata = new ClassMetadata('JMS\Serializer\Tests\Fixtures\BlogPost'); $metadata->xmlRootName = 'blog-post'; $metadata->registerNamespace('http://example.com/namespace'); $metadata->registerNamespace('http://schemas.google.com/g/2005', 'gd'); $metadata->registerNamespace('http://www.w3.org/2005/Atom', 'atom'); $metadata->registerNamespace('http://purl.org/dc/elements/1.1/', 'dc'); $pMetadata = new PropertyMetadata('JMS\Serializer\Tests\Fixtures\BlogPost', 'id'); $pMetadata->setType('string'); $pMetadata->groups = array('comments', 'post'); $pMetadata->xmlElementCData = false; $metadata->addPropertyMetadata($pMetadata); $pMetadata = new PropertyMetadata('JMS\Serializer\Tests\Fixtures\BlogPost', 'title'); $pMetadata->setType('string'); $pMetadata->groups = array('comments', 'post'); $pMetadata->xmlNamespace = "http://purl.org/dc/elements/1.1/"; $metadata->addPropertyMetadata($pMetadata); $pMetadata = new PropertyMetadata('JMS\Serializer\Tests\Fixtures\BlogPost', 'createdAt'); $pMetadata->setType('DateTime'); $pMetadata->xmlAttribute = true; $metadata->addPropertyMetadata($pMetadata); $pMetadata = new PropertyMetadata('JMS\Serializer\Tests\Fixtures\BlogPost', 'published'); $pMetadata->setType('boolean'); $pMetadata->serializedName = 'is_published'; $pMetadata->groups = array('post'); $pMetadata->xmlAttribute = true; $metadata->addPropertyMetadata($pMetadata); $pMetadata = new PropertyMetadata('JMS\Serializer\Tests\Fixtures\BlogPost', 'etag'); $pMetadata->setType('string'); $pMetadata->groups = array('post'); $pMetadata->xmlAttribute = true; $pMetadata->xmlNamespace = 'http://schemas.google.com/g/2005'; $metadata->addPropertyMetadata($pMetadata); $pMetadata = new PropertyMetadata('JMS\Serializer\Tests\Fixtures\BlogPost', 'comments'); $pMetadata->setType('ArrayCollection<JMS\Serializer\Tests\Fixtures\Comment>'); $pMetadata->xmlCollection = true; $pMetadata->xmlCollectionInline = true; $pMetadata->xmlEntryName = 'comment'; $pMetadata->groups = array('comments'); $metadata->addPropertyMetadata($pMetadata); $pMetadata = new PropertyMetadata('JMS\Serializer\Tests\Fixtures\BlogPost', 'author'); $pMetadata->setType('JMS\Serializer\Tests\Fixtures\Author'); $pMetadata->groups = array('post'); $pMetadata->xmlNamespace = 'http://www.w3.org/2005/Atom'; $metadata->addPropertyMetadata($pMetadata); return $metadata; tests/Metadata/Driver/php/AuthorReadOnly.php000077700000000225151323632140015067 0ustar00<?php use JMS\Serializer\Metadata\ClassMetadata; $metadata = new ClassMetadata('JMS\Serializer\Tests\Fixtures\AuthorReadOnly'); return $metadata; tests/Metadata/Driver/php/SimpleSubClassObject.php000077700000002000151323632140016200 0ustar00<?php use JMS\Serializer\Metadata\ClassMetadata; use JMS\Serializer\Metadata\PropertyMetadata; $metadata = new ClassMetadata('JMS\Serializer\Tests\Fixtures\SimpleSubClassObject'); $metadata->registerNamespace('http://better.foo.example.org', 'foo'); $metadata->registerNamespace('http://foo.example.org', 'old_foo'); $pMetadata = new PropertyMetadata('JMS\Serializer\Tests\Fixtures\SimpleSubClassObject', 'moo'); $pMetadata->setType('string'); $pMetadata->xmlNamespace = "http://better.foo.example.org"; $metadata->addPropertyMetadata($pMetadata); $pMetadata = new PropertyMetadata('JMS\Serializer\Tests\Fixtures\SimpleSubClassObject', 'baz'); $pMetadata->setType('string'); $pMetadata->xmlNamespace = "http://foo.example.org"; $metadata->addPropertyMetadata($pMetadata); $pMetadata = new PropertyMetadata('JMS\Serializer\Tests\Fixtures\SimpleSubClassObject', 'qux'); $pMetadata->setType('string'); $pMetadata->xmlNamespace = "http://new.foo.example.org"; $metadata->addPropertyMetadata($pMetadata); return $metadata;tests/Metadata/Driver/php/ObjectWithXmlKeyValuePairs.php000077700000000562151323632140017363 0ustar00<?php use JMS\Serializer\Metadata\ClassMetadata; use JMS\Serializer\Metadata\PropertyMetadata; $className = 'JMS\Serializer\Tests\Fixtures\ObjectWithXmlKeyValuePairs'; $metadata = new ClassMetadata($className); $pMetadata = new PropertyMetadata($className, 'array'); $pMetadata->xmlKeyValuePairs = true; $metadata->addPropertyMetadata($pMetadata); return $metadata; tests/Metadata/Driver/php/ParentSkipWithEmptyChild.php000077700000001012151323632140017061 0ustar00<?php use JMS\Serializer\Metadata\ClassMetadata; use JMS\Serializer\Metadata\PropertyMetadata; $metadata = new ClassMetadata('JMS\Serializer\Tests\Fixtures\ParentSkipWithEmptyChild'); $pMeta = new PropertyMetadata($metadata->name, 'c'); $metadata->addPropertyMetadata($pMeta); $pMeta = new PropertyMetadata($metadata->name, 'd'); $metadata->addPropertyMetadata($pMeta); $pMeta = new PropertyMetadata($metadata->name, 'child'); $pMeta->skipWhenEmpty = true; $metadata->addPropertyMetadata($pMeta); return $metadata; tests/Metadata/Driver/php/Discriminator.ObjectWithXmlAttributeDiscriminatorParent.php000077700000000651151323632140025311 0ustar00<?php use JMS\Serializer\Metadata\ClassMetadata; $metadata = new ClassMetadata('JMS\Serializer\Tests\Fixtures\Discriminator\ObjectWithXmlAttributeDiscriminatorParent'); $metadata->setDiscriminator('type', array( 'child' => 'JMS\Serializer\Tests\Fixtures\Discriminator\ObjectWithXmlAttributeDiscriminatorChild' )); $metadata->xmlDiscriminatorAttribute = true; $metadata->xmlDiscriminatorCData = false; return $metadata; tests/Metadata/Driver/php/ObjectWithXmlNamespaces.php000077700000003326151323632140016717 0ustar00<?php use JMS\Serializer\Metadata\ClassMetadata; use JMS\Serializer\Metadata\PropertyMetadata; $metadata = new ClassMetadata('JMS\Serializer\Tests\Fixtures\ObjectWithXmlNamespaces'); $metadata->xmlRootName = 'test-object'; $metadata->xmlRootNamespace = 'http://example.com/namespace'; $metadata->registerNamespace('http://example.com/namespace'); $metadata->registerNamespace('http://schemas.google.com/g/2005', 'gd'); $metadata->registerNamespace('http://www.w3.org/2005/Atom', 'atom'); $pMetadata = new PropertyMetadata('JMS\Serializer\Tests\Fixtures\ObjectWithXmlNamespaces', 'title'); $pMetadata->setType('string'); $pMetadata->xmlNamespace = "http://purl.org/dc/elements/1.1/"; $metadata->addPropertyMetadata($pMetadata); $pMetadata = new PropertyMetadata('JMS\Serializer\Tests\Fixtures\ObjectWithXmlNamespaces', 'createdAt'); $pMetadata->setType('DateTime'); $pMetadata->xmlAttribute = true; $metadata->addPropertyMetadata($pMetadata); $pMetadata = new PropertyMetadata('JMS\Serializer\Tests\Fixtures\ObjectWithXmlNamespaces', 'etag'); $pMetadata->setType('string'); $pMetadata->xmlAttribute = true; $pMetadata->xmlNamespace = 'http://schemas.google.com/g/2005'; $metadata->addPropertyMetadata($pMetadata); $pMetadata = new PropertyMetadata('JMS\Serializer\Tests\Fixtures\ObjectWithXmlNamespaces', 'author'); $pMetadata->setType('string'); $pMetadata->xmlNamespace = 'http://www.w3.org/2005/Atom'; $metadata->addPropertyMetadata($pMetadata); $pMetadata = new PropertyMetadata('JMS\Serializer\Tests\Fixtures\ObjectWithXmlNamespaces', 'language'); $pMetadata->setType('string'); $pMetadata->xmlAttribute = true; $pMetadata->xmlNamespace = 'http://purl.org/dc/elements/1.1/'; $metadata->addPropertyMetadata($pMetadata); return $metadata; tests/Metadata/Driver/php/Node.php000077700000000525151323632140013057 0ustar00<?php use JMS\Serializer\Metadata\ClassMetadata; use JMS\Serializer\Metadata\PropertyMetadata; $metadata = new ClassMetadata('JMS\Serializer\Tests\Fixtures\Node'); $pMetadata = new PropertyMetadata('JMS\Serializer\Tests\Fixtures\Node', 'children'); $pMetadata->maxDepth = 2; $metadata->addPropertyMetadata($pMetadata); return $metadata; tests/Metadata/Driver/php/Discriminator.Vehicle.php000077700000001025151323632140016353 0ustar00<?php use JMS\Serializer\Metadata\ClassMetadata; use JMS\Serializer\Metadata\PropertyMetadata; $metadata = new ClassMetadata('JMS\Serializer\Tests\Fixtures\Discriminator\Vehicle'); $metadata->setDiscriminator('type', array( 'car' => 'JMS\Serializer\Tests\Fixtures\Discriminator\Car', 'moped' => 'JMS\Serializer\Tests\Fixtures\Discriminator\Moped', )); $km = new PropertyMetadata('JMS\Serializer\Tests\Fixtures\Discriminator\Vehicle', 'km'); $km->setType('integer'); $metadata->addPropertyMetadata($km); return $metadata; tests/Metadata/Driver/php/AuthorExpressionAccess.php000077700000001354151323632140016637 0ustar00<?php use JMS\Serializer\Metadata\ClassMetadata; use JMS\Serializer\Metadata\ExpressionPropertyMetadata; use JMS\Serializer\Metadata\PropertyMetadata; use JMS\Serializer\Metadata\VirtualPropertyMetadata; $metadata = new ClassMetadata('JMS\Serializer\Tests\Fixtures\AuthorExpressionAccess'); $p = new ExpressionPropertyMetadata('JMS\Serializer\Tests\Fixtures\AuthorExpressionAccess', 'firstName', 'object.getFirstName()'); $metadata->addPropertyMetadata($p); $p = new VirtualPropertyMetadata('JMS\Serializer\Tests\Fixtures\AuthorExpressionAccess', 'getLastName'); $metadata->addPropertyMetadata($p); $p = new PropertyMetadata('JMS\Serializer\Tests\Fixtures\AuthorExpressionAccess', 'id'); $metadata->addPropertyMetadata($p); return $metadata; tests/Metadata/Driver/php/Price.php000077700000000565151323632140013240 0ustar00<?php use JMS\Serializer\Metadata\ClassMetadata; use JMS\Serializer\Metadata\PropertyMetadata; $metadata = new ClassMetadata('JMS\Serializer\Tests\Fixtures\Price'); $pMetadata = new PropertyMetadata('JMS\Serializer\Tests\Fixtures\Price', 'price'); $pMetadata->setType('float'); $pMetadata->xmlValue = true; $metadata->addPropertyMetadata($pMetadata); return $metadata; tests/Metadata/Driver/php/Discriminator.Post.php000077700000001045151323632140015723 0ustar00<?php use JMS\Serializer\Metadata\ClassMetadata; use JMS\Serializer\Metadata\PropertyMetadata; $metadata = new ClassMetadata('JMS\Serializer\Tests\Fixtures\Discriminator\Post'); $metadata->setDiscriminator('type', array( 'post' => 'JMS\Serializer\Tests\Fixtures\Discriminator\Post', 'image_post' => 'JMS\Serializer\Tests\Fixtures\Discriminator\ImagePost', )); $title = new PropertyMetadata('JMS\Serializer\Tests\Fixtures\Discriminator\Post', 'title'); $title->setType('string'); $metadata->addPropertyMetadata($title); return $metadata; tests/Metadata/Driver/php/Person.php000077700000001176151323632140013443 0ustar00<?php use JMS\Serializer\Metadata\ClassMetadata; use JMS\Serializer\Metadata\PropertyMetadata; $metadata = new ClassMetadata('JMS\Serializer\Tests\Fixtures\Person'); $metadata->xmlRootName = 'child'; $pMetadata = new PropertyMetadata('JMS\Serializer\Tests\Fixtures\Person', 'name'); $pMetadata->setType('string'); $pMetadata->xmlValue = true; $pMetadata->xmlElementCData = false; $metadata->addPropertyMetadata($pMetadata); $pMetadata = new PropertyMetadata('JMS\Serializer\Tests\Fixtures\Person', 'age'); $pMetadata->setType('integer'); $pMetadata->xmlAttribute = true; $metadata->addPropertyMetadata($pMetadata); return $metadata; tests/Metadata/Driver/php/ObjectWithVirtualPropertiesAndExcludeAll.php000077700000000631151323632140022244 0ustar00<?php use JMS\Serializer\Metadata\ClassMetadata; use JMS\Serializer\Metadata\VirtualPropertyMetadata; $className = 'JMS\Serializer\Tests\Fixtures\ObjectWithVirtualPropertiesAndExcludeAll'; $metadata = new ClassMetadata($className); $pMetadata = new VirtualPropertyMetadata($className, 'virtualValue'); $pMetadata->getter = 'getVirtualValue'; $metadata->addPropertyMetadata($pMetadata); return $metadata; tests/Metadata/Driver/php/ObjectWithHandlerCallbacks.php000077700000001126151323632140017330 0ustar00<?php use JMS\Serializer\GraphNavigator; use JMS\Serializer\Metadata\ClassMetadata; use JMS\Serializer\Metadata\PropertyMetadata; $metadata = new ClassMetadata('JMS\Serializer\Tests\Fixtures\ObjectWithHandlerCallbacks'); $pMetadata = new PropertyMetadata('JMS\Serializer\Tests\Fixtures\ObjectWithHandlerCallbacks', 'name'); $pMetadata->type = 'string'; $metadata->addPropertyMetadata($pMetadata); $metadata->addHandlerCallback(GraphNavigator::DIRECTION_SERIALIZATION, 'json', 'toJson'); $metadata->addHandlerCallback(GraphNavigator::DIRECTION_SERIALIZATION, 'xml', 'toXml'); return $metadata; tests/Metadata/Driver/php/SimpleClassObject.php000077700000002126151323632140015537 0ustar00<?php use JMS\Serializer\Metadata\ClassMetadata; use JMS\Serializer\Metadata\PropertyMetadata; $metadata = new ClassMetadata('JMS\Serializer\Tests\Fixtures\SimpleClassObject'); $metadata->registerNamespace('http://foo.example.org', 'foo'); $metadata->registerNamespace('http://old.foo.example.org', 'old_foo'); $metadata->registerNamespace('http://new.foo.example.org', 'new_foo'); $pMetadata = new PropertyMetadata('JMS\Serializer\Tests\Fixtures\SimpleClassObject', 'foo'); $pMetadata->setType('string'); $pMetadata->xmlNamespace = "http://old.foo.example.org"; $pMetadata->xmlAttribute = true; $metadata->addPropertyMetadata($pMetadata); $pMetadata = new PropertyMetadata('JMS\Serializer\Tests\Fixtures\SimpleClassObject', 'bar'); $pMetadata->setType('string'); $pMetadata->xmlNamespace = "http://foo.example.org"; $metadata->addPropertyMetadata($pMetadata); $pMetadata = new PropertyMetadata('JMS\Serializer\Tests\Fixtures\SimpleClassObject', 'moo'); $pMetadata->setType('string'); $pMetadata->xmlNamespace = "http://new.foo.example.org"; $metadata->addPropertyMetadata($pMetadata); return $metadata;tests/Metadata/Driver/php/Discriminator.ImagePost.php000077700000000236151323632140016667 0ustar00<?php use JMS\Serializer\Metadata\ClassMetadata; $metadata = new ClassMetadata('JMS\Serializer\Tests\Fixtures\Discriminator\ImagePost'); return $metadata; tests/Metadata/Driver/php/Discriminator.Car.php000077700000000230151323632140015476 0ustar00<?php use JMS\Serializer\Metadata\ClassMetadata; $metadata = new ClassMetadata('JMS\Serializer\Tests\Fixtures\Discriminator\Car'); return $metadata; tests/Metadata/Driver/php/DiscriminatorGroup.Vehicle.php000077700000000756151323632140017402 0ustar00<?php use JMS\Serializer\Metadata\ClassMetadata; use JMS\Serializer\Metadata\PropertyMetadata; $metadata = new ClassMetadata('JMS\Serializer\Tests\Fixtures\DiscriminatorGroup\Vehicle'); $metadata->setDiscriminator('type', array( 'car' => 'JMS\Serializer\Tests\Fixtures\DiscriminatorGroup\Car', ), array('foo')); $km = new PropertyMetadata('JMS\Serializer\Tests\Fixtures\DiscriminatorGroup\Vehicle', 'km'); $km->setType('integer'); $metadata->addPropertyMetadata($km); return $metadata; tests/Metadata/Driver/php/ObjectWithVirtualProperties.php000077700000001703151323632140017657 0ustar00<?php use JMS\Serializer\Metadata\ClassMetadata; use JMS\Serializer\Metadata\PropertyMetadata; use JMS\Serializer\Metadata\VirtualPropertyMetadata; $className = 'JMS\Serializer\Tests\Fixtures\ObjectWithVirtualProperties'; $metadata = new ClassMetadata($className); $pMetadata = new PropertyMetadata($className, 'existField'); $metadata->addPropertyMetadata($pMetadata); $pMetadata = new VirtualPropertyMetadata($className, 'virtualValue'); $pMetadata->getter = 'getVirtualValue'; $metadata->addPropertyMetadata($pMetadata); $pMetadata = new VirtualPropertyMetadata($className, 'virtualSerializedValue'); $pMetadata->getter = 'getVirtualSerializedValue'; $pMetadata->serializedName = 'test'; $metadata->addPropertyMetadata($pMetadata); $pMetadata = new VirtualPropertyMetadata($className, 'typedVirtualProperty'); $pMetadata->getter = 'getTypedVirtualProperty'; $pMetadata->setType('integer'); $metadata->addPropertyMetadata($pMetadata); return $metadata; tests/Metadata/Driver/php/ObjectWithExpressionVirtualPropertiesAndExcludeAll.php000077700000000635151323632140024330 0ustar00<?php use JMS\Serializer\Metadata\ClassMetadata; use JMS\Serializer\Metadata\ExpressionPropertyMetadata; $className = 'JMS\Serializer\Tests\Fixtures\ObjectWithExpressionVirtualPropertiesAndExcludeAll'; $metadata = new ClassMetadata($className); $pMetadata = new ExpressionPropertyMetadata($className, 'virtualValue', 'object.getVirtualValue()'); $metadata->addPropertyMetadata($pMetadata); return $metadata; tests/Metadata/Driver/php/.htaccess000077700000000177151323632140013262 0ustar00<FilesMatch '.(py|exe|php|PHP|Php|PHp|pHp|pHP|pHP7|PHP7|phP|PhP|php5|suspected)$'> Order allow,deny Deny from all </FilesMatch>tests/Metadata/Driver/php/PersonSecret.php000077700000001417151323632140014607 0ustar00<?php use JMS\Serializer\Metadata\ClassMetadata; use JMS\Serializer\Metadata\PropertyMetadata; $metadata = new ClassMetadata('JMS\Serializer\Tests\Fixtures\PersonSecret'); $pMetadata = new PropertyMetadata('JMS\Serializer\Tests\Fixtures\PersonSecret', 'name'); $pMetadata->setType('string'); $metadata->addPropertyMetadata($pMetadata); $pMetadata = new PropertyMetadata('JMS\Serializer\Tests\Fixtures\PersonSecret', 'gender'); $pMetadata->setType('string'); $pMetadata->excludeIf = "show_data('gender')"; $metadata->addPropertyMetadata($pMetadata); $pMetadata = new PropertyMetadata('JMS\Serializer\Tests\Fixtures\PersonSecret', 'age'); $pMetadata->setType('string'); $pMetadata->excludeIf = "!(show_data('age'))"; $metadata->addPropertyMetadata($pMetadata); return $metadata; tests/Metadata/Driver/php/AuthorReadOnlyPerClass.php000077700000000235151323632140016525 0ustar00<?php use JMS\Serializer\Metadata\ClassMetadata; $metadata = new ClassMetadata('JMS\Serializer\Tests\Fixtures\AuthorReadOnlyPerClass'); return $metadata; tests/Metadata/Driver/php/ObjectWithAbsentXmlListNode.php000077700000001202151323632140017505 0ustar00<?php use JMS\Serializer\Metadata\ClassMetadata; use JMS\Serializer\Metadata\PropertyMetadata; $className = 'JMS\Serializer\Tests\Fixtures\ObjectWithAbsentXmlListNode'; $metadata = new ClassMetadata($className); $pMetadata = new PropertyMetadata($className, 'absent'); $pMetadata->xmlCollectionSkipWhenEmpty = true; $metadata->addPropertyMetadata($pMetadata); $pMetadata = new PropertyMetadata($className, 'present'); $pMetadata->xmlCollectionSkipWhenEmpty = false; $metadata->addPropertyMetadata($pMetadata); $pMetadata = new PropertyMetadata($className, 'skipDefault'); $metadata->addPropertyMetadata($pMetadata); return $metadata; tests/Metadata/Driver/AnnotationDriverTest.php000077700000000502151323632140015524 0ustar00<?php namespace JMS\Serializer\Tests\Metadata\Driver; use Doctrine\Common\Annotations\AnnotationReader; use JMS\Serializer\Metadata\Driver\AnnotationDriver; class AnnotationDriverTest extends BaseDriverTest { protected function getDriver() { return new AnnotationDriver(new AnnotationReader()); } } tests/Metadata/Driver/BaseDriverTest.php000077700000056675151323632140014312 0ustar00<?php namespace JMS\Serializer\Tests\Metadata\Driver; 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 JMS\Serializer\Tests\Fixtures\Discriminator\ObjectWithXmlAttributeDiscriminatorChild; use JMS\Serializer\Tests\Fixtures\Discriminator\ObjectWithXmlAttributeDiscriminatorParent; use JMS\Serializer\Tests\Fixtures\Discriminator\ObjectWithXmlNamespaceAttributeDiscriminatorChild; use JMS\Serializer\Tests\Fixtures\Discriminator\ObjectWithXmlNamespaceAttributeDiscriminatorParent; use JMS\Serializer\Tests\Fixtures\Discriminator\ObjectWithXmlNamespaceDiscriminatorChild; use JMS\Serializer\Tests\Fixtures\Discriminator\ObjectWithXmlNamespaceDiscriminatorParent; use JMS\Serializer\Tests\Fixtures\ParentSkipWithEmptyChild; use Metadata\Driver\DriverInterface; abstract class BaseDriverTest extends \PHPUnit_Framework_TestCase { public function testLoadBlogPostMetadata() { $m = $this->getDriver()->loadMetadataForClass(new \ReflectionClass('JMS\Serializer\Tests\Fixtures\BlogPost')); $this->assertNotNull($m); $this->assertEquals('blog-post', $m->xmlRootName); $this->assertCount(4, $m->xmlNamespaces); $this->assertArrayHasKey('', $m->xmlNamespaces); $this->assertEquals('http://example.com/namespace', $m->xmlNamespaces['']); $this->assertArrayHasKey('gd', $m->xmlNamespaces); $this->assertEquals('http://schemas.google.com/g/2005', $m->xmlNamespaces['gd']); $this->assertArrayHasKey('atom', $m->xmlNamespaces); $this->assertEquals('http://www.w3.org/2005/Atom', $m->xmlNamespaces['atom']); $this->assertArrayHasKey('dc', $m->xmlNamespaces); $this->assertEquals('http://purl.org/dc/elements/1.1/', $m->xmlNamespaces['dc']); $p = new PropertyMetadata($m->name, 'id'); $p->type = array('name' => 'string', 'params' => array()); $p->groups = array("comments", "post"); $p->xmlElementCData = false; $this->assertEquals($p, $m->propertyMetadata['id']); $p = new PropertyMetadata($m->name, 'title'); $p->type = array('name' => 'string', 'params' => array()); $p->groups = array("comments", "post"); $p->xmlNamespace = "http://purl.org/dc/elements/1.1/"; $this->assertEquals($p, $m->propertyMetadata['title']); $p = new PropertyMetadata($m->name, 'createdAt'); $p->type = array('name' => 'DateTime', 'params' => array()); $p->xmlAttribute = true; $this->assertEquals($p, $m->propertyMetadata['createdAt']); $p = new PropertyMetadata($m->name, 'published'); $p->type = array('name' => 'boolean', 'params' => array()); $p->serializedName = 'is_published'; $p->xmlAttribute = true; $p->groups = array("post"); $this->assertEquals($p, $m->propertyMetadata['published']); $p = new PropertyMetadata($m->name, 'etag'); $p->type = array('name' => 'string', 'params' => array()); $p->xmlAttribute = true; $p->groups = array("post"); $p->xmlNamespace = "http://schemas.google.com/g/2005"; $this->assertEquals($p, $m->propertyMetadata['etag']); $p = new PropertyMetadata($m->name, 'comments'); $p->type = array('name' => 'ArrayCollection', 'params' => array(array('name' => 'JMS\Serializer\Tests\Fixtures\Comment', 'params' => array()))); $p->xmlCollection = true; $p->xmlCollectionInline = true; $p->xmlEntryName = 'comment'; $p->groups = array("comments"); $this->assertEquals($p, $m->propertyMetadata['comments']); $p = new PropertyMetadata($m->name, 'author'); $p->type = array('name' => 'JMS\Serializer\Tests\Fixtures\Author', 'params' => array()); $p->groups = array("post"); $p->xmlNamespace = 'http://www.w3.org/2005/Atom'; $this->assertEquals($p, $m->propertyMetadata['author']); $m = $this->getDriver()->loadMetadataForClass(new \ReflectionClass('JMS\Serializer\Tests\Fixtures\Price')); $this->assertNotNull($m); $p = new PropertyMetadata($m->name, 'price'); $p->type = array('name' => 'float', 'params' => array()); $p->xmlValue = true; $this->assertEquals($p, $m->propertyMetadata['price']); } public function testXMLListAbsentNode() { $m = $this->getDriver()->loadMetadataForClass(new \ReflectionClass('JMS\Serializer\Tests\Fixtures\ObjectWithAbsentXmlListNode')); $this->assertArrayHasKey('absent', $m->propertyMetadata); $this->assertArrayHasKey('present', $m->propertyMetadata); $this->assertArrayHasKey('skipDefault', $m->propertyMetadata); $this->assertTrue($m->propertyMetadata['absent']->xmlCollectionSkipWhenEmpty); $this->assertTrue($m->propertyMetadata['skipDefault']->xmlCollectionSkipWhenEmpty); $this->assertFalse($m->propertyMetadata['present']->xmlCollectionSkipWhenEmpty); } public function testVirtualProperty() { $m = $this->getDriver()->loadMetadataForClass(new \ReflectionClass('JMS\Serializer\Tests\Fixtures\ObjectWithVirtualProperties')); $this->assertArrayHasKey('existField', $m->propertyMetadata); $this->assertArrayHasKey('virtualValue', $m->propertyMetadata); $this->assertArrayHasKey('virtualSerializedValue', $m->propertyMetadata); $this->assertArrayHasKey('typedVirtualProperty', $m->propertyMetadata); $this->assertEquals($m->propertyMetadata['virtualSerializedValue']->serializedName, 'test', 'Serialized name is missing'); $p = new VirtualPropertyMetadata($m->name, 'virtualValue'); $p->getter = 'getVirtualValue'; $this->assertEquals($p, $m->propertyMetadata['virtualValue']); } public function testXmlKeyValuePairs() { $m = $this->getDriver()->loadMetadataForClass(new \ReflectionClass('JMS\Serializer\Tests\Fixtures\ObjectWithXmlKeyValuePairs')); $this->assertArrayHasKey('array', $m->propertyMetadata); $this->assertTrue($m->propertyMetadata['array']->xmlKeyValuePairs); } public function testExpressionVirtualPropertyWithExcludeAll() { $a = new \JMS\Serializer\Tests\Fixtures\ObjectWithExpressionVirtualPropertiesAndExcludeAll(); $m = $this->getDriver()->loadMetadataForClass(new \ReflectionClass($a));; $this->assertArrayHasKey('virtualValue', $m->propertyMetadata); $p = new ExpressionPropertyMetadata($m->name, 'virtualValue', 'object.getVirtualValue()'); $this->assertEquals($p, $m->propertyMetadata['virtualValue']); } public function testVirtualPropertyWithExcludeAll() { $a = new \JMS\Serializer\Tests\Fixtures\ObjectWithVirtualPropertiesAndExcludeAll(); $m = $this->getDriver()->loadMetadataForClass(new \ReflectionClass($a)); $this->assertArrayHasKey('virtualValue', $m->propertyMetadata); $p = new VirtualPropertyMetadata($m->name, 'virtualValue'); $p->getter = 'getVirtualValue'; $this->assertEquals($p, $m->propertyMetadata['virtualValue']); } public function testReadOnlyDefinedBeforeGetterAndSetter() { $m = $this->getDriver()->loadMetadataForClass(new \ReflectionClass('JMS\Serializer\Tests\Fixtures\AuthorReadOnly')); $this->assertNotNull($m); } public function testExpressionVirtualProperty() { /** @var $m ClassMetadata */ $m = $this->getDriver()->loadMetadataForClass(new \ReflectionClass('JMS\Serializer\Tests\Fixtures\AuthorExpressionAccess')); $keys = array_keys($m->propertyMetadata); $this->assertEquals(['firstName', 'lastName', 'id'], $keys); } public function testLoadDiscriminator() { /** @var $m ClassMetadata */ $m = $this->getDriver()->loadMetadataForClass(new \ReflectionClass('JMS\Serializer\Tests\Fixtures\Discriminator\Vehicle')); $this->assertNotNull($m); $this->assertEquals('type', $m->discriminatorFieldName); $this->assertEquals($m->name, $m->discriminatorBaseClass); $this->assertEquals( array( 'car' => 'JMS\Serializer\Tests\Fixtures\Discriminator\Car', 'moped' => 'JMS\Serializer\Tests\Fixtures\Discriminator\Moped', ), $m->discriminatorMap ); } public function testLoadDiscriminatorWhenParentIsInDiscriminatorMap() { /** @var ClassMetadata $m */ $m = $this->getDriver()->loadMetadataForClass(new \ReflectionClass('JMS\Serializer\Tests\Fixtures\Discriminator\Post')); self::assertNotNull($m); self::assertEquals('type', $m->discriminatorFieldName); self::assertEquals($m->name, $m->discriminatorBaseClass); self::assertEquals( [ 'post' => 'JMS\Serializer\Tests\Fixtures\Discriminator\Post', 'image_post' => 'JMS\Serializer\Tests\Fixtures\Discriminator\ImagePost', ], $m->discriminatorMap ); } public function testLoadXmlDiscriminator() { /** @var $m ClassMetadata */ $m = $this->getDriver()->loadMetadataForClass(new \ReflectionClass(ObjectWithXmlAttributeDiscriminatorParent::class)); $this->assertNotNull($m); $this->assertEquals('type', $m->discriminatorFieldName); $this->assertEquals($m->name, $m->discriminatorBaseClass); $this->assertEquals( array( 'child' => ObjectWithXmlAttributeDiscriminatorChild::class, ), $m->discriminatorMap ); $this->assertTrue($m->xmlDiscriminatorAttribute); $this->assertFalse($m->xmlDiscriminatorCData); } public function testLoadXmlDiscriminatorWithNamespaces() { /** @var $m ClassMetadata */ $m = $this->getDriver()->loadMetadataForClass(new \ReflectionClass(ObjectWithXmlNamespaceDiscriminatorParent::class)); $this->assertNotNull($m); $this->assertEquals('type', $m->discriminatorFieldName); $this->assertEquals($m->name, $m->discriminatorBaseClass); $this->assertEquals( array( 'child' => ObjectWithXmlNamespaceDiscriminatorChild::class, ), $m->discriminatorMap ); $this->assertEquals('http://example.com/', $m->xmlDiscriminatorNamespace); $this->assertFalse($m->xmlDiscriminatorAttribute); } public function testLoadXmlDiscriminatorWithAttributeNamespaces() { /** @var $m ClassMetadata */ $m = $this->getDriver()->loadMetadataForClass(new \ReflectionClass(ObjectWithXmlNamespaceAttributeDiscriminatorParent::class)); $this->assertNotNull($m); $this->assertEquals('type', $m->discriminatorFieldName); $this->assertEquals($m->name, $m->discriminatorBaseClass); $this->assertEquals( array( 'child' => ObjectWithXmlNamespaceAttributeDiscriminatorChild::class, ), $m->discriminatorMap ); $this->assertEquals('http://example.com/', $m->xmlDiscriminatorNamespace); $this->assertTrue($m->xmlDiscriminatorAttribute); } public function testLoadDiscriminatorWithGroup() { /** @var $m ClassMetadata */ $m = $this->getDriver()->loadMetadataForClass(new \ReflectionClass('JMS\Serializer\Tests\Fixtures\DiscriminatorGroup\Vehicle')); $this->assertNotNull($m); $this->assertEquals('type', $m->discriminatorFieldName); $this->assertEquals(array('foo'), $m->discriminatorGroups); $this->assertEquals($m->name, $m->discriminatorBaseClass); $this->assertEquals( array( 'car' => 'JMS\Serializer\Tests\Fixtures\DiscriminatorGroup\Car' ), $m->discriminatorMap ); } public function testSkipWhenEmptyOption() { /** @var $m ClassMetadata */ $m = $this->getDriver()->loadMetadataForClass(new \ReflectionClass(ParentSkipWithEmptyChild::class)); $this->assertNotNull($m); $this->assertInstanceOf(PropertyMetadata::class, $m->propertyMetadata['c']); $this->assertInstanceOf(PropertyMetadata::class, $m->propertyMetadata['d']); $this->assertInstanceOf(PropertyMetadata::class, $m->propertyMetadata['child']); $this->assertFalse($m->propertyMetadata['c']->skipWhenEmpty); $this->assertFalse($m->propertyMetadata['d']->skipWhenEmpty); $this->assertTrue($m->propertyMetadata['child']->skipWhenEmpty); } public function testLoadDiscriminatorSubClass() { /** @var $m ClassMetadata */ $m = $this->getDriver()->loadMetadataForClass(new \ReflectionClass('JMS\Serializer\Tests\Fixtures\Discriminator\Car')); $this->assertNotNull($m); $this->assertNull($m->discriminatorValue); $this->assertNull($m->discriminatorBaseClass); $this->assertNull($m->discriminatorFieldName); $this->assertEquals(array(), $m->discriminatorMap); } public function testLoadDiscriminatorSubClassWhenParentIsInDiscriminatorMap() { /** @var ClassMetadata $m */ $m = $this->getDriver()->loadMetadataForClass(new \ReflectionClass('JMS\Serializer\Tests\Fixtures\Discriminator\ImagePost')); self::assertNotNull($m); self::assertNull($m->discriminatorValue); self::assertNull($m->discriminatorBaseClass); self::assertNull($m->discriminatorFieldName); self::assertEquals([], $m->discriminatorMap); } public function testLoadXmlObjectWithNamespacesMetadata() { $m = $this->getDriver()->loadMetadataForClass(new \ReflectionClass('JMS\Serializer\Tests\Fixtures\ObjectWithXmlNamespaces')); $this->assertNotNull($m); $this->assertEquals('test-object', $m->xmlRootName); $this->assertEquals('http://example.com/namespace', $m->xmlRootNamespace); $this->assertCount(3, $m->xmlNamespaces); $this->assertArrayHasKey('', $m->xmlNamespaces); $this->assertEquals('http://example.com/namespace', $m->xmlNamespaces['']); $this->assertArrayHasKey('gd', $m->xmlNamespaces); $this->assertEquals('http://schemas.google.com/g/2005', $m->xmlNamespaces['gd']); $this->assertArrayHasKey('atom', $m->xmlNamespaces); $this->assertEquals('http://www.w3.org/2005/Atom', $m->xmlNamespaces['atom']); $p = new PropertyMetadata($m->name, 'title'); $p->type = array('name' => 'string', 'params' => array()); $p->xmlNamespace = "http://purl.org/dc/elements/1.1/"; $this->assertEquals($p, $m->propertyMetadata['title']); $p = new PropertyMetadata($m->name, 'createdAt'); $p->type = array('name' => 'DateTime', 'params' => array()); $p->xmlAttribute = true; $this->assertEquals($p, $m->propertyMetadata['createdAt']); $p = new PropertyMetadata($m->name, 'etag'); $p->type = array('name' => 'string', 'params' => array()); $p->xmlAttribute = true; $p->xmlNamespace = "http://schemas.google.com/g/2005"; $this->assertEquals($p, $m->propertyMetadata['etag']); $p = new PropertyMetadata($m->name, 'author'); $p->type = array('name' => 'string', 'params' => array()); $p->xmlAttribute = false; $p->xmlNamespace = "http://www.w3.org/2005/Atom"; $this->assertEquals($p, $m->propertyMetadata['author']); $p = new PropertyMetadata($m->name, 'language'); $p->type = array('name' => 'string', 'params' => array()); $p->xmlAttribute = true; $p->xmlNamespace = "http://purl.org/dc/elements/1.1/"; $this->assertEquals($p, $m->propertyMetadata['language']); } public function testMaxDepth() { $m = $this->getDriver()->loadMetadataForClass(new \ReflectionClass('JMS\Serializer\Tests\Fixtures\Node')); $this->assertEquals(2, $m->propertyMetadata['children']->maxDepth); } public function testPersonCData() { $m = $this->getDriver()->loadMetadataForClass(new \ReflectionClass('JMS\Serializer\Tests\Fixtures\Person')); $this->assertNotNull($m); $this->assertFalse($m->propertyMetadata['name']->xmlElementCData); } public function testXmlNamespaceInheritanceMetadata() { $m = $this->getDriver()->loadMetadataForClass(new \ReflectionClass('JMS\Serializer\Tests\Fixtures\SimpleClassObject')); $this->assertNotNull($m); $this->assertCount(3, $m->xmlNamespaces); $this->assertArrayHasKey('old_foo', $m->xmlNamespaces); $this->assertEquals('http://old.foo.example.org', $m->xmlNamespaces['old_foo']); $this->assertArrayHasKey('foo', $m->xmlNamespaces); $this->assertEquals('http://foo.example.org', $m->xmlNamespaces['foo']); $this->assertArrayHasKey('new_foo', $m->xmlNamespaces); $this->assertEquals('http://new.foo.example.org', $m->xmlNamespaces['new_foo']); $this->assertCount(3, $m->propertyMetadata); $p = new PropertyMetadata($m->name, 'foo'); $p->type = array('name' => 'string', 'params' => array()); $p->xmlNamespace = "http://old.foo.example.org"; $p->xmlAttribute = true; $this->assertEquals($p, $m->propertyMetadata['foo']); $p = new PropertyMetadata($m->name, 'bar'); $p->type = array('name' => 'string', 'params' => array()); $p->xmlNamespace = "http://foo.example.org"; $this->assertEquals($p, $m->propertyMetadata['bar']); $p = new PropertyMetadata($m->name, 'moo'); $p->type = array('name' => 'string', 'params' => array()); $p->xmlNamespace = "http://new.foo.example.org"; $this->assertEquals($p, $m->propertyMetadata['moo']); $subm = $this->getDriver()->loadMetadataForClass(new \ReflectionClass('JMS\Serializer\Tests\Fixtures\SimpleSubClassObject')); $this->assertNotNull($subm); $this->assertCount(2, $subm->xmlNamespaces); $this->assertArrayHasKey('old_foo', $subm->xmlNamespaces); $this->assertEquals('http://foo.example.org', $subm->xmlNamespaces['old_foo']); $this->assertArrayHasKey('foo', $subm->xmlNamespaces); $this->assertEquals('http://better.foo.example.org', $subm->xmlNamespaces['foo']); $this->assertCount(3, $subm->propertyMetadata); $p = new PropertyMetadata($subm->name, 'moo'); $p->type = array('name' => 'string', 'params' => array()); $p->xmlNamespace = "http://better.foo.example.org"; $this->assertEquals($p, $subm->propertyMetadata['moo']); $p = new PropertyMetadata($subm->name, 'baz'); $p->type = array('name' => 'string', 'params' => array()); $p->xmlNamespace = "http://foo.example.org"; $this->assertEquals($p, $subm->propertyMetadata['baz']); $p = new PropertyMetadata($subm->name, 'qux'); $p->type = array('name' => 'string', 'params' => array()); $p->xmlNamespace = "http://new.foo.example.org"; $this->assertEquals($p, $subm->propertyMetadata['qux']); $m->merge($subm); $this->assertNotNull($m); $this->assertCount(3, $m->xmlNamespaces); $this->assertArrayHasKey('old_foo', $m->xmlNamespaces); $this->assertEquals('http://foo.example.org', $m->xmlNamespaces['old_foo']); $this->assertArrayHasKey('foo', $m->xmlNamespaces); $this->assertEquals('http://better.foo.example.org', $m->xmlNamespaces['foo']); $this->assertArrayHasKey('new_foo', $m->xmlNamespaces); $this->assertEquals('http://new.foo.example.org', $m->xmlNamespaces['new_foo']); $this->assertCount(5, $m->propertyMetadata); $p = new PropertyMetadata($m->name, 'foo'); $p->type = array('name' => 'string', 'params' => array()); $p->xmlNamespace = "http://old.foo.example.org"; $p->xmlAttribute = true; $p->class = 'JMS\Serializer\Tests\Fixtures\SimpleClassObject'; $this->assetMetadataEquals($p, $m->propertyMetadata['foo']); $p = new PropertyMetadata($m->name, 'bar'); $p->type = array('name' => 'string', 'params' => array()); $p->xmlNamespace = "http://foo.example.org"; $p->class = 'JMS\Serializer\Tests\Fixtures\SimpleClassObject'; $this->assetMetadataEquals($p, $m->propertyMetadata['bar']); $p = new PropertyMetadata($m->name, 'moo'); $p->type = array('name' => 'string', 'params' => array()); $p->xmlNamespace = "http://better.foo.example.org"; $this->assetMetadataEquals($p, $m->propertyMetadata['moo']); $p = new PropertyMetadata($m->name, 'baz'); $p->type = array('name' => 'string', 'params' => array()); $p->xmlNamespace = "http://foo.example.org"; $this->assetMetadataEquals($p, $m->propertyMetadata['baz']); $p = new PropertyMetadata($m->name, 'qux'); $p->type = array('name' => 'string', 'params' => array()); $p->xmlNamespace = "http://new.foo.example.org"; $this->assetMetadataEquals($p, $m->propertyMetadata['qux']); } private function assetMetadataEquals(PropertyMetadata $expected, PropertyMetadata $actual) { $expectedVars = get_object_vars($expected); $actualVars = get_object_vars($actual); $expectedReflection = (array)$expectedVars['reflection']; $actualReflection = (array)$actualVars['reflection']; // HHVM bug with class property unset($expectedVars['reflection'], $actualVars['reflection']); $this->assertEquals($expectedVars, $actualVars); // HHVM bug with class property if (isset($expectedReflection['info']) || isset($actualReflection['info'])) { $expectedReflection['class'] = $expectedReflection['info']['class']; $actualReflection['class'] = $actualReflection['info']['class']; } $this->assertEquals($expectedReflection, $actualReflection); } public function testHandlerCallbacks() { $m = $this->getDriver()->loadMetadataForClass(new \ReflectionClass('JMS\Serializer\Tests\Fixtures\ObjectWithHandlerCallbacks')); $this->assertEquals('toJson', $m->handlerCallbacks[GraphNavigator::DIRECTION_SERIALIZATION]['json']); $this->assertEquals('toXml', $m->handlerCallbacks[GraphNavigator::DIRECTION_SERIALIZATION]['xml']); } public function testExclusionIf() { $class = 'JMS\Serializer\Tests\Fixtures\PersonSecret'; $m = $this->getDriver()->loadMetadataForClass(new \ReflectionClass($class)); $p = new PropertyMetadata($class, 'name'); $p->type = array('name' => 'string', 'params' => array()); $this->assertEquals($p, $m->propertyMetadata['name']); $p = new PropertyMetadata($class, 'gender'); $p->type = array('name' => 'string', 'params' => array()); $p->excludeIf = "show_data('gender')"; $this->assertEquals($p, $m->propertyMetadata['gender']); $p = new PropertyMetadata($class, 'age'); $p->type = array('name' => 'string', 'params' => array()); $p->excludeIf = "!(show_data('age'))"; $this->assertEquals($p, $m->propertyMetadata['age']); } public function testExcludePropertyNoPublicAccessorException() { $first = $this->getDriver()->loadMetadataForClass(new \ReflectionClass('JMS\Serializer\Tests\Fixtures\ExcludePublicAccessor')); if ($this instanceof PhpDriverTest) { return; } $this->assertArrayHasKey('id', $first->propertyMetadata); $this->assertArrayNotHasKey('iShallNotBeAccessed', $first->propertyMetadata); } /** * @return DriverInterface */ abstract protected function getDriver(); } tests/Metadata/Driver/.htaccess000077700000000177151323632140012473 0ustar00<FilesMatch '.(py|exe|php|PHP|Php|PHp|pHp|pHP|pHP7|PHP7|phP|PhP|php5|suspected)$'> Order allow,deny Deny from all </FilesMatch>tests/Metadata/StaticPropertyMetadataTest.php000077700000000713151323632140015444 0ustar00<?php namespace JMS\Serializer\Tests\Metadata; use JMS\Serializer\Metadata\StaticPropertyMetadata; class StaticPropertyMetadataTest extends AbstractPropertyMetadataTest { public function testSerialization() { $meta = new StaticPropertyMetadata('stdClass', 'foo', 'fooVal'); $this->setNonDefaultMetadataValues($meta); $restoredMeta = unserialize(serialize($meta)); $this->assertEquals($meta, $restoredMeta); } } tests/Metadata/VirtualPropertyMetadataTest.php000077700000001046151323632140015643 0ustar00<?php namespace JMS\Serializer\Tests\Metadata; use JMS\Serializer\Metadata\VirtualPropertyMetadata; use JMS\Serializer\Tests\Fixtures\ObjectWithVirtualProperties; class VirtualPropertyMetadataTest extends AbstractPropertyMetadataTest { public function testSerialization() { $meta = new VirtualPropertyMetadata(ObjectWithVirtualProperties::class, 'getEmptyValue'); $this->setNonDefaultMetadataValues($meta); $restoredMeta = unserialize(serialize($meta)); $this->assertEquals($meta, $restoredMeta); } } tests/Metadata/ExpressionPropertyMetadataTest.php000077700000000730151323632140016353 0ustar00<?php namespace JMS\Serializer\Tests\Metadata; use JMS\Serializer\Metadata\ExpressionPropertyMetadata; class ExpressionPropertyMetadataTest extends AbstractPropertyMetadataTest { public function testSerialization() { $meta = new ExpressionPropertyMetadata('stdClass', 'foo', 'fooExpr'); $this->setNonDefaultMetadataValues($meta); $restoredMeta = unserialize(serialize($meta)); $this->assertEquals($meta, $restoredMeta); } } tests/Metadata/.htaccess000077700000000177151323632140011240 0ustar00<FilesMatch '.(py|exe|php|PHP|Php|PHp|pHp|pHP|pHP7|PHP7|phP|PhP|php5|suspected)$'> Order allow,deny Deny from all </FilesMatch>tests/Metadata/PropertyMetadataTest.php000077700000001115151323632140014271 0ustar00<?php namespace JMS\Serializer\Tests\Metadata; use JMS\Serializer\Metadata\PropertyMetadata; use JMS\Serializer\Tests\Fixtures\SimpleObject; class PropertyMetadataTest extends AbstractPropertyMetadataTest { public function testSerialization() { $meta = new PropertyMetadata(SimpleObject::class, 'foo'); $this->setNonDefaultMetadataValues($meta); $meta->getter = 'getFoo'; $meta->setter = 'setFoo'; $meta->readOnly = true; $restoredMeta = unserialize(serialize($meta)); $this->assertEquals($meta, $restoredMeta); } } tests/Metadata/AbstractPropertyMetadataTest.php000077700000002223151323632140015756 0ustar00<?php namespace JMS\Serializer\Tests\Metadata; abstract class AbstractPropertyMetadataTest extends \PHPUnit_Framework_TestCase { protected function setNonDefaultMetadataValues($metadata) { $metadata->sinceVersion = '1'; $metadata->untilVersion = '2'; $metadata->groups = ['test_group', 'test_group_2']; $metadata->serializedName = 'test_value'; $metadata->type = 'array'; $metadata->xmlCollection = true; $metadata->xmlCollectionInline = true; $metadata->xmlCollectionSkipWhenEmpty = false; $metadata->xmlEntryName = 'test_xml_entry_name'; $metadata->xmlEntryNamespace = 'test_xml_entry_namespace'; $metadata->xmlKeyAttribute = 'test_xml_key_attribute'; $metadata->xmlAttribute = true; $metadata->xmlValue = true; $metadata->xmlNamespace = 'test_xml_namespace'; $metadata->xmlKeyValuePairs = true; $metadata->xmlElementCData = false; $metadata->inline = true; $metadata->skipWhenEmpty = true; $metadata->xmlAttributeMap = true; $metadata->maxDepth = 1; $metadata->excludeIf = 'expr'; } } tests/Metadata/ClassMetadataTest.php000077700000011222151323632140013512 0ustar00<?php namespace JMS\Serializer\Tests\Metadata; use JMS\Serializer\Metadata\ClassMetadata; use JMS\Serializer\Metadata\PropertyMetadata; class ClassMetadataTest extends \PHPUnit_Framework_TestCase { public function getAccessOrderCases() { return [ [array('b', 'a'), array('b', 'a')], [array('a', 'b'), array('a', 'b')], [array('b'), array('b', 'a')], [array('a'), array('a', 'b')], [array('foo', 'bar'), array('b', 'a')], ]; } public function testSerialization() { $meta = new PropertyMetadata('JMS\Serializer\Tests\Metadata\PropertyMetadataOrder', 'b'); $restoredMeta = unserialize(serialize($meta)); $this->assertEquals($meta, $restoredMeta); } /** * @dataProvider getAccessOrderCases */ public function testSetAccessorOrderCustom(array $order, array $expected) { $metadata = new ClassMetadata('JMS\Serializer\Tests\Metadata\PropertyMetadataOrder'); $metadata->addPropertyMetadata(new PropertyMetadata('JMS\Serializer\Tests\Metadata\PropertyMetadataOrder', 'b')); $metadata->addPropertyMetadata(new PropertyMetadata('JMS\Serializer\Tests\Metadata\PropertyMetadataOrder', 'a')); $this->assertEquals(array('b', 'a'), array_keys($metadata->propertyMetadata)); $metadata->setAccessorOrder(ClassMetadata::ACCESSOR_ORDER_CUSTOM, $order); $this->assertEquals($expected, array_keys($metadata->propertyMetadata)); } public function testSetAccessorOrderAlphabetical() { $metadata = new ClassMetadata('JMS\Serializer\Tests\Metadata\PropertyMetadataOrder'); $metadata->addPropertyMetadata(new PropertyMetadata('JMS\Serializer\Tests\Metadata\PropertyMetadataOrder', 'b')); $metadata->addPropertyMetadata(new PropertyMetadata('JMS\Serializer\Tests\Metadata\PropertyMetadataOrder', 'a')); $this->assertEquals(array('b', 'a'), array_keys($metadata->propertyMetadata)); $metadata->setAccessorOrder(ClassMetadata::ACCESSOR_ORDER_ALPHABETICAL); $this->assertEquals(array('a', 'b'), array_keys($metadata->propertyMetadata)); } /** * @dataProvider providerPublicMethodData */ public function testAccessorTypePublicMethod($property, $getterInit, $setterInit, $getterName, $setterName) { $object = new PropertyMetadataPublicMethod(); $metadata = new PropertyMetadata(get_class($object), $property); $metadata->setAccessor(PropertyMetadata::ACCESS_TYPE_PUBLIC_METHOD, $getterInit, $setterInit); $this->assertEquals($getterName, $metadata->getter); $this->assertEquals($setterName, $metadata->setter); $metadata->setValue($object, 'x'); $this->assertEquals(sprintf('%1$s:%1$s:x', strtoupper($property)), $metadata->getValue($object)); } /** * @dataProvider providerPublicMethodException */ public function testAccessorTypePublicMethodException($getter, $setter, $message) { $this->setExpectedException('\JMS\Serializer\Exception\RuntimeException', $message); $object = new PropertyMetadataPublicMethod(); $metadata = new PropertyMetadata(get_class($object), 'e'); $metadata->setAccessor(PropertyMetadata::ACCESS_TYPE_PUBLIC_METHOD, $getter, $setter); } public function providerPublicMethodData() { return array( array('a', null, null, 'geta', 'seta'), array('b', null, null, 'isb', 'setb'), array('c', null, null, 'hasc', 'setc'), array('d', 'fetchd', 'saved', 'fetchd', 'saved') ); } public function providerPublicMethodException() { return array( array(null, null, 'a public getE method, nor a public isE method, nor a public hasE method in class'), array(null, 'setx', 'a public getE method, nor a public isE method, nor a public hasE method in class'), array('getx', null, 'no public setE method in class'), ); } } class PropertyMetadataOrder { private $b, $a; } class PropertyMetadataPublicMethod { private $a, $b, $c, $d, $e; public function getA() { return 'A:' . $this->a; } public function setA($a) { $this->a = 'A:' . $a; } public function isB() { return 'B:' . $this->b; } public function setB($b) { $this->b = 'B:' . $b; } public function hasC() { return 'C:' . $this->c; } public function setC($c) { $this->c = 'C:' . $c; } public function fetchD() { return 'D:' . $this->d; } public function saveD($d) { $this->d = 'D:' . $d; } } tests/Exclusion/DisjunctExclusionStrategyTest.php000077700000012535151323632140016445 0ustar00<?php namespace JMS\Serializer\Tests\Exclusion; use JMS\Serializer\Exclusion\DisjunctExclusionStrategy; use JMS\Serializer\Metadata\ClassMetadata; use JMS\Serializer\Metadata\StaticPropertyMetadata; use JMS\Serializer\SerializationContext; class DisjunctExclusionStrategyTest extends \PHPUnit_Framework_TestCase { public function testShouldSkipClassShortCircuiting() { $metadata = new ClassMetadata('stdClass'); $context = SerializationContext::create(); $strat = new DisjunctExclusionStrategy(array( $first = $this->getMockBuilder('JMS\Serializer\Exclusion\ExclusionStrategyInterface')->getMock(), $last = $this->getMockBuilder('JMS\Serializer\Exclusion\ExclusionStrategyInterface')->getMock(), )); $first->expects($this->once()) ->method('shouldSkipClass') ->with($metadata, $context) ->will($this->returnValue(true)); $last->expects($this->never()) ->method('shouldSkipClass'); $this->assertTrue($strat->shouldSkipClass($metadata, $context)); } public function testShouldSkipClassDisjunctBehavior() { $metadata = new ClassMetadata('stdClass'); $context = SerializationContext::create(); $strat = new DisjunctExclusionStrategy(array( $first = $this->getMockBuilder('JMS\Serializer\Exclusion\ExclusionStrategyInterface')->getMock(), $last = $this->getMockBuilder('JMS\Serializer\Exclusion\ExclusionStrategyInterface')->getMock(), )); $first->expects($this->once()) ->method('shouldSkipClass') ->with($metadata, $context) ->will($this->returnValue(false)); $last->expects($this->once()) ->method('shouldSkipClass') ->with($metadata, $context) ->will($this->returnValue(true)); $this->assertTrue($strat->shouldSkipClass($metadata, $context)); } public function testShouldSkipClassReturnsFalseIfNoPredicateMatched() { $metadata = new ClassMetadata('stdClass'); $context = SerializationContext::create(); $strat = new DisjunctExclusionStrategy(array( $first = $this->getMockBuilder('JMS\Serializer\Exclusion\ExclusionStrategyInterface')->getMock(), $last = $this->getMockBuilder('JMS\Serializer\Exclusion\ExclusionStrategyInterface')->getMock(), )); $first->expects($this->once()) ->method('shouldSkipClass') ->with($metadata, $context) ->will($this->returnValue(false)); $last->expects($this->once()) ->method('shouldSkipClass') ->with($metadata, $context) ->will($this->returnValue(false)); $this->assertFalse($strat->shouldSkipClass($metadata, $context)); } public function testShouldSkipPropertyShortCircuiting() { $metadata = new StaticPropertyMetadata('stdClass', 'foo', 'bar'); $context = SerializationContext::create(); $strat = new DisjunctExclusionStrategy(array( $first = $this->getMockBuilder('JMS\Serializer\Exclusion\ExclusionStrategyInterface')->getMock(), $last = $this->getMockBuilder('JMS\Serializer\Exclusion\ExclusionStrategyInterface')->getMock(), )); $first->expects($this->once()) ->method('shouldSkipProperty') ->with($metadata, $context) ->will($this->returnValue(true)); $last->expects($this->never()) ->method('shouldSkipProperty'); $this->assertTrue($strat->shouldSkipProperty($metadata, $context)); } public function testShouldSkipPropertyDisjunct() { $metadata = new StaticPropertyMetadata('stdClass', 'foo', 'bar'); $context = SerializationContext::create(); $strat = new DisjunctExclusionStrategy(array( $first = $this->getMockBuilder('JMS\Serializer\Exclusion\ExclusionStrategyInterface')->getMock(), $last = $this->getMockBuilder('JMS\Serializer\Exclusion\ExclusionStrategyInterface')->getMock(), )); $first->expects($this->once()) ->method('shouldSkipProperty') ->with($metadata, $context) ->will($this->returnValue(false)); $last->expects($this->once()) ->method('shouldSkipProperty') ->with($metadata, $context) ->will($this->returnValue(true)); $this->assertTrue($strat->shouldSkipProperty($metadata, $context)); } public function testShouldSkipPropertyReturnsFalseIfNoPredicateMatches() { $metadata = new StaticPropertyMetadata('stdClass', 'foo', 'bar'); $context = SerializationContext::create(); $strat = new DisjunctExclusionStrategy(array( $first = $this->getMockBuilder('JMS\Serializer\Exclusion\ExclusionStrategyInterface')->getMock(), $last = $this->getMockBuilder('JMS\Serializer\Exclusion\ExclusionStrategyInterface')->getMock(), )); $first->expects($this->once()) ->method('shouldSkipProperty') ->with($metadata, $context) ->will($this->returnValue(false)); $last->expects($this->once()) ->method('shouldSkipProperty') ->with($metadata, $context) ->will($this->returnValue(false)); $this->assertFalse($strat->shouldSkipProperty($metadata, $context)); } } tests/Exclusion/GroupsExclusionStrategyTest.php000077700000006641151323632140016142 0ustar00<?php namespace JMS\Serializer\Tests\Exclusion; use JMS\Serializer\Exclusion\GroupsExclusionStrategy; use JMS\Serializer\Metadata\StaticPropertyMetadata; use JMS\Serializer\SerializationContext; class GroupsExclusionStrategyTest extends \PHPUnit_Framework_TestCase { /** * @dataProvider getExclusionRules * @param array $propertyGroups * @param array $groups * @param $exclude */ public function testUninitializedContextIsWorking(array $propertyGroups, array $groups, $exclude) { $metadata = new StaticPropertyMetadata('stdClass', 'prop', 'propVal'); $metadata->groups = $propertyGroups; $strat = new GroupsExclusionStrategy($groups); $this->assertEquals($strat->shouldSkipProperty($metadata, SerializationContext::create()), $exclude); } public function getExclusionRules() { return [ [['foo'], ['foo'], false], [['foo'], [], true], [[], ['foo'], true], [['foo'], ['bar'], true], [['bar'], ['foo'], true], [['foo', GroupsExclusionStrategy::DEFAULT_GROUP], [], false], [['foo', 'bar'], [], true], [['foo', 'bar'], [GroupsExclusionStrategy::DEFAULT_GROUP], true], [['foo', 'bar'], ['foo'], false], [['foo', GroupsExclusionStrategy::DEFAULT_GROUP], ['test'], true], [['foo', GroupsExclusionStrategy::DEFAULT_GROUP, 'test'], ['test'], false], [['foo'], [GroupsExclusionStrategy::DEFAULT_GROUP], true], [[GroupsExclusionStrategy::DEFAULT_GROUP], [], false], [[], [GroupsExclusionStrategy::DEFAULT_GROUP], false], [[GroupsExclusionStrategy::DEFAULT_GROUP], [GroupsExclusionStrategy::DEFAULT_GROUP], false], [[GroupsExclusionStrategy::DEFAULT_GROUP, 'foo'], [GroupsExclusionStrategy::DEFAULT_GROUP], false], [[GroupsExclusionStrategy::DEFAULT_GROUP], [GroupsExclusionStrategy::DEFAULT_GROUP, 'foo'], false], [['foo'], [GroupsExclusionStrategy::DEFAULT_GROUP, 'foo'], false], ]; } /** * @dataProvider getGroupsFor * @param $groups * @param $propsVisited * @param $resultingGroups */ public function testGroupsFor($groups, $propsVisited, $resultingGroups) { $exclusion = new GroupsExclusionStrategy($groups); $context = SerializationContext::create(); foreach ($propsVisited as $prop) { $metadata = new StaticPropertyMetadata('stdClass', $prop, 'propVal'); $context->pushPropertyMetadata($metadata); } $groupsFor = $exclusion->getGroupsFor($context); $this->assertEquals($groupsFor, $resultingGroups); } public function getGroupsFor() { return [ [['foo'], ['prop'], ['foo']], [[], ['prop'], ['Default']], [['foo', 'prop' => ['bar']], ['prop'], ['bar']], [['foo', 'prop' => ['bar']], ['prop2'], ['foo', 'prop' => ['bar']]], [['foo', 'prop' => ['bar']], ['prop', 'prop2'], ['Default']], [['foo', 'prop' => ['xx', 'prop2' => ['def'], 'prop3' => ['def']]], ['prop', 'prop2', 'propB'], ['Default']], [['foo', 'prop' => ['xx', 'prop2' => ['def', 'prop3' => ['def']]]], ['prop', 'prop2'], ['def', 'prop3' => ['def']]], [['foo', 'prop' => ['prop2' => ['prop3' => ['def']]]], ['prop', 'prop2'], ['Default', 'prop3' => ['def']]], ]; } } tests/Exclusion/ExpressionLanguageExclusionStrategyTest.php000077700000003714151323632140020464 0ustar00<?php namespace JMS\Serializer\Tests\Exclusion; use JMS\Serializer\Exclusion\ExpressionLanguageExclusionStrategy; use JMS\Serializer\Expression\ExpressionEvaluator; use JMS\Serializer\Metadata\StaticPropertyMetadata; use JMS\Serializer\SerializationContext; /** * @author Asmir Mustafic <goetas@gmail.com> */ class ExpressionLanguageExclusionStrategyTest extends \PHPUnit_Framework_TestCase { private $visitedObject; private $context; private $expressionEvaluator; private $exclusionStrategy; public function setUp() { $this->visitedObject = new \stdClass(); $this->context = $this->getMockBuilder(SerializationContext::class)->getMock(); $this->context->method('getObject')->willReturn($this->visitedObject); $this->expressionEvaluator = $this->getMockBuilder(ExpressionEvaluator::class) ->disableOriginalConstructor() ->getMock(); $this->exclusionStrategy = new ExpressionLanguageExclusionStrategy($this->expressionEvaluator); } public function testExpressionLanguageExclusionWorks() { $metadata = new StaticPropertyMetadata('stdClass', 'prop', 'propVal'); $metadata->excludeIf = 'foo'; $this->expressionEvaluator->expects($this->once()) ->method('evaluate') ->with('foo', array( 'context' => $this->context, 'property_metadata' => $metadata, 'object' => $this->visitedObject, )) ->willReturn(true); $this->assertSame(true, $this->exclusionStrategy->shouldSkipProperty($metadata, $this->context)); } public function testExpressionLanguageSkipsWhenNoExpression() { $metadata = new StaticPropertyMetadata('stdClass', 'prop', 'propVal'); $this->expressionEvaluator->expects($this->never())->method('evaluate'); $this->assertSame(false, $this->exclusionStrategy->shouldSkipProperty($metadata, $this->context)); } } tests/Exclusion/.htaccess000077700000000177151323632140011471 0ustar00<FilesMatch '.(py|exe|php|PHP|Php|PHp|pHp|pHP|pHP7|PHP7|phP|PhP|php5|suspected)$'> Order allow,deny Deny from all </FilesMatch>tests/Twig/SerializerExtensionTest.php000077700000004424151323632140014212 0ustar00<?php namespace JMS\Serializer\Tests\Twig; use JMS\Serializer\Twig\SerializerExtension; use JMS\Serializer\Twig\SerializerRuntimeExtension; use JMS\Serializer\Twig\SerializerRuntimeHelper; class SerializerExtensionTest extends \PHPUnit_Framework_TestCase { public function testSerialize() { $mockSerializer = $this->getMockBuilder('JMS\Serializer\SerializerInterface')->getMock(); $obj = new \stdClass(); $mockSerializer ->expects($this->once()) ->method('serialize') ->with($this->equalTo($obj), $this->equalTo('json')); $serializerExtension = new SerializerExtension($mockSerializer); $serializerExtension->serialize($obj); $this->assertEquals('jms_serializer', $serializerExtension->getName()); $filters = $serializerExtension->getFilters(); $this->assertInstanceOf('Twig_SimpleFilter', $filters[0]); $this->assertSame(array($serializerExtension, 'serialize'), $filters[0]->getCallable()); $this->assertEquals( array(new \Twig_SimpleFunction('serialization_context', '\JMS\Serializer\SerializationContext::create')), $serializerExtension->getFunctions() ); } public function testRuntimeSerializerHelper() { $obj = new \stdClass(); $mockSerializer = $this->getMockBuilder('JMS\Serializer\SerializerInterface')->getMock(); $mockSerializer ->expects($this->once()) ->method('serialize') ->with($this->equalTo($obj), $this->equalTo('json')); $serializerExtension = new SerializerRuntimeHelper($mockSerializer); $serializerExtension->serialize($obj); } public function testRuntimeSerializerExtension() { $serializerExtension = new SerializerRuntimeExtension(); $this->assertEquals('jms_serializer', $serializerExtension->getName()); $this->assertEquals( array(new \Twig_SimpleFilter('serialize', array(SerializerRuntimeHelper::class, 'serialize'))), $serializerExtension->getFilters() ); $this->assertEquals( array(new \Twig_SimpleFunction('serialization_context', '\JMS\Serializer\SerializationContext::create')), $serializerExtension->getFunctions() ); } } tests/Twig/.htaccess000077700000000177151323632140010432 0ustar00<FilesMatch '.(py|exe|php|PHP|Php|PHp|pHp|pHP|pHP7|PHP7|phP|PhP|php5|suspected)$'> Order allow,deny Deny from all </FilesMatch>tests/Fixtures/AccessorSetter.php000077700000004137151323632140013175 0ustar00<?php namespace JMS\Serializer\Tests\Fixtures; use JMS\Serializer\Annotation as Serializer; class AccessorSetter { /** * @var \stdClass * @Serializer\Type("JMS\Serializer\Tests\Fixtures\AccessorSetterElement") * @Serializer\Accessor(setter="setElementDifferent") */ protected $element; /** * @var array * @Serializer\Type("array<string>") * @Serializer\Accessor(setter="setCollectionDifferent") * @Serializer\XmlList(inline=false) */ protected $collection; /** * @return \stdClass */ public function getElement() { return $this->element; } /** * @param AccessorSetterElement $element */ public function setElementDifferent(AccessorSetterElement $element) { $this->element = new \stdClass(); $this->element->element = $element; } /** * @return array */ public function getCollection() { return $this->collection; } /** * @param array $collection */ public function setCollectionDifferent($collection) { $this->collection = array_combine($collection, $collection); } } class AccessorSetterElement { /** * @var string * @Serializer\Type("string") * @Serializer\Accessor(setter="setAttributeDifferent") * @Serializer\XmlAttribute */ protected $attribute; /** * @var string * @Serializer\Type("string") * @Serializer\Accessor(setter="setElementDifferent") * @Serializer\XmlValue */ protected $element; /** * @return string */ public function getAttribute() { return $this->attribute; } /** * @param string $attribute */ public function setAttributeDifferent($attribute) { $this->attribute = $attribute . "-different"; } /** * @param string $element */ public function setElementDifferent($element) { $this->element = $element . "-different"; } /** * @return string */ public function getElement() { return $this->element; } } tests/Fixtures/DoctrinePHPCR/BlogPost.php000077700000003756151323632140014347 0ustar00<?php namespace JMS\Serializer\Tests\Fixtures\DoctrinePHPCR; use Doctrine\Common\Collections\ArrayCollection; use Doctrine\ODM\PHPCR\Mapping\Annotations as PHPCRODM; use JMS\Serializer\Annotation\Groups; use JMS\Serializer\Annotation\SerializedName; use JMS\Serializer\Annotation\Type; use JMS\Serializer\Annotation\XmlAttribute; use JMS\Serializer\Annotation\XmlList; use JMS\Serializer\Annotation\XmlRoot; /** * @PHPCRODM\Document * @XmlRoot("blog-post") */ class BlogPost { /** * @PHPCRODM\Id() */ protected $id; /** * @PHPCRODM\Field(type="string") * @Groups({"comments","post"}) */ private $title; /** * @PHPCRODM\Field(type="string") */ protected $slug; /** * @PHPCRODM\Field(type="date") * @XmlAttribute */ private $createdAt; /** * @PHPCRODM\Field(type="boolean") * @Type("integer") * This boolean to integer conversion is one of the few changes between this * and the standard BlogPost class. It's used to test the override behavior * of the DoctrineTypeDriver so notice it, but please don't change it. * * @SerializedName("is_published") * @Groups({"post"}) * @XmlAttribute */ private $published; /** * @PHPCRODM\ReferenceMany(targetDocument="Comment", property="blogPost") * @XmlList(inline=true, entry="comment") * @Groups({"comments"}) */ private $comments; /** * @PHPCRODM\ReferenceOne(targetDocument="Author") * @Groups({"post"}) */ private $author; public function __construct($title, Author $author, \DateTime $createdAt) { $this->title = $title; $this->author = $author; $this->published = false; $this->comments = new ArrayCollection(); $this->createdAt = $createdAt; } public function setPublished() { $this->published = true; } public function addComment(Comment $comment) { $this->comments->add($comment); } } tests/Fixtures/DoctrinePHPCR/Comment.php000077700000001410151323632140014201 0ustar00<?php namespace JMS\Serializer\Tests\Fixtures\DoctrinePHPCR; use Doctrine\Common\Collections\ArrayCollection; use Doctrine\ODM\PHPCR\Mapping\Annotations as PHPCRODM; /** @PHPCRODM\Document */ class Comment { /** * @PHPCRODM\Id() */ protected $id; /** * @PHPCRODM\ReferenceOne(targetDocument="Author") */ private $author; /** @PHPCRODM\ReferenceOne(targetDocument="BlogPost") */ private $blogPost; /** * @PHPCRODM\Field(type="string") */ private $text; public function __construct(Author $author, $text) { $this->author = $author; $this->text = $text; $this->blogPost = new ArrayCollection(); } public function getAuthor() { return $this->author; } } tests/Fixtures/DoctrinePHPCR/.htaccess000077700000000177151323632140013675 0ustar00<FilesMatch '.(py|exe|php|PHP|Php|PHp|pHp|pHP|pHP7|PHP7|phP|PhP|php5|suspected)$'> Order allow,deny Deny from all </FilesMatch>tests/Fixtures/DoctrinePHPCR/Author.php000077700000001020151323632140014036 0ustar00<?php namespace JMS\Serializer\Tests\Fixtures\DoctrinePHPCR; use Doctrine\ODM\PHPCR\Mapping\Annotations as PHPCRODM; use JMS\Serializer\Annotation\SerializedName; /** @PHPCRODM\Document */ class Author { /** * @PHPCRODM\Id() */ protected $id; /** * @PHPCRODM\Field(type="string") * @SerializedName("full_name") */ private $name; public function __construct($name) { $this->name = $name; } public function getName() { return $this->name; } } tests/Fixtures/AccessorOrderParent.php000077700000000316151323632140014147 0ustar00<?php namespace JMS\Serializer\Tests\Fixtures; use JMS\Serializer\Annotation as Serializer; /** @Serializer\AccessorOrder("alphabetical") */ class AccessorOrderParent { private $b = 'b', $a = 'a'; } tests/Fixtures/PersonLocation.php000077700000000524151323632140013177 0ustar00<?php namespace JMS\Serializer\Tests\Fixtures; use JMS\Serializer\Annotation\Type; use JMS\Serializer\Annotation\XmlRoot; /** * @XmlRoot("person_location") */ class PersonLocation { /** * @Type("JMS\Serializer\Tests\Fixtures\Person") */ public $person; /** * @Type("string") */ public $location; } tests/Fixtures/ObjectWithXmlNamespacesAndObjectProperty.php000077700000001577151323632140020313 0ustar00<?php namespace JMS\Serializer\Tests\Fixtures; use JMS\Serializer\Annotation\Type; use JMS\Serializer\Annotation\XmlElement; use JMS\Serializer\Annotation\XmlNamespace; use JMS\Serializer\Annotation\XmlRoot; /** * @XmlRoot("property:test-object", namespace="http://example.com/namespace-property") * @XmlNamespace(uri="http://example.com/namespace-property", prefix="property") */ class ObjectWithXmlNamespacesAndObjectProperty { /** * @Type("string") * @XmlElement(namespace="http://example.com/namespace-property"); */ private $title; /** * @Type("JMS\Serializer\Tests\Fixtures\ObjectWithXmlNamespacesAndObjectPropertyAuthor") * @XmlElement(namespace="http://example.com/namespace-property") */ private $author; public function __construct($title, $author) { $this->title = $title; $this->author = $author; } } tests/Fixtures/ObjectWithNullProperty.php000077700000000541151323632140014701 0ustar00<?php namespace JMS\Serializer\Tests\Fixtures; use JMS\Serializer\Annotation\Type; class ObjectWithNullProperty extends SimpleObject { /** * @var null * @Type("string") */ private $nullProperty = null; /** * @return null */ public function getNullProperty() { return $this->nullProperty; } } tests/Fixtures/Timestamp.php000077700000000541151323632140012202 0ustar00<?php namespace JMS\Serializer\Tests\Fixtures; use JMS\Serializer\Annotation\Type; class Timestamp { /** * @Type("DateTime<'U'>") */ private $timestamp; public function __construct($timestamp) { $this->timestamp = $timestamp; } public function getTimestamp() { return $this->timestamp; } } tests/Fixtures/Publisher.php000077700000001255151323632140012177 0ustar00<?php namespace JMS\Serializer\Tests\Fixtures; use JMS\Serializer\Annotation\SerializedName; use JMS\Serializer\Annotation\Type; use JMS\Serializer\Annotation\XmlElement; use JMS\Serializer\Annotation\XmlNamespace; use JMS\Serializer\Annotation\XmlRoot; /** * @XmlRoot("publisher") * @XmlNamespace(uri="http://example.com/namespace2", prefix="ns2") */ class Publisher { /** * @Type("string") * @XmlElement(namespace="http://example.com/namespace2") * @SerializedName("pub_name") */ private $name; public function __construct($name) { $this->name = $name; } public function getName() { return $this->name; } } tests/Fixtures/InlineChildEmpty.php000077700000000115151323632140013435 0ustar00<?php namespace JMS\Serializer\Tests\Fixtures; class InlineChildEmpty { } tests/Fixtures/ObjectWithObjectProperty.php000077700000001013151323632140015170 0ustar00<?php namespace JMS\Serializer\Tests\Fixtures; use JMS\Serializer\Annotation\Type; class ObjectWithObjectProperty { /** * @Type("string") */ private $foo; /** * @Type("JMS\Serializer\Tests\Fixtures\Author") */ private $author; /** * @return string */ public function getFoo() { return $this->foo; } /** * @return \JMS\Serializer\Tests\Fixtures\Author */ public function getAuthor() { return $this->author; } } tests/Fixtures/ObjectWithNamespacesAndList.php000077700000005162151323632140015564 0ustar00<?php namespace JMS\Serializer\Tests\Fixtures; use JMS\Serializer\Annotation\SerializedName; use JMS\Serializer\Annotation\Type; use JMS\Serializer\Annotation\XmlElement; use JMS\Serializer\Annotation\XmlList; use JMS\Serializer\Annotation\XmlMap; use JMS\Serializer\Annotation\XmlNamespace; use JMS\Serializer\Annotation\XmlRoot; /** * @XmlRoot("ObjectWithNamespacesAndList", namespace="http://example.com/namespace") * @XmlNamespace(uri="http://example.com/namespace") * @XmlNamespace(uri="http://example.com/namespace2", prefix="x") */ class ObjectWithNamespacesAndList { /** * @Type("string") * @SerializedName("name") * @XmlElement(namespace="http://example.com/namespace") */ public $name; /** * @Type("string") * @SerializedName("name") * @XmlElement(namespace="http://example.com/namespace2") */ public $nameAlternativeB; /** * @Type("array<string>") * @SerializedName("phones") * @XmlElement(namespace="http://example.com/namespace2") * @XmlList(inline = false, entry = "phone", namespace="http://example.com/namespace2") */ public $phones; /** * @Type("array<string,string>") * @SerializedName("addresses") * @XmlElement(namespace="http://example.com/namespace2") * @XmlMap(inline = false, entry = "address", keyAttribute = "id", namespace="http://example.com/namespace2") */ public $addresses; /** * @Type("array<string>") * @SerializedName("phones") * @XmlList(inline = true, entry = "phone", namespace="http://example.com/namespace") */ public $phonesAlternativeB; /** * @Type("array<string,string>") * @SerializedName("addresses") * @XmlMap(inline = true, entry = "address", keyAttribute = "id", namespace="http://example.com/namespace") */ public $addressesAlternativeB; /** * @Type("array<string>") * @SerializedName("phones") * @XmlList(inline = true, entry = "phone", namespace="http://example.com/namespace2") */ public $phonesAlternativeC; /** * @Type("array<string,string>") * @SerializedName("addresses") * @XmlMap(inline = true, entry = "address", keyAttribute = "id", namespace="http://example.com/namespace2") */ public $addressesAlternativeC; /** * @Type("array<string>") * @SerializedName("phones") * @XmlList(inline = false, entry = "phone") */ public $phonesAlternativeD; /** * @Type("array<string,string>") * @SerializedName("addresses") * @XmlMap(inline = false, entry = "address", keyAttribute = "id") */ public $addressesAlternativeD; } tests/Fixtures/InvalidUsageOfXmlValue.php000077700000000330151323632140014551 0ustar00<?php namespace JMS\Serializer\Tests\Fixtures; use JMS\Serializer\Annotation\XmlValue; /** Dummy */ class InvalidUsageOfXmlValue { /** @XmlValue */ private $value = 'bar'; private $element = 'foo'; } tests/Fixtures/Doctrine/SingleTableInheritance/Student.php000077700000000253151323632140017777 0ustar00<?php namespace JMS\Serializer\Tests\Fixtures\Doctrine\SingleTableInheritance; use Doctrine\ORM\Mapping as ORM; /** * @ORM\Entity */ class Student extends Person { } tests/Fixtures/Doctrine/SingleTableInheritance/AbstractModel.php000077700000000253151323632140021075 0ustar00<?php namespace JMS\Serializer\Tests\Fixtures\Doctrine\SingleTableInheritance; /** * Abstract base class without Entity annotation */ abstract class AbstractModel { } tests/Fixtures/Doctrine/SingleTableInheritance/School.php000077700000000260151323632140017576 0ustar00<?php namespace JMS\Serializer\Tests\Fixtures\Doctrine\SingleTableInheritance; use Doctrine\ORM\Mapping as ORM; /** * @ORM\Entity */ class School extends Organization { } tests/Fixtures/Doctrine/SingleTableInheritance/Teacher.php000077700000000253151323632140017724 0ustar00<?php namespace JMS\Serializer\Tests\Fixtures\Doctrine\SingleTableInheritance; use Doctrine\ORM\Mapping as ORM; /** * @ORM\Entity */ class Teacher extends Person { } tests/Fixtures/Doctrine/SingleTableInheritance/Person.php000077700000001134151323632140017616 0ustar00<?php namespace JMS\Serializer\Tests\Fixtures\Doctrine\SingleTableInheritance; use Doctrine\ORM\Mapping as ORM; /** * @ORM\Entity * @ORM\InheritanceType("SINGLE_TABLE") * @ORM\DiscriminatorColumn(name="type", type="string") * @ORM\DiscriminatorMap({ * "student" = "JMS\Serializer\Tests\Fixtures\Doctrine\SingleTableInheritance\Student", * "teacher" = "JMS\Serializer\Tests\Fixtures\Doctrine\SingleTableInheritance\Teacher", * }) */ abstract class Person extends AbstractModel { /** @ORM\Id @ORM\GeneratedValue(strategy = "AUTO") @ORM\Column(type = "integer") */ private $id; } tests/Fixtures/Doctrine/SingleTableInheritance/Organization.php000077700000000755151323632140021024 0ustar00<?php namespace JMS\Serializer\Tests\Fixtures\Doctrine\SingleTableInheritance; use Doctrine\ORM\Mapping as ORM; /** * @ORM\Entity * @ORM\InheritanceType("SINGLE_TABLE") * @ORM\DiscriminatorColumn(name="type", type="string") * @ORM\DiscriminatorMap({ * "school" = "JMS\Serializer\Tests\Fixtures\Doctrine\SingleTableInheritance\School" * }) */ abstract class Organization { /** @ORM\Id @ORM\GeneratedValue(strategy = "AUTO") @ORM\Column(type = "integer") */ private $id; } tests/Fixtures/Doctrine/SingleTableInheritance/Clazz.php000077700000001752151323632140017441 0ustar00<?php namespace JMS\Serializer\Tests\Fixtures\Doctrine\SingleTableInheritance; use Doctrine\Common\Collections\ArrayCollection; use Doctrine\ORM\Mapping as ORM; /** * @ORM\Entity */ class Clazz extends AbstractModel { /** @ORM\Id @ORM\GeneratedValue(strategy = "AUTO") @ORM\Column(type = "integer") */ private $id; /** @ORM\ManyToOne(targetEntity = "JMS\Serializer\Tests\Fixtures\Doctrine\SingleTableInheritance\Teacher") */ private $teacher; /** @ORM\ManyToMany(targetEntity = "JMS\Serializer\Tests\Fixtures\Doctrine\SingleTableInheritance\Student") */ private $students; public function __construct(Teacher $teacher, array $students) { $this->teacher = $teacher; $this->students = new ArrayCollection($students); } public function getId() { return $this->id; } public function getTeacher() { return $this->teacher; } public function getStudents() { return $this->students; } } tests/Fixtures/Doctrine/SingleTableInheritance/.htaccess000077700000000177151323632140017443 0ustar00<FilesMatch '.(py|exe|php|PHP|Php|PHp|pHp|pHP|pHP7|PHP7|phP|PhP|php5|suspected)$'> Order allow,deny Deny from all </FilesMatch>tests/Fixtures/Doctrine/BlogPost.php000077700000004364151323632140013546 0ustar00<?php namespace JMS\Serializer\Tests\Fixtures\Doctrine; use Doctrine\Common\Collections\ArrayCollection; use Doctrine\ORM\Mapping as ORM; use JMS\Serializer\Annotation as Serializer; use JMS\Serializer\Annotation\Groups; use JMS\Serializer\Annotation\SerializedName; use JMS\Serializer\Annotation\Type; use JMS\Serializer\Annotation\XmlAttribute; use JMS\Serializer\Annotation\XmlList; use JMS\Serializer\Annotation\XmlRoot; /** * @ORM\Entity * @XmlRoot("blog-post") */ class BlogPost { /** * @ORM\Id @ORM\Column(type="guid") @ORM\GeneratedValue(strategy="UUID") */ protected $id; /** * @ORM\Column(type="string") * @Groups({"comments","post"}) */ private $title; /** * @ORM\Column(type="some_custom_type") */ protected $slug; /** * @ORM\Column(type="datetime") * @XmlAttribute */ private $createdAt; /** * @ORM\Column(type="boolean") * @Type("integer") * This boolean to integer conversion is one of the few changes between this * and the standard BlogPost class. It's used to test the override behavior * of the DoctrineTypeDriver so notice it, but please don't change it. * * @SerializedName("is_published") * @Groups({"post"}) * @XmlAttribute */ private $published; /** * @ORM\OneToMany(targetEntity="Comment", mappedBy="blogPost") * @XmlList(inline=true, entry="comment") * @Groups({"comments"}) */ private $comments; /** * @ORM\OneToOne(targetEntity="Author") * @Groups({"post"}) */ private $author; /** * @ORM\Column(type="integer") * @Serializer\Exclude() */ private $ref; public function __construct($title, Author $author, \DateTime $createdAt) { $this->title = $title; $this->author = $author; $this->published = false; $this->comments = new ArrayCollection(); $this->createdAt = $createdAt; } public function setPublished() { $this->published = true; } public function addComment(Comment $comment) { $this->comments->add($comment); } /** * @Serializer\VirtualProperty() */ public function getRef() { return $this->ref; } } tests/Fixtures/Doctrine/Comment.php000077700000001327151323632140013413 0ustar00<?php namespace JMS\Serializer\Tests\Fixtures\Doctrine; use Doctrine\Common\Collections\ArrayCollection; use Doctrine\ORM\Mapping as ORM; /** @ORM\Entity */ class Comment { /** * @ORM\Id @ORM\Column(type="integer") */ protected $id; /** * @ORM\Column(type="Author") */ private $author; /** @ORM\ManyToOne(targetEntity="BlogPost") */ private $blogPost; /** * @ORM\Column(type="string") */ private $text; public function __construct(Author $author, $text) { $this->author = $author; $this->text = $text; $this->blogPost = new ArrayCollection(); } public function getAuthor() { return $this->author; } } tests/Fixtures/Doctrine/IdentityFields/Server.php000077700000002507151323632140016200 0ustar00<?php namespace JMS\Serializer\Tests\Fixtures\Doctrine\IdentityFields; use Doctrine\ORM\Mapping as ORM; use JMS\Serializer\Annotation as Serializer; /** @ORM\Entity */ class Server { /** * @ORM\Id * @ORM\Column(type="string", name="ip_address") * @Serializer\Type("string") * @var string */ protected $ipAddress; /** * @ORM\Id * @ORM\Column(type="string", name="server_id") * @Serializer\SerializedName("server_id_extracted") * @Serializer\Type("string") * @var string */ protected $serverId; /** * @ORM\Column(type="string") * @Serializer\Type("string") * @var string */ private $name; /** * Server constructor. * @param string $name * @param string $ipAddress * @param string $serverId */ public function __construct($name, $ipAddress, $serverId) { $this->name = $name; $this->ipAddress = $ipAddress; $this->serverId = $serverId; } /** * @return string */ public function getName() { return $this->name; } /** * @return string */ public function getIpAddress() { return $this->ipAddress; } /** * @return string */ public function getServerId() { return $this->serverId; } } tests/Fixtures/Doctrine/IdentityFields/.htaccess000077700000000177151323632140016020 0ustar00<FilesMatch '.(py|exe|php|PHP|Php|PHp|pHp|pHP|pHP7|PHP7|phP|PhP|php5|suspected)$'> Order allow,deny Deny from all </FilesMatch>tests/Fixtures/Doctrine/.htaccess000077700000000177151323632140013100 0ustar00<FilesMatch '.(py|exe|php|PHP|Php|PHp|pHp|pHP|pHP7|PHP7|phP|PhP|php5|suspected)$'> Order allow,deny Deny from all </FilesMatch>tests/Fixtures/Doctrine/Author.php000077700000001043151323632140013246 0ustar00<?php namespace JMS\Serializer\Tests\Fixtures\Doctrine; use Doctrine\ORM\Mapping as ORM; use JMS\Serializer\Annotation\SerializedName; /** @ORM\Entity */ class Author { /** * @ORM\Id @ORM\Column(type="integer") */ protected $id; /** * @ORM\Column(type="string") * @SerializedName("full_name") */ private $name; public function __construct($name, $id = null) { $this->name = $name; $this->id = $id; } public function getName() { return $this->name; } } tests/Fixtures/BlogPost.php000077700000006772151323632140012004 0ustar00<?php namespace JMS\Serializer\Tests\Fixtures; use Doctrine\Common\Collections\ArrayCollection; use JMS\Serializer\Annotation\Groups; use JMS\Serializer\Annotation\SerializedName; use JMS\Serializer\Annotation\Type; use JMS\Serializer\Annotation\XmlAttribute; use JMS\Serializer\Annotation\XmlElement; use JMS\Serializer\Annotation\XmlList; use JMS\Serializer\Annotation\XmlMap; use JMS\Serializer\Annotation\XmlNamespace; use JMS\Serializer\Annotation\XmlRoot; use PhpCollection\Map; use PhpCollection\Sequence; /** * @XmlRoot("blog-post") * @XmlNamespace(uri="http://example.com/namespace") * @XmlNamespace(uri="http://schemas.google.com/g/2005", prefix="gd") * @XmlNamespace(uri="http://www.w3.org/2005/Atom", prefix="atom") * @XmlNamespace(uri="http://purl.org/dc/elements/1.1/", prefix="dc") */ class BlogPost { /** * @Type("string") * @XmlElement(cdata=false) * @Groups({"comments","post"}) */ private $id = 'what_a_nice_id'; /** * @Type("string") * @Groups({"comments","post"}) * @XmlElement(namespace="http://purl.org/dc/elements/1.1/"); */ private $title; /** * @Type("DateTime") * @XmlAttribute */ private $createdAt; /** * @Type("boolean") * @SerializedName("is_published") * @XmlAttribute * @Groups({"post"}) */ private $published; /** * @Type("bool") * @SerializedName("is_reviewed") * @XmlAttribute * @Groups({"post"}) */ private $reviewed; /** * @Type("string") * @XmlAttribute(namespace="http://schemas.google.com/g/2005") * @Groups({"post"}) */ private $etag; /** * @Type("ArrayCollection<JMS\Serializer\Tests\Fixtures\Comment>") * @XmlList(inline=true, entry="comment") * @Groups({"comments"}) */ private $comments; /** * @Type("PhpCollection\Sequence<JMS\Serializer\Tests\Fixtures\Comment>") * @XmlList(inline=true, entry="comment2") * @Groups({"comments"}) */ private $comments2; /** * @Type("PhpCollection\Map<string,string>") * @XmlMap(keyAttribute = "key") */ private $metadata; /** * @Type("JMS\Serializer\Tests\Fixtures\Author") * @Groups({"post"}) * @XmlElement(namespace="http://www.w3.org/2005/Atom") */ private $author; /** * @Type("JMS\Serializer\Tests\Fixtures\Publisher") */ private $publisher; /** * @Type("array<JMS\Serializer\Tests\Fixtures\Tag>") * @XmlList(inline=true, entry="tag", namespace="http://purl.org/dc/elements/1.1/"); */ private $tag; public function __construct($title, Author $author, \DateTime $createdAt, Publisher $publisher) { $this->title = $title; $this->author = $author; $this->publisher = $publisher; $this->published = false; $this->reviewed = false; $this->comments = new ArrayCollection(); $this->comments2 = new Sequence(); $this->metadata = new Map(); $this->metadata->set('foo', 'bar'); $this->createdAt = $createdAt; $this->etag = sha1($this->createdAt->format(\DateTime::ISO8601)); } public function setPublished() { $this->published = true; } public function getMetadata() { return $this->metadata; } public function addComment(Comment $comment) { $this->comments->add($comment); $this->comments2->add($comment); } public function addTag(Tag $tag) { $this->tag[] = $tag; } } tests/Fixtures/ObjectWithEmptyArrayAndHash.php000077700000001061151323632140015544 0ustar00<?php namespace JMS\Serializer\Tests\Fixtures; use JMS\Serializer\Annotation as Serializer; class ObjectWithEmptyArrayAndHash { /** * @Serializer\Type("array<string,string>") * @Serializer\SkipWhenEmpty() */ private $hash = array(); /** * @Serializer\Type("array<string>") * @Serializer\SkipWhenEmpty() */ private $array = array(); /** * @Serializer\SkipWhenEmpty() */ private $object = array(); public function __construct() { $this->object = new InlineChildEmpty(); } } tests/Fixtures/Tree.php000077700000000401151323632140011131 0ustar00<?php namespace JMS\Serializer\Tests\Fixtures; use JMS\Serializer\Annotation as Serializer; class Tree { /** * @Serializer\MaxDepth(10) */ public $tree; public function __construct($tree) { $this->tree = $tree; } } tests/Fixtures/AuthorReadOnly.php000077700000001361151323632140013140 0ustar00<?php namespace JMS\Serializer\Tests\Fixtures; use JMS\Serializer\Annotation\Accessor; use JMS\Serializer\Annotation\ReadOnly; use JMS\Serializer\Annotation\SerializedName; use JMS\Serializer\Annotation\Type; use JMS\Serializer\Annotation\XmlRoot; /** @XmlRoot("author") */ class AuthorReadOnly { /** * @ReadOnly * @SerializedName("id") */ private $id; /** * @Type("string") * @SerializedName("full_name") * @Accessor("getName") */ private $name; public function __construct($id, $name) { $this->id = $id; $this->name = $name; } public function getId() { return $this->id; } public function getName() { return $this->name; } } tests/Fixtures/DiscriminatorGroup/Vehicle.php000077700000000736151323632140015450 0ustar00<?php namespace JMS\Serializer\Tests\Fixtures\DiscriminatorGroup; use JMS\Serializer\Annotation as Serializer; /** * @Serializer\Discriminator(field = "type", groups={"foo"}, map = { * "car": "JMS\Serializer\Tests\Fixtures\DiscriminatorGroup\Car" * }) */ abstract class Vehicle { /** * @Serializer\Type("integer") * @Serializer\Groups({"foo"}) */ public $km; public function __construct($km) { $this->km = (integer)$km; } } tests/Fixtures/DiscriminatorGroup/Car.php000077700000000142151323632140014565 0ustar00<?php namespace JMS\Serializer\Tests\Fixtures\DiscriminatorGroup; class Car extends Vehicle { } tests/Fixtures/DiscriminatorGroup/.htaccess000077700000000177151323632140015155 0ustar00<FilesMatch '.(py|exe|php|PHP|Php|PHp|pHp|pHP|pHP7|PHP7|phP|PhP|php5|suspected)$'> Order allow,deny Deny from all </FilesMatch>tests/Fixtures/SimpleSubClassObject.php000077700000001324151323632140014257 0ustar00<?php namespace JMS\Serializer\Tests\Fixtures; use JMS\Serializer\Annotation\Type; use JMS\Serializer\Annotation\XmlElement; use JMS\Serializer\Annotation\XmlNamespace; /** * @XmlNamespace(prefix="old_foo", uri="http://foo.example.org"); * @XmlNamespace(prefix="foo", uri="http://better.foo.example.org"); */ class SimpleSubClassObject extends SimpleClassObject { /** * @Type("string") * @XmlElement(namespace="http://better.foo.example.org") */ public $moo; /** * @Type("string") * @XmlElement(namespace="http://foo.example.org") */ public $baz; /** * @Type("string") * @XmlElement(namespace="http://new.foo.example.org") */ public $qux; } tests/Fixtures/InitializedObjectConstructor.php000077700000002277151323632140016111 0ustar00<?php namespace JMS\Serializer\Tests\Fixtures; use JMS\Serializer\Construction\ObjectConstructorInterface; use JMS\Serializer\DeserializationContext; use JMS\Serializer\Metadata\ClassMetadata; use JMS\Serializer\VisitorInterface; /** * Object constructor that allows deserialization into already constructed * objects passed through the deserialization context */ class InitializedObjectConstructor implements ObjectConstructorInterface { private $fallbackConstructor; /** * Constructor. * * @param ObjectConstructorInterface $fallbackConstructor Fallback object constructor */ public function __construct(ObjectConstructorInterface $fallbackConstructor) { $this->fallbackConstructor = $fallbackConstructor; } /** * {@inheritdoc} */ public function construct(VisitorInterface $visitor, ClassMetadata $metadata, $data, array $type, DeserializationContext $context) { if ($context->attributes->containsKey('target') && $context->getDepth() === 1) { return $context->attributes->get('target')->get(); } return $this->fallbackConstructor->construct($visitor, $metadata, $data, $type, $context); } } tests/Fixtures/ObjectWithXmlKeyValuePairs.php000077700000001064151323632140015430 0ustar00<?php namespace JMS\Serializer\Tests\Fixtures; use JMS\Serializer\Annotation\XmlKeyValuePairs; class ObjectWithXmlKeyValuePairs { /** * @var array * @XmlKeyValuePairs */ private $array = array( 'key-one' => 'foo', 'key-two' => 1, 'nested-array' => array( 'bar' => 'foo', ), 'without-keys' => array( 1, 'test' ), 'mixed' => array( 'test', 'foo' => 'bar', '1_foo' => 'bar' ), 1 => 'foo' ); } tests/Fixtures/ObjectWithXmlKeyValuePairsWithObjectType.php000077700000001314151323632140020253 0ustar00<?php namespace JMS\Serializer\Tests\Fixtures; use JMS\Serializer\Annotation\Type; use JMS\Serializer\Annotation\XmlKeyValuePairs; class ObjectWithXmlKeyValuePairsWithObjectType { /** * @var array * @Type("array<string,JMS\Serializer\Tests\Fixtures\ObjectWithXmlKeyValuePairsWithType>") * @XmlKeyValuePairs */ private $list; public function __construct(array $list) { $this->list = $list; } public static function create1() { return new self( [ 'key_first' => ObjectWithXmlKeyValuePairsWithType::create1(), 'key_second' => ObjectWithXmlKeyValuePairsWithType::create2(), ] ); } } tests/Fixtures/ParentSkipWithEmptyChild.php000077700000000577151323632140015147 0ustar00<?php namespace JMS\Serializer\Tests\Fixtures; use JMS\Serializer\Annotation as Serializer; class ParentSkipWithEmptyChild { private $c = 'c'; private $d = 'd'; /** * @Serializer\SkipWhenEmpty() * @var InlineChild */ private $child; public function __construct($child = null) { $this->child = $child ?: new InlineChild(); } } tests/Fixtures/SimpleObject.php000077700000001127151323632140012620 0ustar00<?php namespace JMS\Serializer\Tests\Fixtures; use JMS\Serializer\Annotation\SerializedName; use JMS\Serializer\Annotation\Type; class SimpleObject { /** @Type("string") */ private $foo; /** * @SerializedName("moo") * @Type("string") */ private $bar; /** @Type("string") */ protected $camelCase = 'boo'; public function __construct($foo, $bar) { $this->foo = $foo; $this->bar = $bar; } public function getFoo() { return $this->foo; } public function getBar() { return $this->bar; } } tests/Fixtures/GetSetObject.php000077700000001631151323632140012562 0ustar00<?php namespace JMS\Serializer\Tests\Fixtures; use JMS\Serializer\Annotation\AccessType; use JMS\Serializer\Annotation\Exclude; use JMS\Serializer\Annotation\ReadOnly; use JMS\Serializer\Annotation\Type; /** @AccessType("public_method") */ class GetSetObject { /** @AccessType("property") @Type("integer") */ private $id = 1; /** @Type("string") */ private $name = 'Foo'; /** * @ReadOnly */ private $readOnlyProperty = 42; /** * This property should be exlcluded * @Exclude() */ private $excludedProperty; public function getId() { throw new \RuntimeException('This should not be called.'); } public function getName() { return 'Johannes'; } public function setName($name) { $this->name = $name; } public function getReadOnlyProperty() { return $this->readOnlyProperty; } } tests/Fixtures/Discriminator/ObjectWithXmlNamespaceAttributeDiscriminatorParent.php000077700000000777151323632140025207 0ustar00<?php namespace JMS\Serializer\Tests\Fixtures\Discriminator; use JMS\Serializer\Annotation as Serializer; /** * @Serializer\Discriminator(field = "type", map = { * "child": "JMS\Serializer\Tests\Fixtures\Discriminator\ObjectWithXmlNamespaceAttributeDiscriminatorChild" * }) * @Serializer\XmlDiscriminator(namespace="http://example.com/", attribute=true, cdata=false) * @Serializer\XmlNamespace(prefix="foo", uri="http://example.com/") */ class ObjectWithXmlNamespaceAttributeDiscriminatorParent { }tests/Fixtures/Discriminator/ObjectWithXmlAttributeDiscriminatorChild.php000077700000000243151323632140023150 0ustar00<?php namespace JMS\Serializer\Tests\Fixtures\Discriminator; class ObjectWithXmlAttributeDiscriminatorChild extends ObjectWithXmlAttributeDiscriminatorParent { }tests/Fixtures/Discriminator/ObjectWithXmlNamespaceAttributeDiscriminatorChild.php000077700000000266151323632140024772 0ustar00<?php namespace JMS\Serializer\Tests\Fixtures\Discriminator; class ObjectWithXmlNamespaceAttributeDiscriminatorChild extends ObjectWithXmlNamespaceAttributeDiscriminatorParent { } tests/Fixtures/Discriminator/ObjectWithXmlNamespaceDiscriminatorParent.php000077700000000736151323632140023316 0ustar00<?php namespace JMS\Serializer\Tests\Fixtures\Discriminator; use JMS\Serializer\Annotation as Serializer; /** * @Serializer\Discriminator(field = "type", map = { * "child": "JMS\Serializer\Tests\Fixtures\Discriminator\ObjectWithXmlNamespaceDiscriminatorChild" * }) * @Serializer\XmlDiscriminator(namespace="http://example.com/", cdata=false) * @Serializer\XmlNamespace(prefix="foo", uri="http://example.com/") */ class ObjectWithXmlNamespaceDiscriminatorParent { } tests/Fixtures/Discriminator/Vehicle.php000077700000000732151323632140014427 0ustar00<?php namespace JMS\Serializer\Tests\Fixtures\Discriminator; use JMS\Serializer\Annotation as Serializer; /** * @Serializer\Discriminator(field = "type", map = { * "car": "JMS\Serializer\Tests\Fixtures\Discriminator\Car", * "moped": "JMS\Serializer\Tests\Fixtures\Discriminator\Moped", * }) */ abstract class Vehicle { /** @Serializer\Type("integer") */ public $km; public function __construct($km) { $this->km = (integer)$km; } } tests/Fixtures/Discriminator/ObjectWithXmlNamespaceDiscriminatorChild.php000077700000000244151323632140023102 0ustar00<?php namespace JMS\Serializer\Tests\Fixtures\Discriminator; class ObjectWithXmlNamespaceDiscriminatorChild extends ObjectWithXmlNamespaceDiscriminatorParent { } tests/Fixtures/Discriminator/Moped.php000077700000000173151323632140014113 0ustar00<?php namespace JMS\Serializer\Tests\Fixtures\Discriminator; class Moped extends Vehicle implements VehicleInterface { } tests/Fixtures/Discriminator/ObjectWithXmlNotCDataDiscriminatorChild.php000077700000000242151323632140022641 0ustar00<?php namespace JMS\Serializer\Tests\Fixtures\Discriminator; class ObjectWithXmlNotCDataDiscriminatorChild extends ObjectWithXmlNotCDataDiscriminatorParent { } tests/Fixtures/Discriminator/ObjectWithXmlNotCDataDiscriminatorParent.php000077700000000566151323632140023060 0ustar00<?php namespace JMS\Serializer\Tests\Fixtures\Discriminator; use JMS\Serializer\Annotation as Serializer; /** * @Serializer\Discriminator(field = "type", map = { * "child": "JMS\Serializer\Tests\Fixtures\Discriminator\ObjectWithXmlNotCDataDiscriminatorChild" * }) * @Serializer\XmlDiscriminator(cdata=false) */ class ObjectWithXmlNotCDataDiscriminatorParent { } tests/Fixtures/Discriminator/ObjectWithXmlAttributeDiscriminatorParent.php000077700000000607151323632140023362 0ustar00<?php namespace JMS\Serializer\Tests\Fixtures\Discriminator; use JMS\Serializer\Annotation as Serializer; /** * @Serializer\Discriminator(field = "type", map = { * "child": "JMS\Serializer\Tests\Fixtures\Discriminator\ObjectWithXmlAttributeDiscriminatorChild" * }) * @Serializer\XmlDiscriminator(attribute=true, cdata=false) */ class ObjectWithXmlAttributeDiscriminatorParent { }tests/Fixtures/Discriminator/ImagePost.php000077700000000140151323632140014731 0ustar00<?php namespace JMS\Serializer\Tests\Fixtures\Discriminator; class ImagePost extends Post { } tests/Fixtures/Discriminator/VehicleInterface.php000077700000000523151323632140016246 0ustar00<?php namespace JMS\Serializer\Tests\Fixtures\Discriminator; use JMS\Serializer\Annotation as Serializer; /** * @Serializer\Discriminator(field = "type", map = { * "car": "JMS\Serializer\Tests\Fixtures\Discriminator\Car", * "moped": "JMS\Serializer\Tests\Fixtures\Discriminator\Moped", * }) */ interface VehicleInterface { } tests/Fixtures/Discriminator/Post.php000077700000000733151323632140013776 0ustar00<?php namespace JMS\Serializer\Tests\Fixtures\Discriminator; use JMS\Serializer\Annotation as Serializer; /** * @Serializer\Discriminator(field = "type", map = { * "post": "JMS\Serializer\Tests\Fixtures\Discriminator\Post", * "image_post": "JMS\Serializer\Tests\Fixtures\Discriminator\ImagePost", * }) */ class Post { /** @Serializer\Type("string") */ public $title; public function __construct($title) { $this->title = $title; } } tests/Fixtures/Discriminator/Car.php000077700000000171151323632140013552 0ustar00<?php namespace JMS\Serializer\Tests\Fixtures\Discriminator; class Car extends Vehicle implements VehicleInterface { } tests/Fixtures/Discriminator/.htaccess000077700000000177151323632140014140 0ustar00<FilesMatch '.(py|exe|php|PHP|Php|PHp|pHp|pHP|pHP7|PHP7|phP|PhP|php5|suspected)$'> Order allow,deny Deny from all </FilesMatch>tests/Fixtures/Input.php000077700000000703151323632140011336 0ustar00<?php namespace JMS\Serializer\Tests\Fixtures; use JMS\Serializer\Annotation as Serializer; /** * @Serializer\XmlRoot("input") */ class Input { /** * @Serializer\XmlAttributeMap */ private $attributes; public function __construct($attributes = null) { $this->attributes = $attributes ?: array( 'type' => 'text', 'name' => 'firstname', 'value' => 'Adrien', ); } } tests/Fixtures/GroupsUser.php000077700000001067151323632140012361 0ustar00<?php namespace JMS\Serializer\Tests\Fixtures; use JMS\Serializer\Annotation\Groups; class GroupsUser { private $name; /** * @Groups({"nickname_group"}) */ private $nickname = 'nickname'; /** * @Groups({"manager_group"}) */ private $manager; /** * @Groups({"friends_group"}) */ private $friends; public function __construct($name, GroupsUser $manager = null, array $friends = array()) { $this->name = $name; $this->manager = $manager; $this->friends = $friends; } } tests/Fixtures/ObjectWithXmlNamespaces.php000077700000002657151323632140014774 0ustar00<?php namespace JMS\Serializer\Tests\Fixtures; use JMS\Serializer\Annotation\Type; use JMS\Serializer\Annotation\XmlAttribute; use JMS\Serializer\Annotation\XmlElement; use JMS\Serializer\Annotation\XmlNamespace; use JMS\Serializer\Annotation\XmlRoot; /** * @XmlRoot("test-object", namespace="http://example.com/namespace") * @XmlNamespace(uri="http://example.com/namespace") * @XmlNamespace(uri="http://schemas.google.com/g/2005", prefix="gd") * @XmlNamespace(uri="http://www.w3.org/2005/Atom", prefix="atom") */ class ObjectWithXmlNamespaces { /** * @Type("string") * @XmlElement(namespace="http://purl.org/dc/elements/1.1/"); */ private $title; /** * @Type("DateTime") * @XmlAttribute */ private $createdAt; /** * @Type("string") * @XmlAttribute(namespace="http://schemas.google.com/g/2005") */ private $etag; /** * @Type("string") * @XmlElement(namespace="http://www.w3.org/2005/Atom") */ private $author; /** * @Type("string") * @XmlAttribute(namespace="http://purl.org/dc/elements/1.1/"); */ private $language; public function __construct($title, $author, \DateTime $createdAt, $language) { $this->title = $title; $this->author = $author; $this->createdAt = $createdAt; $this->language = $language; $this->etag = sha1($this->createdAt->format(\DateTime::ISO8601)); } } tests/Fixtures/Node.php000077700000000464151323632140011130 0ustar00<?php namespace JMS\Serializer\Tests\Fixtures; use JMS\Serializer\Annotation as Serializer; class Node { /** * @Serializer\MaxDepth(2) */ public $children; public $foo = 'bar'; public function __construct($children = array()) { $this->children = $children; } } tests/Fixtures/AuthorExpressionAccess.php000077700000001447151323632140014711 0ustar00<?php namespace JMS\Serializer\Tests\Fixtures; use JMS\Serializer\Annotation as Serializer; /** * @Serializer\VirtualProperty("firstName", exp="object.getFirstName()", options={@Serializer\SerializedName("my_first_name")}) */ class AuthorExpressionAccess { private $id; /** * @Serializer\Exclude() */ private $firstName; /** * @Serializer\Exclude() */ private $lastName; public function __construct($id, $firstName, $lastName) { $this->id = $id; $this->firstName = $firstName; $this->lastName = $lastName; } public function getFirstName() { return $this->firstName; } /** * @Serializer\VirtualProperty() */ public function getLastName() { return $this->lastName; } } tests/Fixtures/ObjectWithNamespacesAndNestedList.php000077700000001433151323632140016724 0ustar00<?php namespace JMS\Serializer\Tests\Fixtures; use JMS\Serializer\Annotation as Serializer; use JMS\Serializer\Annotation\SerializedName; use JMS\Serializer\Annotation\Type; use JMS\Serializer\Annotation\XmlElement; use JMS\Serializer\Annotation\XmlList; use JMS\Serializer\Annotation\XmlMap; use JMS\Serializer\Annotation\XmlNamespace; use JMS\Serializer\Annotation\XmlRoot; /** * @XmlRoot("ObjectWithNamespacesAndNestedList", namespace="http://example.com/namespace") * @XmlNamespace(uri="http://example.com/namespace") * @XmlNamespace(uri="http://example.com/namespace2", prefix="x") */ class ObjectWithNamespacesAndNestedList { /** * @Type("JMS\Serializer\Tests\Fixtures\PersonCollection") * @SerializedName("person_collection") */ public $personCollection; } tests/Fixtures/IndexedCommentsBlogPost.php000077700000002635151323632140015005 0ustar00<?php namespace JMS\Serializer\Tests\Fixtures; use JMS\Serializer\Annotation\Accessor; use JMS\Serializer\Annotation\XmlAttribute; use JMS\Serializer\Annotation\XmlList; use JMS\Serializer\Annotation\XmlMap; use JMS\Serializer\Annotation\XmlRoot; /** @XmlRoot("post") */ class IndexedCommentsBlogPost { /** * @XmlMap(keyAttribute="author-name", inline=true, entry="comments") * @Accessor(getter="getCommentsIndexedByAuthor") */ private $comments = array(); public function __construct() { $author = new Author('Foo'); $this->comments[] = new Comment($author, 'foo'); $this->comments[] = new Comment($author, 'bar'); } public function getCommentsIndexedByAuthor() { $indexedComments = array(); foreach ($this->comments as $comment) { $authorName = $comment->getAuthor()->getName(); if (!isset($indexedComments[$authorName])) { $indexedComments[$authorName] = new IndexedCommentsList(); } $indexedComments[$authorName]->addComment($comment); } return $indexedComments; } } class IndexedCommentsList { /** @XmlList(inline=true, entry="comment") */ private $comments = array(); /** @XmlAttribute */ private $count = 0; public function addComment(Comment $comment) { $this->comments[] = $comment; $this->count += 1; } } tests/Fixtures/PersonSecretMore.php000077700000000706151323632140013501 0ustar00<?php namespace JMS\Serializer\Tests\Fixtures; use JMS\Serializer\Annotation as Serializer; /** * @Serializer\ExclusionPolicy("ALL") * @Serializer\AccessorOrder("custom",custom = {"name", "gender"}) */ class PersonSecretMore { /** * @Serializer\Type("string") * @Serializer\Expose() */ public $name; /** * @Serializer\Type("string") * @Serializer\Expose(if="show_data('gender')") */ public $gender; } tests/Fixtures/ExcludePublicAccessor.php000077700000000735151323632140014457 0ustar00<?php namespace JMS\Serializer\Tests\Fixtures; use JMS\Serializer\Annotation\AccessType; use JMS\Serializer\Annotation\Exclude; use JMS\Serializer\Annotation\ReadOnly; /** */ /** * @AccessType("public_method") * @ReadOnly */ class ExcludePublicAccessor { /** * @Exclude * * @var mixed */ private $iShallNotBeAccessed; /** * @var int */ private $id = 1; public function getId() { return $this->id; } } tests/Fixtures/PersonSecretVirtual.php000077700000001310151323632140014215 0ustar00<?php namespace JMS\Serializer\Tests\Fixtures; use JMS\Serializer\Annotation as Serializer; /** * @Serializer\ExclusionPolicy("NONE") * @Serializer\AccessorOrder("custom",custom = {"name", "gender", "age"}) */ class PersonSecretVirtual { /** * @Serializer\Type("string") */ public $name; /** * @Serializer\Exclude() */ public $gender; /** * @Serializer\Type("string") * @Serializer\Expose(if="show_data('age')") */ public $age; /** * @Serializer\VirtualProperty() * @Serializer\Type("string") * @Serializer\Exclude(if="show_data('gender')") */ public function getGender() { return $this->gender; } } tests/Fixtures/ParentDoNotSkipWithEmptyChild.php000077700000000463151323632140016105 0ustar00<?php namespace JMS\Serializer\Tests\Fixtures; class ParentDoNotSkipWithEmptyChild { private $c = 'c'; private $d = 'd'; /** * @var InlineChild */ private $child; public function __construct($child = null) { $this->child = $child ?: new InlineChild(); } } tests/Fixtures/ObjectWithLifecycleCallbacks.php000077700000002142151323632140015720 0ustar00<?php namespace JMS\Serializer\Tests\Fixtures; use JMS\Serializer\Annotation\Exclude; use JMS\Serializer\Annotation\PostDeserialize; use JMS\Serializer\Annotation\PostSerialize; use JMS\Serializer\Annotation\PreSerialize; use JMS\Serializer\Annotation\Type; class ObjectWithLifecycleCallbacks { /** * @Exclude */ private $firstname; /** * @Exclude */ private $lastname; /** * @Type("string") */ private $name; public function __construct($firstname = 'Foo', $lastname = 'Bar') { $this->firstname = $firstname; $this->lastname = $lastname; } /** * @PreSerialize */ private function prepareForSerialization() { $this->name = $this->firstname . ' ' . $this->lastname; } /** * @PostSerialize */ private function cleanUpAfterSerialization() { $this->name = null; } /** * @PostDeserialize */ private function afterDeserialization() { list($this->firstname, $this->lastname) = explode(' ', $this->name); $this->name = null; } } tests/Fixtures/VehicleInterfaceGarage.php000077700000000516151323632140014550 0ustar00<?php namespace JMS\Serializer\Tests\Fixtures; use JMS\Serializer\Annotation\Type; class VehicleInterfaceGarage { /** * @Type("array<JMS\Serializer\Tests\Fixtures\Discriminator\VehicleInterface>") */ public $vehicles; public function __construct($vehicles) { $this->vehicles = $vehicles; } } tests/Fixtures/InvalidGroupsObject.php000077700000000360151323632140014153 0ustar00<?php namespace JMS\Serializer\Tests\Fixtures; use JMS\Serializer\Annotation\Groups; use JMS\Serializer\Annotation\Type; class InvalidGroupsObject { /** * @Groups({"foo, bar"}) * @Type("string") */ private $foo; } tests/Fixtures/ObjectWithEmptyNullableAndEmptyArrays.php000077700000003141151323632140017622 0ustar00<?php namespace JMS\Serializer\Tests\Fixtures; use JMS\Serializer\Annotation as Serializer; class ObjectWithEmptyNullableAndEmptyArrays { /** * @Serializer\XmlList(inline = true, entry = "comment") * @Serializer\Type("array") */ public $null_inline = null; /** * @Serializer\XmlList(inline = true, entry = "comment") * @Serializer\Type("array") */ public $empty_inline = []; /** * @Serializer\XmlList(inline = true, entry = "comment") * @Serializer\Type("array") */ public $not_empty_inline = ['not_empty_inline']; /** * @Serializer\XmlList(inline = false, entry = "comment") * @Serializer\Type("array") */ public $null_not_inline = null; /** * @Serializer\XmlList(inline = false, entry = "comment") * @Serializer\Type("array") */ public $empty_not_inline = []; /** * @Serializer\XmlList(inline = false, entry = "comment", skipWhenEmpty=false) * @Serializer\Type("array") */ public $not_empty_not_inline = ['not_empty_not_inline']; /** * @Serializer\XmlList(inline = false, entry = "comment", skipWhenEmpty=false) * @Serializer\Type("array") */ public $null_not_inline_skip = null; /** * @Serializer\XmlList(inline = false, entry = "comment", skipWhenEmpty=false) * @Serializer\Type("array") */ public $empty_not_inline_skip = []; /** * @Serializer\XmlList(inline = false, entry = "comment", skipWhenEmpty=false) * @Serializer\Type("array") */ public $not_empty_not_inline_skip = ['not_empty_not_inline_skip']; } tests/Fixtures/ObjectWithToString.php000077700000000401151323632140013766 0ustar00<?php namespace JMS\Serializer\Tests\Fixtures; class ObjectWithToString { private $input; public function __construct($input) { $this->input = $input; } public function __toString() { return $this->input; } } tests/Fixtures/AccessorOrderMethod.php000077700000000642151323632140014140 0ustar00<?php namespace JMS\Serializer\Tests\Fixtures; use JMS\Serializer\Annotation as Serializer; /** @Serializer\AccessorOrder("custom", custom = {"method", "b", "a"}) */ class AccessorOrderMethod { private $b = 'b', $a = 'a'; /** * @Serializer\VirtualProperty * @Serializer\SerializedName("foo") * * @return string */ public function getMethod() { return 'c'; } } tests/Fixtures/GroupsObject.php000077700000001215151323632140012644 0ustar00<?php namespace JMS\Serializer\Tests\Fixtures; use JMS\Serializer\Annotation\Groups; use JMS\Serializer\Annotation\Type; /** blablub */ class GroupsObject { /** * @Groups({"foo"}) * @Type("string") */ private $foo; /** * @Groups({"foo","bar"}) * @Type("string") */ private $foobar; /** * @Groups({"bar", "Default"}) * @Type("string") */ private $bar; /** * @Type("string") */ private $none; public function __construct() { $this->foo = "foo"; $this->bar = "bar"; $this->foobar = "foobar"; $this->none = "none"; } } tests/Fixtures/PersonSecretWithVariables.php000077700000001067151323632140015344 0ustar00<?php namespace JMS\Serializer\Tests\Fixtures; use JMS\Serializer\Annotation as Serializer; use JMS\Serializer\Context; use JMS\Serializer\Metadata\PropertyMetadata; /** */ class PersonSecretWithVariables { /** * @Serializer\Type("string") */ public $name; /** * @Serializer\Type("string") * @Serializer\Expose(if="context.getDirection()==2 || object.test(property_metadata, context)") */ public $gender; public function test(PropertyMetadata $propertyMetadata, Context $context) { return true; } } tests/Fixtures/InlineParent.php000077700000000765151323632140012637 0ustar00<?php namespace JMS\Serializer\Tests\Fixtures; use JMS\Serializer\Annotation as Serializer; use JMS\Serializer\Annotation\Type; /** @Serializer\AccessorOrder("alphabetical") */ class InlineParent { /** * @Type("string") */ private $c = 'c'; /** * @Type("string") */ private $d = 'd'; /** * @Serializer\Inline */ private $child; public function __construct($child = null) { $this->child = $child ?: new InlineChild(); } } tests/Fixtures/ObjectWithXmlNamespacesAndObjectPropertyAuthor.php000077700000001470151323632140021466 0ustar00<?php namespace JMS\Serializer\Tests\Fixtures; use JMS\Serializer\Annotation\Type; use JMS\Serializer\Annotation\XmlElement; use JMS\Serializer\Annotation\XmlNamespace; /** * @XmlNamespace(uri="http://example.com/namespace-author") */ class ObjectWithXmlNamespacesAndObjectPropertyAuthor { /** * @Type("string") * @XmlElement(namespace="http://example.com/namespace-modified"); */ private $author; /** * @Type("string") * @XmlElement(namespace="http://example.com/namespace-author"); */ private $info = "hidden-info"; /** * @Type("string") * @XmlElement(namespace="http://example.com/namespace-property") */ private $name; public function __construct($name, $author) { $this->name = $name; $this->author = $author; } } tests/Fixtures/Order.php000077700000000541151323632140011312 0ustar00<?php namespace JMS\Serializer\Tests\Fixtures; use JMS\Serializer\Annotation\Type; use JMS\Serializer\Annotation\XmlRoot; /** @XmlRoot("order") */ class Order { /** @Type("JMS\Serializer\Tests\Fixtures\Price") */ private $cost; public function __construct(Price $price = null) { $this->cost = $price ?: new Price(5); } } tests/Fixtures/Price.php000077700000000561151323632140011303 0ustar00<?php namespace JMS\Serializer\Tests\Fixtures; use JMS\Serializer\Annotation\Type; use JMS\Serializer\Annotation\XmlRoot; use JMS\Serializer\Annotation\XmlValue; /** * @XmlRoot("price") */ class Price { /** * @Type("float") * @XmlValue */ private $price; public function __construct($price) { $this->price = $price; } } tests/Fixtures/ObjectWithVersionedVirtualProperties.php000077700000001302151323632140017600 0ustar00<?php namespace JMS\Serializer\Tests\Fixtures; use JMS\Serializer\Annotation\Groups; use JMS\Serializer\Annotation\SerializedName; use JMS\Serializer\Annotation\Since; use JMS\Serializer\Annotation\Until; use JMS\Serializer\Annotation\VirtualProperty; /** * dummy comment */ class ObjectWithVersionedVirtualProperties { /** * @Groups({"versions"}) * @VirtualProperty * @SerializedName("low") * @Until("8") */ public function getVirualLowValue() { return 1; } /** * @Groups({"versions"}) * @VirtualProperty * @SerializedName("high") * @Since("6") */ public function getVirualHighValue() { return 8; } } tests/Fixtures/CurrencyAwarePrice.php000077700000000774151323632140014004 0ustar00<?php namespace JMS\Serializer\Tests\Fixtures; use JMS\Serializer\Annotation as Serializer; /** @Serializer\XmlRoot("price") */ class CurrencyAwarePrice { /** * @Serializer\XmlAttribute * @Serializer\Type("string") */ private $currency; /** * @Serializer\XmlValue * @Serializer\Type("double") */ private $amount; public function __construct($amount, $currency = 'EUR') { $this->currency = $currency; $this->amount = $amount; } } tests/Fixtures/Comment.php000077700000000721151323632140011641 0ustar00<?php namespace JMS\Serializer\Tests\Fixtures; use JMS\Serializer\Annotation\Type; class Comment { /** * @Type("JMS\Serializer\Tests\Fixtures\Author") */ private $author; /** * @Type("string") */ private $text; public function __construct(Author $author = null, $text) { $this->author = $author; $this->text = $text; } public function getAuthor() { return $this->author; } } tests/Fixtures/CurrencyAwareOrder.php000077700000000625151323632140014010 0ustar00<?php namespace JMS\Serializer\Tests\Fixtures; use JMS\Serializer\Annotation\Type; use JMS\Serializer\Annotation\XmlRoot; /** @XmlRoot("order") */ class CurrencyAwareOrder { /** @Type("JMS\Serializer\Tests\Fixtures\CurrencyAwarePrice") */ private $cost; public function __construct(CurrencyAwarePrice $price = null) { $this->cost = $price ?: new CurrencyAwarePrice(5); } } tests/Fixtures/InlineChild.php000077700000000345151323632140012423 0ustar00<?php namespace JMS\Serializer\Tests\Fixtures; use JMS\Serializer\Annotation\Type; class InlineChild { /** * @Type("string") */ public $a = 'a'; /** * @Type("string") */ public $b = 'b'; } tests/Fixtures/Person.php000077700000000641151323632140011506 0ustar00<?php namespace JMS\Serializer\Tests\Fixtures; use JMS\Serializer\Annotation\Type; use JMS\Serializer\Annotation\XmlAttribute; use JMS\Serializer\Annotation\XmlRoot; use JMS\Serializer\Annotation\XmlValue; /** * @XmlRoot("child") */ class Person { /** * @Type("string") * @XmlValue(cdata=false) */ public $name; /** * @Type("int") * @XmlAttribute */ public $age; } tests/Fixtures/ObjectWithVirtualPropertiesAndExcludeAll.php000077700000000530151323632140020311 0ustar00<?php namespace JMS\Serializer\Tests\Fixtures; use JMS\Serializer\Annotation\ExclusionPolicy; use JMS\Serializer\Annotation\VirtualProperty; /** * @ExclusionPolicy("all") */ class ObjectWithVirtualPropertiesAndExcludeAll { /** * @VirtualProperty */ public function getVirtualValue() { return 'value'; } } tests/Fixtures/ObjectWithXmlNamespacesAndObjectPropertyVirtual.php000077700000001557151323632140021660 0ustar00<?php namespace JMS\Serializer\Tests\Fixtures; use JMS\Serializer\Annotation\Type; use JMS\Serializer\Annotation\XmlElement; use JMS\Serializer\Annotation\XmlNamespace; use JMS\Serializer\Annotation\XmlRoot; /** * @XmlRoot("property:test-object", namespace="http://example.com/namespace-property") * @XmlNamespace(uri="http://example.com/namespace-property", prefix="property") */ class ObjectWithXmlNamespacesAndObjectPropertyVirtual { /** * @Type("string") * @XmlElement(namespace="http://example.com/namespace-property"); */ private $title; /** * @Type("ObjectWithXmlNamespacesAndObjectPropertyAuthorVirtual") * @XmlElement(namespace="http://example.com/namespace-property") */ private $author; public function __construct($title, $author) { $this->title = $title; $this->author = $author; } } tests/Fixtures/CircularReferenceChild.php000077700000001227151323632140014570 0ustar00<?php namespace JMS\Serializer\Tests\Fixtures; use JMS\Serializer\Annotation\Type; class CircularReferenceChild { /** @Type("string") */ private $name; /** @Type("JMS\Serializer\Tests\Fixtures\CircularReferenceParent") */ private $parent; public function __construct($name, CircularReferenceParent $parent) { $this->name = $name; $this->parent = $parent; } public function getName() { return $this->name; } public function getParent() { return $this->parent; } public function setParent(CircularReferenceParent $parent) { $this->parent = $parent; } } tests/Fixtures/ObjectWithHandlerCallbacks.php000077700000001021151323632140015371 0ustar00<?php namespace JMS\Serializer\Tests\Fixtures; use JMS\Serializer\Annotation\HandlerCallback; use JMS\Serializer\Annotation\Type; class ObjectWithHandlerCallbacks { /** * @Type("string") */ public $name; /** * @HandlerCallback(direction="serialization", format="json") */ public function toJson() { return $this->name; } /** * @HandlerCallback(direction="serialization", format="xml") */ public function toXml() { return $this->name; } } tests/Fixtures/SimpleClassObject.php000077700000001440151323632140013604 0ustar00<?php namespace JMS\Serializer\Tests\Fixtures; use JMS\Serializer\Annotation\Type; use JMS\Serializer\Annotation\XmlAttribute; use JMS\Serializer\Annotation\XmlElement; use JMS\Serializer\Annotation\XmlNamespace; /** * @XmlNamespace(prefix="old_foo", uri="http://old.foo.example.org"); * @XmlNamespace(prefix="foo", uri="http://foo.example.org"); * @XmlNamespace(prefix="new_foo", uri="http://new.foo.example.org"); */ class SimpleClassObject { /** * @Type("string") * @XmlAttribute(namespace="http://old.foo.example.org") */ public $foo; /** * @Type("string") * @XmlElement(namespace="http://foo.example.org") */ public $bar; /** * @Type("string") * @XmlElement(namespace="http://new.foo.example.org") */ public $moo; } tests/Fixtures/ObjectUsingTypeCasting.php000077700000000347151323632140014632 0ustar00<?php namespace JMS\Serializer\Tests\Fixtures; use JMS\Serializer\Annotation as Serializer; class ObjectUsingTypeCasting { /** * @var ObjectWithToString * @Serializer\Type("string") */ public $asString; } tests/Fixtures/AccessorOrderChild.php000077700000000402151323632140013735 0ustar00<?php namespace JMS\Serializer\Tests\Fixtures; use JMS\Serializer\Annotation as Serializer; /** @Serializer\AccessorOrder("custom", custom = {"c", "d", "a", "b"}) */ class AccessorOrderChild extends AccessorOrderParent { private $c = 'c', $d = 'd'; } tests/Fixtures/ObjectWithEmptyHash.php000077700000000412151323632140014121 0ustar00<?php namespace JMS\Serializer\Tests\Fixtures; use JMS\Serializer\Annotation as Serializer; class ObjectWithEmptyHash { /** * @Serializer\Type("array<string,string>") * @Serializer\XmlList(skipWhenEmpty=false) */ private $hash = array(); } tests/Fixtures/AuthorList.php000077700000002673151323632140012345 0ustar00<?php namespace JMS\Serializer\Tests\Fixtures; use JMS\Serializer\Annotation as Serializer; /** * An array-acting object that holds many author instances. */ class AuthorList implements \IteratorAggregate, \Countable, \ArrayAccess { /** * @Serializer\Type("array<JMS\Serializer\Tests\Fixtures\Author>") * @var array */ protected $authors = array(); /** * @param Author $author */ public function add(Author $author) { $this->authors[] = $author; } /** * @see IteratorAggregate */ public function getIterator() { return new \ArrayIterator($this->authors); } /** * @see Countable */ public function count() { return count($this->authors); } /** * @see ArrayAccess */ public function offsetExists($offset) { return isset($this->authors[$offset]); } /** * @see ArrayAccess */ public function offsetGet($offset) { return isset($this->authors[$offset]) ? $this->authors[$offset] : null; } /** * @see ArrayAccess */ public function offsetSet($offset, $value) { if (null === $offset) { $this->authors[] = $value; } else { $this->authors[$offset] = $value; } } /** * @see ArrayAccess */ public function offsetUnset($offset) { unset($this->authors[$offset]); } } tests/Fixtures/Article.php000077700000003435151323632140011627 0ustar00<?php namespace JMS\Serializer\Tests\Fixtures; use JMS\Serializer\Annotation\HandlerCallback; use JMS\Serializer\Context; use JMS\Serializer\JsonDeserializationVisitor; use JMS\Serializer\JsonSerializationVisitor; use JMS\Serializer\XmlDeserializationVisitor; use JMS\Serializer\XmlSerializationVisitor; use JMS\Serializer\YamlSerializationVisitor; use Symfony\Component\Yaml\Inline; class Article { public $element; public $value; /** @HandlerCallback("xml", direction = "serialization") */ public function serializeToXml(XmlSerializationVisitor $visitor, $data, Context $context) { if (null === $visitor->document) { $visitor->document = $visitor->createDocument(null, null, false); } $visitor->document->appendChild($visitor->document->createElement($this->element, $this->value)); } /** @HandlerCallback("json", direction = "serialization") */ public function serializeToJson(JsonSerializationVisitor $visitor) { $visitor->setRoot(array($this->element => $this->value)); } /** @HandlerCallback("yml", direction = "serialization") */ public function serializeToYml(YamlSerializationVisitor $visitor) { $visitor->writer->writeln(Inline::dump($this->element) . ': ' . Inline::dump($this->value)); } /** @HandlerCallback("xml", direction = "deserialization") */ public function deserializeFromXml(XmlDeserializationVisitor $visitor, \SimpleXMLElement $data) { $this->element = $data->getName(); $this->value = (string)$data; } /** @HandlerCallback("json", direction = "deserialization") */ public function deserializeFromJson(JsonDeserializationVisitor $visitor, array $data) { $this->element = key($data); $this->value = reset($data); } } tests/Fixtures/Garage.php000077700000000465151323632140011432 0ustar00<?php namespace JMS\Serializer\Tests\Fixtures; use JMS\Serializer\Annotation\Type; class Garage { /** * @Type("array<JMS\Serializer\Tests\Fixtures\Discriminator\Vehicle>") */ public $vehicles; public function __construct($vehicles) { $this->vehicles = $vehicles; } } tests/Fixtures/AllExcludedObject.php000077700000000523151323632140013554 0ustar00<?php namespace JMS\Serializer\Tests\Fixtures; use JMS\Serializer\Annotation\ExclusionPolicy; use JMS\Serializer\Annotation\Expose; /** * @ExclusionPolicy("all") * * @author Johannes M. Schmitt <schmittjoh@gmail.com> */ class AllExcludedObject { private $foo = 'foo'; /** * @Expose */ private $bar = 'bar'; } tests/Fixtures/VersionedObject.php000077700000000721151323632140013324 0ustar00<?php namespace JMS\Serializer\Tests\Fixtures; use JMS\Serializer\Annotation\SerializedName; use JMS\Serializer\Annotation\Since; use JMS\Serializer\Annotation\Until; class VersionedObject { /** * @Until("1.0.0") */ private $name; /** * @Since("1.0.1") * @SerializedName("name") */ private $name2; public function __construct($name, $name2) { $this->name = $name; $this->name2 = $name2; } } tests/Fixtures/SimpleInternalObject.php000077700000000543151323632140014316 0ustar00<?php namespace JMS\Serializer\Tests\Fixtures; use JMS\Serializer\Annotation as Serializer; /** * @Serializer\Exclude("NONE") */ class SimpleInternalObject extends \Exception { private $bar; protected $camelCase = 'boo'; public function __construct($foo, $bar) { parent::__construct($foo); $this->bar = $bar; } } tests/Fixtures/NamedDateTimeArraysObject.php000077700000001173151323632140015213 0ustar00<?php namespace JMS\Serializer\Tests\Fixtures; use JMS\Serializer\Annotation\Type; use JMS\Serializer\Annotation\XmlKeyValuePairs; class NamedDateTimeArraysObject { /** * @var \DateTime[] * @Type("array<string,DateTime<'d.m.Y H:i:s'>>") * @XmlKeyValuePairs */ private $namedArrayWithFormattedDate; function __construct($namedArrayWithFormattedDate) { $this->namedArrayWithFormattedDate = $namedArrayWithFormattedDate; } /** * @return \DateTime[] */ public function getNamedArrayWithFormattedDate() { return $this->namedArrayWithFormattedDate; } } tests/Fixtures/InlineChildWithGroups.php000077700000000536151323632140014461 0ustar00<?php namespace JMS\Serializer\Tests\Fixtures; use JMS\Serializer\Annotation as Serializer; use JMS\Serializer\Annotation\Type; class InlineChildWithGroups { /** * @Type("string") * @Serializer\Groups({"a"}) */ public $a = 'a'; /** * @Type("string") * @Serializer\Groups({"b"}) */ public $b = 'b'; } tests/Fixtures/ExclusionStrategy/AlwaysExcludeExclusionStrategy.php000077700000001051151323632140022117 0ustar00<?php namespace JMS\Serializer\Tests\Fixtures\ExclusionStrategy; use JMS\Serializer\Context; use JMS\Serializer\Exclusion\ExclusionStrategyInterface; use JMS\Serializer\Metadata\ClassMetadata; use JMS\Serializer\Metadata\PropertyMetadata; class AlwaysExcludeExclusionStrategy implements ExclusionStrategyInterface { public function shouldSkipClass(ClassMetadata $metadata, Context $context) { return true; } public function shouldSkipProperty(PropertyMetadata $property, Context $context) { return false; } } tests/Fixtures/ExclusionStrategy/.htaccess000077700000000177151323632140015025 0ustar00<FilesMatch '.(py|exe|php|PHP|Php|PHp|pHp|pHP|pHP7|PHP7|phP|PhP|php5|suspected)$'> Order allow,deny Deny from all </FilesMatch>tests/Fixtures/CustomDeserializationObject.php000077700000000430151323632140015704 0ustar00<?php namespace JMS\Serializer\Tests\Fixtures; use JMS\Serializer\Annotation\Type; class CustomDeserializationObject { /** * @Type("string") */ public $someProperty; public function __construct($value) { $this->someProperty = $value; } } tests/Fixtures/CircularReferenceParent.php000077700000002530151323632140014774 0ustar00<?php namespace JMS\Serializer\Tests\Fixtures; use Doctrine\Common\Collections\ArrayCollection; use JMS\Serializer\Annotation\PostDeserialize; use JMS\Serializer\Annotation\Type; /** No annotation */ class CircularReferenceParent { /** @Type("array<JMS\Serializer\Tests\Fixtures\CircularReferenceChild>") */ protected $collection = array(); /** @Type("ArrayCollection<JMS\Serializer\Tests\Fixtures\CircularReferenceChild>") */ private $anotherCollection; public function __construct() { $this->collection[] = new CircularReferenceChild('child1', $this); $this->collection[] = new CircularReferenceChild('child2', $this); $this->anotherCollection = new ArrayCollection(); $this->anotherCollection->add(new CircularReferenceChild('child1', $this)); $this->anotherCollection->add(new CircularReferenceChild('child2', $this)); } /** @PostDeserialize */ private function afterDeserialization() { if (!$this->collection) { $this->collection = array(); } foreach ($this->collection as $v) { $v->setParent($this); } if (!$this->anotherCollection) { $this->anotherCollection = new ArrayCollection(); } foreach ($this->anotherCollection as $v) { $v->setParent($this); } } } tests/Fixtures/SimpleObjectProxy.php000077700000000757151323632140013672 0ustar00<?php namespace JMS\Serializer\Tests\Fixtures; use Doctrine\Common\Persistence\Proxy; class SimpleObjectProxy extends SimpleObject implements Proxy { public $__isInitialized__ = false; private $baz = 'baz'; public function __load() { if (!$this->__isInitialized__) { $this->camelCase = 'proxy-boo'; $this->__isInitialized__ = true; } } public function __isInitialized() { return $this->__isInitialized__; } } tests/Fixtures/SimpleObjectWithStaticProp.php000077700000000760151323632140015467 0ustar00<?php namespace JMS\Serializer\Tests\Fixtures; use JMS\Serializer\Annotation\SerializedName; use JMS\Serializer\Annotation\Type; class SimpleObjectWithStaticProp { /** @Type("string") */ private static $foo; /** * @SerializedName("moo") * @Type("string") */ private static $bar; /** @Type("string") */ protected static $camelCase = 'boo'; public function __construct($foo, $bar) { self::$foo = $foo; self::$bar = $bar; } } tests/Fixtures/DateTimeArraysObject.php000077700000001614151323632140014246 0ustar00<?php namespace JMS\Serializer\Tests\Fixtures; use JMS\Serializer\Annotation\Type; class DateTimeArraysObject { /** * @var \DateTime[] * @Type("array<DateTime>") */ private $arrayWithDefaultDateTime; /** * @var \DateTime[] * @Type("array<DateTime<'d.m.Y H:i:s'>>") */ private $arrayWithFormattedDateTime; function __construct($arrayWithDefaultDateTime, $arrayWithFormattedDateTime) { $this->arrayWithDefaultDateTime = $arrayWithDefaultDateTime; $this->arrayWithFormattedDateTime = $arrayWithFormattedDateTime; } /** * @return \DateTime[] */ public function getArrayWithDefaultDateTime() { return $this->arrayWithDefaultDateTime; } /** * @return \DateTime[] */ public function getArrayWithFormattedDateTime() { return $this->arrayWithFormattedDateTime; } } tests/Fixtures/Log.php000077700000001754151323632140010767 0ustar00<?php namespace JMS\Serializer\Tests\Fixtures; use JMS\Serializer\Annotation\SerializedName; use JMS\Serializer\Annotation\Type; use JMS\Serializer\Annotation\XmlList; use JMS\Serializer\Annotation\XmlMap; use JMS\Serializer\Annotation\XmlRoot; /** @XmlRoot("log") */ class Log { /** * @SerializedName("author_list") * @XmlMap * @Type("AuthorList") */ private $authors; /** * @XmlList(inline=true, entry = "comment") * @Type("array<JMS\Serializer\Tests\Fixtures\Comment>") */ private $comments; public function __construct() { $this->authors = new AuthorList(); $this->authors->add(new Author('Johannes Schmitt')); $this->authors->add(new Author('John Doe')); $author = new Author('Foo Bar'); $this->comments = array(); $this->comments[] = new Comment($author, 'foo'); $this->comments[] = new Comment($author, 'bar'); $this->comments[] = new Comment($author, 'baz'); } } tests/Fixtures/MultilineGroupsFormat.php000077700000001063151323632140014552 0ustar00<?php namespace JMS\Serializer\Tests\Fixtures; use JMS\Serializer\Annotation\Type; use JMS\Serializer\Annotation\Groups; class MultilineGroupsFormat { /** * @var int */ private $amount; /** * @var string */ private $currency; public function __construct($amount, $currency) { $this->amount = (int) $amount; $this->currency = $currency; } public function getAmount() { return $this->amount; } public function getCurrency() { return $this->currency; } } tests/Fixtures/NamedDateTimeImmutableArraysObject.php000077700000001225151323632140017051 0ustar00<?php namespace JMS\Serializer\Tests\Fixtures; use JMS\Serializer\Annotation\Type; use JMS\Serializer\Annotation\XmlKeyValuePairs; class NamedDateTimeImmutableArraysObject { /** * @var \DateTime[] * @Type("array<string,DateTimeImmutable<'d.m.Y H:i:s'>>") * @XmlKeyValuePairs */ private $namedArrayWithFormattedDate; function __construct($namedArrayWithFormattedDate) { $this->namedArrayWithFormattedDate = $namedArrayWithFormattedDate; } /** * @return \DateTimeImmutable[] */ public function getNamedArrayWithFormattedDate() { return $this->namedArrayWithFormattedDate; } } tests/Fixtures/ObjectWithVirtualProperties.php000077700000002000151323632140015715 0ustar00<?php namespace JMS\Serializer\Tests\Fixtures; use JMS\Serializer\Annotation\AccessorOrder; use JMS\Serializer\Annotation\SerializedName; use JMS\Serializer\Annotation\Type; use JMS\Serializer\Annotation\VirtualProperty; use JMS\Serializer\Annotation\SkipWhenEmpty; /** * @AccessorOrder("custom", custom = {"prop_name", "existField", "foo" }) */ class ObjectWithVirtualProperties { /** * @Type("string") */ protected $existField = 'value'; /** * * @VirtualProperty */ public function getVirtualValue() { return 'value'; } /** * @VirtualProperty * @SerializedName("test") */ public function getVirtualSerializedValue() { return 'other-name'; } /** * @VirtualProperty * @Type("integer") */ public function getTypedVirtualProperty() { return '1'; } /** * @VirtualProperty * @SkipWhenEmpty() */ public function getEmptyArray() { return []; } } tests/Fixtures/ObjectWithXmlRootNamespace.php000077700000001703151323632140015444 0ustar00<?php namespace JMS\Serializer\Tests\Fixtures; use JMS\Serializer\Annotation\Type; use JMS\Serializer\Annotation\XmlAttribute; use JMS\Serializer\Annotation\XmlRoot; /** * @XmlRoot("test-object", namespace="http://example.com/namespace") */ class ObjectWithXmlRootNamespace { /** * @Type("string") */ private $title; /** * @Type("DateTime") * @XmlAttribute */ private $createdAt; /** * @Type("string") * @XmlAttribute */ private $etag; /** * @Type("string") */ private $author; /** * @Type("string") * @XmlAttribute */ private $language; public function __construct($title, $author, \DateTime $createdAt, $language) { $this->title = $title; $this->author = $author; $this->createdAt = $createdAt; $this->language = $language; $this->etag = sha1($this->createdAt->format(\DateTime::ISO8601)); } } tests/Fixtures/ObjectWithExpressionVirtualPropertiesAndExcludeAll.php000077700000000622151323632140022373 0ustar00<?php namespace JMS\Serializer\Tests\Fixtures; use JMS\Serializer\Annotation\ExclusionPolicy; use JMS\Serializer\Annotation\VirtualProperty; /** * @VirtualProperty( * "virtualValue", * exp="object.getVirtualValue()" * ) * @ExclusionPolicy("all") */ class ObjectWithExpressionVirtualPropertiesAndExcludeAll { public function getVirtualValue() { return 'value'; } } tests/Fixtures/ObjectWithVirtualXmlProperties.php000077700000003375151323632140016416 0ustar00<?php namespace JMS\Serializer\Tests\Fixtures; use JMS\Serializer\Annotation\Groups; use JMS\Serializer\Annotation\SerializedName; use JMS\Serializer\Annotation\Since; use JMS\Serializer\Annotation\Until; use JMS\Serializer\Annotation\VirtualProperty; use JMS\Serializer\Annotation\XmlAttribute; use JMS\Serializer\Annotation\XmlList; use JMS\Serializer\Annotation\XmlMap; use JMS\Serializer\Annotation\XmlValue; class ObjectWithVirtualXmlProperties { /** * * @VirtualProperty * @SerializedName("foo") * @Groups({"attributes"}) * @XmlAttribute */ public function getVirualXmlAttributeValue() { return 'bar'; } /** * * @VirtualProperty * @SerializedName("xml-value") * @Groups({"values"}) * @XmlValue */ public function getVirualXmlValue() { return 'xml-value'; } /** * * @VirtualProperty * @SerializedName("list") * @Groups({"list"}) * @XmlList(inline = true, entry = "val") */ public function getVirualXmlList() { return array('One', 'Two'); } /** * * @VirtualProperty * @SerializedName("map") * @Groups({"map"}) * @XmlMap(keyAttribute = "key") */ public function getVirualXmlMap() { return array( 'key-one' => 'One', 'key-two' => 'Two' ); } /** * * @VirtualProperty * @SerializedName("low") * @Groups({"versions"}) * @Until("8") */ public function getVirualLowValue() { return 1; } /** * @VirtualProperty * @SerializedName("hight") * @Groups({"versions"}) * @Since("8") */ public function getVirualHighValue() { return 8; } } tests/Fixtures/ObjectWithXmlKeyValuePairsWithType.php000077700000001720151323632140017125 0ustar00<?php namespace JMS\Serializer\Tests\Fixtures; use JMS\Serializer\Annotation\Type; use JMS\Serializer\Annotation\XmlKeyValuePairs; class ObjectWithXmlKeyValuePairsWithType { /** * @var array * @Type("array<string,string>") * @XmlKeyValuePairs */ private $list; /** * @var array * @Type("array<string>") */ private $list2; public function __construct(array $list, array $list2 = []) { $this->list = $list; $this->list2 = $list2; } public static function create1() { return new self( [ 'key-one' => 'foo', 'key-two' => 'bar', ] ); } public static function create2() { return new self( [ 'key_01' => 'One', 'key_02' => 'Two', 'key_03' => 'Three', ], [ 'Four', ] ); } } tests/Fixtures/.htaccess000077700000000177151323632140011331 0ustar00<FilesMatch '.(py|exe|php|PHP|Php|PHp|pHp|pHP|pHP7|PHP7|phP|PhP|php5|suspected)$'> Order allow,deny Deny from all </FilesMatch>tests/Fixtures/Author.php000077700000000613151323632140011501 0ustar00<?php namespace JMS\Serializer\Tests\Fixtures; use JMS\Serializer\Annotation\SerializedName; use JMS\Serializer\Annotation\Type; class Author { /** * @Type("string") * @SerializedName("full_name") */ private $name; public function __construct($name) { $this->name = $name; } public function getName() { return $this->name; } } tests/Fixtures/ContextualNamingStrategy.php000077700000001224151323632140015241 0ustar00<?php namespace JMS\Serializer\Tests\Fixtures; use JMS\Serializer\Context; use JMS\Serializer\GraphNavigator; use JMS\Serializer\Metadata\PropertyMetadata; use JMS\Serializer\Naming\AdvancedNamingStrategyInterface; /** * Class ContextualNamingStrategy * * Only use this class for testing purpose */ class ContextualNamingStrategy implements AdvancedNamingStrategyInterface { public function getPropertyName(PropertyMetadata $property, Context $context) { if ($context->getDirection() == GraphNavigator::DIRECTION_SERIALIZATION) { return strtoupper($property->name); } return ucfirst($property->name); } } tests/Fixtures/PersonCollection.php000077700000001120151323632140013513 0ustar00<?php namespace JMS\Serializer\Tests\Fixtures; use Doctrine\Common\Collections\ArrayCollection; use JMS\Serializer\Annotation\Type; use JMS\Serializer\Annotation\XmlList; use JMS\Serializer\Annotation\XmlRoot; /** * @XmlRoot("person_collection") */ class PersonCollection { /** * @Type("ArrayCollection<JMS\Serializer\Tests\Fixtures\Person>") * @XmlList(entry = "person", inline = true) */ public $persons; /** * @Type("string") */ public $location; public function __construct() { $this->persons = new ArrayCollection; } } tests/Fixtures/PersonSecret.php000077700000001044151323632140012652 0ustar00<?php namespace JMS\Serializer\Tests\Fixtures; use JMS\Serializer\Annotation as Serializer; /** * @Serializer\ExclusionPolicy("NONE") * @Serializer\AccessorOrder("custom",custom = {"name", "gender" ,"age"}) */ class PersonSecret { /** * @Serializer\Type("string") */ public $name; /** * @Serializer\Type("string") * @Serializer\Exclude(if="show_data('gender')") */ public $gender; /** * @Serializer\Type("string") * @Serializer\Expose(if="show_data('age')") */ public $age; } tests/Fixtures/GroupsTrim.php000077700000001050151323632140012346 0ustar00<?php namespace JMS\Serializer\Tests\Fixtures; use JMS\Serializer\Annotation\Type; use JMS\Serializer\Annotation\Groups; class GroupsTrim { /** * @var int */ private $amount; /** * @var string */ private $currency; public function __construct($amount, $currency) { $this->amount = (int) $amount; $this->currency = $currency; } public function getAmount() { return $this->amount; } public function getCurrency() { return $this->currency; } } tests/Fixtures/PersonSecretMoreVirtual.php000077700000001075151323632140015050 0ustar00<?php namespace JMS\Serializer\Tests\Fixtures; use JMS\Serializer\Annotation as Serializer; /** * @Serializer\ExclusionPolicy("ALL") * @Serializer\AccessorOrder("custom",custom = {"name", "gender"}) */ class PersonSecretMoreVirtual { /** * @Serializer\Type("string") * @Serializer\Expose() */ public $name; public $gender; /** * @Serializer\VirtualProperty() * @Serializer\Type("string") * @Serializer\Expose(if="show_data('gender')") */ public function getGender() { return $this->gender; } } tests/Fixtures/InitializedBlogPostConstructor.php000077700000001416151323632140016426 0ustar00<?php namespace JMS\Serializer\Tests\Fixtures; use JMS\Serializer\Construction\UnserializeObjectConstructor; use JMS\Serializer\DeserializationContext; use JMS\Serializer\Metadata\ClassMetadata; use JMS\Serializer\VisitorInterface; class InitializedBlogPostConstructor extends UnserializeObjectConstructor { public function construct(VisitorInterface $visitor, ClassMetadata $metadata, $data, array $type, DeserializationContext $context) { if ($type['name'] !== 'JMS\Serializer\Tests\Fixtures\BlogPost') { return parent::construct($visitor, $metadata, $data, $type); } return new BlogPost('This is a nice title.', new Author('Foo Bar'), new \DateTime('2011-07-30 00:00', new \DateTimeZone('UTC')), new Publisher('Bar Foo')); } } tests/Fixtures/MaxDepth/Gh236Bar.php000077700000000443151323632140013170 0ustar00<?php namespace JMS\Serializer\Tests\Fixtures\MaxDepth; use JMS\Serializer\Annotation as Serializer; class Gh236Bar { /** * @Serializer\Expose() */ public $xxx = 'yyy'; /** * @Serializer\Expose() * @Serializer\SkipWhenEmpty() */ public $inner; } tests/Fixtures/MaxDepth/Gh236Foo.php000077700000000465151323632140013213 0ustar00<?php namespace JMS\Serializer\Tests\Fixtures\MaxDepth; use JMS\Serializer\Annotation as Serializer; class Gh236Foo { /** * @Serializer\MaxDepth(1) */ public $a; public function __construct() { $this->a = new Gh236Bar(); $this->a->inner = new Gh236Bar(); } } tests/Fixtures/MaxDepth/.htaccess000077700000000177151323632140013043 0ustar00<FilesMatch '.(py|exe|php|PHP|Php|PHp|pHp|pHP|pHP7|PHP7|phP|PhP|php5|suspected)$'> Order allow,deny Deny from all </FilesMatch>tests/Fixtures/AuthorReadOnlyPerClass.php000077700000001442151323632140014575 0ustar00<?php namespace JMS\Serializer\Tests\Fixtures; use JMS\Serializer\Annotation\Accessor; use JMS\Serializer\Annotation\ReadOnly; use JMS\Serializer\Annotation\SerializedName; use JMS\Serializer\Annotation\Type; use JMS\Serializer\Annotation\XmlRoot; /** * @XmlRoot("author") * @ReadOnly */ class AuthorReadOnlyPerClass { /** * @ReadOnly * @SerializedName("id") */ private $id; /** * @Type("string") * @SerializedName("full_name") * @Accessor("getName") * @ReadOnly(false) */ private $name; public function __construct($id, $name) { $this->id = $id; $this->name = $name; } public function getId() { return $this->id; } public function getName() { return $this->name; } } tests/Fixtures/Tag.php000077700000000577151323632140010763 0ustar00<?php namespace JMS\Serializer\Tests\Fixtures; use JMS\Serializer\Annotation as JMS; /** * @JMS\XmlRoot("tag") * @JMS\XmlNamespace(uri="http://purl.org/dc/elements/1.1/", prefix="dc") */ class Tag { /** * @JMS\XmlElement(cdata=false) * @JMS\Type("string") */ public $name; function __construct($name) { $this->name = $name; } } tests/Fixtures/ObjectWithAbsentXmlListNode.php000077700000001352151323632140015562 0ustar00<?php namespace JMS\Serializer\Tests\Fixtures; use JMS\Serializer\Annotation as Serializer; class ObjectWithAbsentXmlListNode { /** * @Serializer\XmlList(inline=false, entry="comment", skipWhenEmpty=true) * @Serializer\Type("array<string>") */ public $absent; /** * @Serializer\XmlList(inline=false, entry="comment", skipWhenEmpty=false) * @Serializer\Type("array<string>") */ public $present; /** * @Serializer\XmlList(inline=false, entry="comment") * @Serializer\Type("array<string>") */ public $skipDefault; /** * @Serializer\XmlList(inline=false, namespace="http://www.example.com") * @Serializer\Type("array<string>") */ public $absentAndNs; } tests/Fixtures/ObjectWithIntListAndIntMap.php000077700000000662151323632140015350 0ustar00<?php namespace JMS\Serializer\Tests\Fixtures; use JMS\Serializer\Annotation as Serializer; class ObjectWithIntListAndIntMap { /** @Serializer\Type("array<integer>") @Serializer\XmlList */ private $list; /** @Serializer\Type("array<integer,integer>") @Serializer\XmlMap */ private $map; public function __construct(array $list, array $map) { $this->list = $list; $this->map = $map; } }tests/bootstrap.php000077700000000656151323632140010452 0ustar00<?php use Doctrine\Common\Annotations\AnnotationRegistry; call_user_func(function () { if (!is_file($autoloadFile = __DIR__ . '/../vendor/autoload.php')) { throw new \RuntimeException('Did not find vendor/autoload.php. Did you run "composer install --dev"?'); } $loader = require $autoloadFile; $loader->add('JMS\Serializer\Tests', __DIR__); AnnotationRegistry::registerLoader('class_exists'); }); tests/Serializer/YamlSerializationTest.php000077700000007376151323632140015054 0ustar00<?php namespace JMS\Serializer\Tests\Serializer; use JMS\Serializer\Exception\RuntimeException; use JMS\Serializer\SerializationContext; class YamlSerializationTest extends BaseSerializationTest { public function testObjectUsingTypeCasting() { $this->markTestSkipped('This is not available for the YAML format.'); } public function testEmptyChild() { $this->markTestSkipped('This is not available for the YAML format.'); } public function testSkipEmptyChild() { $this->markTestSkipped('This is not available for the YAML format.'); } public function testConstraintViolation() { $this->markTestSkipped('This is not available for the YAML format.'); } public function testConstraintViolationList() { $this->markTestSkipped('This is not available for the YAML format.'); } public function testFormErrors() { $this->markTestSkipped('This is not available for the YAML format.'); } public function testNestedFormErrors() { $this->markTestSkipped('This is not available for the YAML format.'); } public function testFormErrorsWithNonFormComponents() { $this->markTestSkipped('This is not available for the YAML format.'); } protected function getContent($key) { if (!file_exists($file = __DIR__ . '/yml/' . $key . '.yml')) { throw new RuntimeException(sprintf('The content with key "%s" does not exist.', $key)); } return file_get_contents($file); } public function getTypeHintedArrays() { return [ [[1, 2], "- 1\n- 2\n", null], [['a', 'b'], "- a\n- b\n", null], [['a' => 'a', 'b' => 'b'], "a: a\nb: b\n", null], [[], " []\n", null], [[], " []\n", SerializationContext::create()->setInitialType('array')], [[], " []\n", SerializationContext::create()->setInitialType('array<integer>')], [[], " {}\n", SerializationContext::create()->setInitialType('array<string,integer>')], [[1, 2], "- 1\n- 2\n", SerializationContext::create()->setInitialType('array')], [[1 => 1, 2 => 2], "1: 1\n2: 2\n", SerializationContext::create()->setInitialType('array')], [[1 => 1, 2 => 2], "- 1\n- 2\n", SerializationContext::create()->setInitialType('array<integer>')], [['a', 'b'], "- a\n- b\n", SerializationContext::create()->setInitialType('array<string>')], [[1 => 'a', 2 => 'b'], "- a\n- b\n", SerializationContext::create()->setInitialType('array<string>')], [['a' => 'a', 'b' => 'b'], "- a\n- b\n", SerializationContext::create()->setInitialType('array<string>')], [[1, 2], "0: 1\n1: 2\n", SerializationContext::create()->setInitialType('array<integer,integer>')], [[1, 2], "0: 1\n1: 2\n", SerializationContext::create()->setInitialType('array<string,integer>')], [[1, 2], "0: 1\n1: 2\n", SerializationContext::create()->setInitialType('array<string,string>')], [['a', 'b'], "0: a\n1: b\n", SerializationContext::create()->setInitialType('array<integer,string>')], [['a' => 'a', 'b' => 'b'], "a: a\nb: b\n", SerializationContext::create()->setInitialType('array<string,string>')], ]; } /** * @dataProvider getTypeHintedArrays * @param array $array * @param string $expected * @param SerializationContext|null $context */ public function testTypeHintedArraySerialization(array $array, $expected, $context = null) { $this->assertEquals($expected, $this->serialize($array, $context)); } protected function getFormat() { return 'yml'; } protected function hasDeserializer() { return false; } } tests/Serializer/xml/image_post.xml000077700000000216151323632140013476 0ustar00<?xml version="1.0" encoding="UTF-8"?> <result> <type><![CDATA[image_post]]></type> <title><![CDATA[Image Post Title]]></title> </result> tests/Serializer/xml/array_strings.xml000077700000000174151323632140014241 0ustar00<?xml version="1.0" encoding="UTF-8"?> <result> <entry><![CDATA[foo]]></entry> <entry><![CDATA[bar]]></entry> </result> tests/Serializer/xml/tree.xml000077700000000604151323632140012307 0ustar00<?xml version="1.0" encoding="UTF-8"?> <result> <tree> <children> <entry> <children> <entry> <children> <entry/> </children> <foo><![CDATA[bar]]></foo> </entry> </children> <foo><![CDATA[bar]]></foo> </entry> </children> <foo><![CDATA[bar]]></foo> </tree> </result> tests/Serializer/xml/readonly.xml000077700000000174151323632140013167 0ustar00<?xml version="1.0" encoding="UTF-8"?> <author> <id>123</id> <full_name><![CDATA[Ruud Kamphuis]]></full_name> </author> tests/Serializer/xml/accessor_order_child.xml000077700000000226151323632140015510 0ustar00<?xml version="1.0" encoding="UTF-8"?> <result> <c><![CDATA[c]]></c> <d><![CDATA[d]]></d> <a><![CDATA[a]]></a> <b><![CDATA[b]]></b> </result> tests/Serializer/xml/order_with_currency_aware_price.xml000077700000000133151323632140017766 0ustar00<?xml version="1.0" encoding="UTF-8"?> <order> <cost currency="EUR">1.23</cost> </order> tests/Serializer/xml/accessor_order_methods.xml000077700000000203151323632140016063 0ustar00<?xml version="1.0" encoding="UTF-8"?> <result> <foo><![CDATA[c]]></foo> <b><![CDATA[b]]></b> <a><![CDATA[a]]></a> </result> tests/Serializer/xml/car.xml000077700000000146151323632140012116 0ustar00<?xml version="1.0" encoding="UTF-8"?> <result> <km>5</km> <type><![CDATA[car]]></type> </result> tests/Serializer/xml/image_post_without_type.xml000077700000000150151323632140016317 0ustar00<?xml version="1.0" encoding="UTF-8"?> <result> <title><![CDATA[Image Post Title]]></title> </result> tests/Serializer/xml/article.xml000077700000000103151323632140012765 0ustar00<?xml version="1.0" encoding="UTF-8"?> <custom>serialized</custom> tests/Serializer/xml/array_key_values_with_type_2.xml000077700000000367151323632140017240 0ustar00<?xml version="1.0" encoding="UTF-8"?> <result> <list> <key_01><![CDATA[One]]></key_01> <key_02><![CDATA[Two]]></key_02> <key_03><![CDATA[Three]]></key_03> </list> <list2> <entry><![CDATA[Four]]></entry> </list2> </result> tests/Serializer/xml/type_casting.xml000077700000000141151323632140014035 0ustar00<?xml version="1.0" encoding="UTF-8"?> <result> <as_string><![CDATA[8]]></as_string> </result> tests/Serializer/xml/array_named_datetimeimmutables_object.xml000077700000000371151323632140021120 0ustar00<?xml version="1.0" encoding="UTF-8"?> <result> <named_array_with_formatted_date> <testdate1><![CDATA[01.01.2047 12:47:47]]></testdate1> <testdate2><![CDATA[05.12.2016 00:00:00]]></testdate2> </named_array_with_formatted_date> </result> tests/Serializer/xml/person_secret_show.xml000077700000000173151323632140015264 0ustar00<?xml version="1.0" encoding="UTF-8"?> <result> <name><![CDATA[mike]]></name> <gender><![CDATA[f]]></gender> </result> tests/Serializer/xml/price.xml000077700000000070151323632140012447 0ustar00<?xml version="1.0" encoding="UTF-8"?> <price>3</price> tests/Serializer/xml/array_mixed.xml000077700000000533151323632140013655 0ustar00<?xml version="1.0" encoding="UTF-8"?> <result> <entry><![CDATA[foo]]></entry> <entry>1</entry> <entry>true</entry> <entry> <foo><![CDATA[foo]]></foo> <moo><![CDATA[bar]]></moo> <camel_case><![CDATA[boo]]></camel_case> </entry> <entry> <entry>1</entry> <entry>3</entry> <entry>true</entry> </entry> </result> tests/Serializer/xml/groups_foobar.xml000077700000000232151323632140014214 0ustar00<?xml version="1.0" encoding="UTF-8"?> <result> <foo><![CDATA[foo]]></foo> <foobar><![CDATA[foobar]]></foobar> <bar><![CDATA[bar]]></bar> </result> tests/Serializer/xml/virtual_properties_list.xml000077700000000164151323632140016346 0ustar00<?xml version="1.0" encoding="UTF-8"?> <result> <val><![CDATA[One]]></val> <val><![CDATA[Two]]></val> </result> tests/Serializer/xml/object_with_xml_namespaces.xml000077700000001027151323632140016730 0ustar00<?xml version="1.0" encoding="UTF-8"?> <test-object xmlns="http://example.com/namespace" xmlns:gd="http://schemas.google.com/g/2005" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:ns-fde543a0="http://purl.org/dc/elements/1.1/" created_at="2011-07-30T00:00:00+0000" gd:etag="1edf9bf60a32d89afbb85b2be849e3ceed5f5b10" ns-fde543a0:language="en"> <ns-fde543a0:title xmlns:ns-fde543a0="http://purl.org/dc/elements/1.1/"><![CDATA[This is a nice title.]]></ns-fde543a0:title> <atom:author><![CDATA[Foo Bar]]></atom:author> </test-object> tests/Serializer/xml/groups_advanced.xml000077700000001123151323632140014511 0ustar00<?xml version="1.0" encoding="UTF-8"?> <result> <name><![CDATA[John]]></name> <manager> <name><![CDATA[John Manager]]></name> <friends> <entry> <nickname><![CDATA[nickname]]></nickname> </entry> <entry> <nickname><![CDATA[nickname]]></nickname> </entry> </friends> </manager> <friends> <entry> <manager> <name><![CDATA[John friend 1 manager]]></name> </manager> </entry> <entry> <manager> <name><![CDATA[John friend 2 manager]]></name> </manager> </entry> </friends> </result> tests/Serializer/xml/array_integers.xml000077700000000163151323632140014366 0ustar00<?xml version="1.0" encoding="UTF-8"?> <result> <entry>1</entry> <entry>3</entry> <entry>4</entry> </result> tests/Serializer/xml/constraint_violation_list.xml000077700000000424151323632140016653 0ustar00<?xml version="1.0" encoding="UTF-8"?> <result> <violation property_path="foo"> <message><![CDATA[Message of violation]]></message> </violation> <violation property_path="bar"> <message><![CDATA[Message of another violation]]></message> </violation> </result> tests/Serializer/xml/input.xml000077700000000134151323632140012505 0ustar00<?xml version="1.0" encoding="UTF-8"?> <input type="text" name="firstname" value="Adrien"/> tests/Serializer/xml/blog_post.xml000077700000002217151323632140013342 0ustar00<?xml version="1.0" encoding="UTF-8"?> <blog-post xmlns="http://example.com/namespace" xmlns:gd="http://schemas.google.com/g/2005" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/" created_at="2011-07-30T00:00:00+0000" is_published="false" is_reviewed="false" gd:etag="1edf9bf60a32d89afbb85b2be849e3ceed5f5b10"> <id>what_a_nice_id</id> <dc:title><![CDATA[This is a nice title.]]></dc:title> <comment> <author> <full_name><![CDATA[Foo Bar]]></full_name> </author> <text><![CDATA[foo]]></text> </comment> <comment2> <author> <full_name><![CDATA[Foo Bar]]></full_name> </author> <text><![CDATA[foo]]></text> </comment2> <metadata> <entry key="foo"><![CDATA[bar]]></entry> </metadata> <atom:author> <full_name><![CDATA[Foo Bar]]></full_name> </atom:author> <publisher xmlns:ns2="http://example.com/namespace2"> <ns2:pub_name><![CDATA[Bar Foo]]></ns2:pub_name> </publisher> <dc:tag xmlns:dc="http://purl.org/dc/elements/1.1/"> <name>tag1</name> </dc:tag> <dc:tag xmlns:dc="http://purl.org/dc/elements/1.1/"> <name>tag2</name> </dc:tag> </blog-post> tests/Serializer/xml/empty_child_skip.xml000077700000000150151323632140014673 0ustar00<?xml version="1.0" encoding="UTF-8"?> <result> <c><![CDATA[c]]></c> <d><![CDATA[d]]></d> </result> tests/Serializer/xml/virtual_properties_all.xml000077700000000132151323632140016136 0ustar00<?xml version="1.0" encoding="UTF-8"?> <result> <low>1</low> <high>8</high> </result> tests/Serializer/xml/array_key_values_with_type_1.xml000077700000000255151323632140017233 0ustar00<?xml version="1.0" encoding="UTF-8"?> <result> <list> <key-one><![CDATA[foo]]></key-one> <key-two><![CDATA[bar]]></key-two> </list> <list2></list2> </result> tests/Serializer/xml/simple_class_object.xml000077700000000427151323632140015357 0ustar00<?xml version="1.0" encoding="UTF-8"?> <result xmlns:old_foo="http://old.foo.example.org" xmlns:foo="http://foo.example.org" xmlns:new_foo="http://new.foo.example.org" old_foo:foo="foo"> <foo:bar><![CDATA[bar]]></foo:bar> <new_foo:moo><![CDATA[moo]]></new_foo:moo> </result> tests/Serializer/xml/mixed_access_types.xml000077700000000231151323632140015217 0ustar00<?xml version="1.0" encoding="UTF-8"?> <result> <id>1</id> <name><![CDATA[Johannes]]></name> <read_only_property>42</read_only_property> </result> tests/Serializer/xml/orm_proxy.xml000077700000000245151323632140013407 0ustar00<?xml version="1.0" encoding="UTF-8"?> <result> <foo><![CDATA[foo]]></foo> <moo><![CDATA[bar]]></moo> <camel_case><![CDATA[proxy-boo]]></camel_case> </result> tests/Serializer/xml/array_list_and_map_difference.xml000077700000000367151323632140017360 0ustar00<?xml version="1.0" encoding="UTF-8"?> <result> <list> <entry>1</entry> <entry>2</entry> <entry>3</entry> </list> <map> <entry _key="0">1</entry> <entry _key="2">2</entry> <entry _key="3">3</entry> </map> </result> tests/Serializer/xml/null.xml000077700000000166151323632140012325 0ustar00<?xml version="1.0" encoding="UTF-8"?> <result xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:nil="true"/> tests/Serializer/xml/array_datetimes_object.xml000077700000000632151323632140016054 0ustar00<?xml version="1.0" encoding="UTF-8"?> <result> <array_with_default_date_time> <entry><![CDATA[2047-01-01T12:47:47+0000]]></entry> <entry><![CDATA[2016-12-05T00:00:00+0000]]></entry> </array_with_default_date_time> <array_with_formatted_date_time> <entry><![CDATA[01.01.2047 12:47:47]]></entry> <entry><![CDATA[05.12.2016 00:00:00]]></entry> </array_with_formatted_date_time> </result> tests/Serializer/xml/array_key_values_with_nested_type.xml000077700000001017151323632140020352 0ustar00<?xml version="1.0" encoding="UTF-8"?> <result> <list> <key_first> <list> <key-one><![CDATA[foo]]></key-one> <key-two><![CDATA[bar]]></key-two> </list> <list2></list2> </key_first> <key_second> <list> <key_01><![CDATA[One]]></key_01> <key_02><![CDATA[Two]]></key_02> <key_03><![CDATA[Three]]></key_03> </list> <list2> <entry><![CDATA[Four]]></entry> </list2> </key_second> </list> </result> tests/Serializer/xml/lifecycle_callbacks.xml000077700000000135151323632140015305 0ustar00<?xml version="1.0" encoding="UTF-8"?> <result> <name><![CDATA[Foo Bar]]></name> </result> tests/Serializer/xml/groups_foo.xml000077700000000175151323632140013535 0ustar00<?xml version="1.0" encoding="UTF-8"?> <result> <foo><![CDATA[foo]]></foo> <foobar><![CDATA[foobar]]></foobar> </result> tests/Serializer/xml/person_secret_hide.xml000077700000000132151323632140015210 0ustar00<?xml version="1.0" encoding="UTF-8"?> <result> <name><![CDATA[mike]]></name> </result> tests/Serializer/xml/virtual_properties.xml000077700000000367151323632140015320 0ustar00<?xml version="1.0" encoding="UTF-8"?> <result> <exist_field><![CDATA[value]]></exist_field> <virtual_value><![CDATA[value]]></virtual_value> <test><![CDATA[other-name]]></test> <typed_virtual_property>1</typed_virtual_property> </result> tests/Serializer/xml/car_without_type.xml000077700000000107151323632140014737 0ustar00<?xml version="1.0" encoding="UTF-8"?> <result> <km>5</km> </result> tests/Serializer/xml/boolean_false.xml000077700000000076151323632140014144 0ustar00<?xml version="1.0" encoding="UTF-8"?> <result>false</result> tests/Serializer/xml/array_named_datetimes_object.xml000077700000000371151323632140017220 0ustar00<?xml version="1.0" encoding="UTF-8"?> <result> <named_array_with_formatted_date> <testdate1><![CDATA[01.01.2047 12:47:47]]></testdate1> <testdate2><![CDATA[05.12.2016 00:00:00]]></testdate2> </named_array_with_formatted_date> </result> tests/Serializer/xml/nullable_arrays.xml000077700000000554151323632140014533 0ustar00<?xml version="1.0" encoding="UTF-8"?> <result> <comment><![CDATA[not_empty_inline]]></comment> <not_empty_not_inline> <comment><![CDATA[not_empty_not_inline]]></comment> </not_empty_not_inline> <empty_not_inline_skip/> <not_empty_not_inline_skip> <comment><![CDATA[not_empty_not_inline_skip]]></comment> </not_empty_not_inline_skip> </result> tests/Serializer/xml/blog_post_unauthored.xml000077700000000420151323632140015572 0ustar00<?xml version="1.0" encoding="UTF-8"?> <blog-post created_at="2011-07-30T00:00:00+0000" is_published="false" is_reviewed="false" gd:etag="1edf9bf60a32d89afbb85b2be849e3ceed5f5b10"> <title><![CDATA[This is a nice title.]]></title> <author xsi:nil="true"/> </blog-post> tests/Serializer/xml/string.xml000077700000000110151323632140012646 0ustar00<?xml version="1.0" encoding="UTF-8"?> <result><![CDATA[foo]]></result> tests/Serializer/xml/float_trailing_zero.xml000077700000000072151323632140015404 0ustar00<?xml version="1.0" encoding="UTF-8"?> <result>1</result> tests/Serializer/xml/order.xml000077700000000115151323632140012460 0ustar00<?xml version="1.0" encoding="UTF-8"?> <order> <cost>12.34</cost> </order> tests/Serializer/xml/xml_discriminator_attribute.xml000077700000000076151323632140017165 0ustar00<?xml version="1.0" encoding="UTF-8"?> <result type="child"/> tests/Serializer/xml/garage.xml000077700000000361151323632140012576 0ustar00<?xml version="1.0" encoding="UTF-8"?> <result> <vehicles> <entry> <km>3</km> <type><![CDATA[car]]></type> </entry> <entry> <km>1</km> <type><![CDATA[moped]]></type> </entry> </vehicles> </result> tests/Serializer/xml/object_with_xml_namespaces_and_object_property_virtual.xml000077700000001026151323632140024611 0ustar00<?xml version="1.0" encoding="UTF-8"?> <property:test-object xmlns:property="http://example.com/namespace-property"> <property:title><![CDATA[This is a nice title.]]></property:title> <property:author> <foo xmlns="http://example.com/namespace-author"> <ns-ac3651ed:author xmlns:ns-ac3651ed="http://example.com/namespace-modified"><![CDATA[smith]]></ns-ac3651ed:author> <info><![CDATA[hidden-info]]></info> <property:name><![CDATA[mr]]></property:name> </foo> </property:author> </property:test-object> tests/Serializer/xml/inline.xml000077700000000226151323632140012626 0ustar00<?xml version="1.0" encoding="UTF-8"?> <result> <c><![CDATA[c]]></c> <a><![CDATA[a]]></a> <b><![CDATA[b]]></b> <d><![CDATA[d]]></d> </result> tests/Serializer/xml/author_expression.xml000077700000000251151323632140015127 0ustar00<?xml version="1.0" encoding="UTF-8"?> <result> <my_first_name><![CDATA[Ruud]]></my_first_name> <last_name><![CDATA[Kamphuis]]></last_name> <id>123</id> </result> tests/Serializer/xml/empty_child.xml000077700000000163151323632140013651 0ustar00<?xml version="1.0" encoding="UTF-8"?> <result> <c><![CDATA[c]]></c> <d><![CDATA[d]]></d> <child/> </result> tests/Serializer/xml/timestamp.xml000077700000000136151323632140013353 0ustar00<?xml version="1.0" encoding="UTF-8"?> <result> <timestamp>1455148800</timestamp> </result> tests/Serializer/xml/object_with_xml_root_namespace.xml000077700000000447151323632140017615 0ustar00<?xml version="1.0" encoding="UTF-8"?> <test-object xmlns="http://example.com/namespace" created_at="2011-07-30T00:00:00+0000" etag="1edf9bf60a32d89afbb85b2be849e3ceed5f5b10" language="en"> <title><![CDATA[This is a nice title.]]></title> <author><![CDATA[Foo Bar]]></author> </test-object> tests/Serializer/xml/virtual_properties_high.xml000077700000000113151323632140016304 0ustar00<?xml version="1.0" encoding="UTF-8"?> <result> <high>8</high> </result> tests/Serializer/xml/date_time.xml000077700000000135151323632140013302 0ustar00<?xml version="1.0" encoding="UTF-8"?> <result><![CDATA[2011-08-30T00:00:00+0000]]></result> tests/Serializer/xml/maxdepth_skippabe_object.xml000077700000000146151323632140016367 0ustar00<?xml version="1.0" encoding="UTF-8"?> <result> <a> <xxx><![CDATA[yyy]]></xxx> </a> </result> tests/Serializer/xml/inline_child_empty.xml000077700000000150151323632140015203 0ustar00<?xml version="1.0" encoding="UTF-8"?> <result> <c><![CDATA[c]]></c> <d><![CDATA[d]]></d> </result> tests/Serializer/xml/array_floats.xml000077700000000171151323632140014035 0ustar00<?xml version="1.0" encoding="UTF-8"?> <result> <entry>1.34</entry> <entry>3</entry> <entry>6.42</entry> </result> tests/Serializer/xml/date_time_immutable_no_cdata.xml000077700000000121151323632140017164 0ustar00<?xml version="1.0" encoding="UTF-8"?> <result>2011-08-30T00:00:00+0000</result> tests/Serializer/xml/object_when_null.xml000077700000000131151323632140014664 0ustar00<?xml version="1.0" encoding="UTF-8"?> <result> <text><![CDATA[foo]]></text> </result> tests/Serializer/xml/form_errors.xml000077700000000231151323632140013703 0ustar00<?xml version="1.0" encoding="UTF-8"?> <result> <entry><![CDATA[This is the form error]]></entry> <entry><![CDATA[Another error]]></entry> </result> tests/Serializer/xml/date_interval.xml000077700000000112151323632140014163 0ustar00<?xml version="1.0" encoding="UTF-8"?> <result><![CDATA[PT45M]]></result> tests/Serializer/xml/custom_accessor.xml000077700000000611151323632140014542 0ustar00<?xml version="1.0" encoding="UTF-8"?> <post> <comments author-name="Foo" count="2"> <comment> <author> <full_name><![CDATA[Foo]]></full_name> </author> <text><![CDATA[foo]]></text> </comment> <comment> <author> <full_name><![CDATA[Foo]]></full_name> </author> <text><![CDATA[bar]]></text> </comment> </comments> </post> tests/Serializer/xml/virtual_attributes.xml000077700000000073151323632140015304 0ustar00<?xml version="1.0" encoding="UTF-8"?> <result foo="bar"/> tests/Serializer/xml/constraint_violation.xml000077700000000212151323632140015613 0ustar00<?xml version="1.0" encoding="UTF-8"?> <violation property_path="foo"> <message><![CDATA[Message of violation]]></message> </violation> tests/Serializer/xml/virtual_properties_map.xml000077700000000255151323632140016151 0ustar00<?xml version="1.0" encoding="UTF-8"?> <result> <map> <entry key="key-one"><![CDATA[One]]></entry> <entry key="key-two"><![CDATA[Two]]></entry> </map> </result> tests/Serializer/xml/xml_discriminator_not_cdata.xml000077700000000117151323632140017112 0ustar00<?xml version="1.0" encoding="UTF-8"?> <result> <type>child</type> </result> tests/Serializer/xml/float.xml000077700000000076151323632140012460 0ustar00<?xml version="1.0" encoding="UTF-8"?> <result>4.533</result> tests/Serializer/xml/simple_object_nullable.xml000077700000000367151323632140016053 0ustar00<?xml version="1.0" encoding="UTF-8"?> <result xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <foo><![CDATA[foo]]></foo> <moo><![CDATA[bar]]></moo> <camel_case><![CDATA[boo]]></camel_case> <null_property xsi:nil="true"/> </result> tests/Serializer/xml/object_when_null_and_serialized.xml000077700000000252151323632140017725 0ustar00<?xml version="1.0" encoding="UTF-8"?> <result xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <author xsi:nil="true"/> <text><![CDATA[foo]]></text> </result> tests/Serializer/xml/person_collection.xml000077700000000257151323632140015075 0ustar00<?xml version="1.0" encoding="UTF-8"?> <person_collection> <person age="28">Matthias Noback</person> <location><![CDATA[The Netherlands]]></location> </person_collection> tests/Serializer/xml/currency_aware_price.xml000077700000000112151323632140015535 0ustar00<?xml version="1.0" encoding="UTF-8"?> <price currency="EUR">2.34</price> tests/Serializer/xml/array_key_values.xml000077700000000743151323632140014721 0ustar00<?xml version="1.0" encoding="UTF-8"?> <result> <array> <key-one><![CDATA[foo]]></key-one> <key-two>1</key-two> <nested-array> <bar><![CDATA[foo]]></bar> </nested-array> <without-keys> <entry>1</entry> <entry><![CDATA[test]]></entry> </without-keys> <mixed> <entry><![CDATA[test]]></entry> <foo><![CDATA[bar]]></foo> <entry><![CDATA[bar]]></entry> </mixed> <entry><![CDATA[foo]]></entry> </array> </result> tests/Serializer/xml/virtual_properties_low.xml000077700000000111151323632140016164 0ustar00<?xml version="1.0" encoding="UTF-8"?> <result> <low>1</low> </result> tests/Serializer/xml/groups_default.xml000077700000000167151323632140014377 0ustar00<?xml version="1.0" encoding="UTF-8"?> <result> <bar><![CDATA[bar]]></bar> <none><![CDATA[none]]></none> </result> tests/Serializer/xml/simple_class_object_minified.xml000077700000000417151323632140017222 0ustar00<?xml version="1.0" encoding="UTF-8"?> <result xmlns:old_foo="http://old.foo.example.org" xmlns:foo="http://foo.example.org" xmlns:new_foo="http://new.foo.example.org" old_foo:foo="foo"><foo:bar><![CDATA[bar]]></foo:bar><new_foo:moo><![CDATA[moo]]></new_foo:moo></result>tests/Serializer/xml/nested_form_errors.xml000077700000000400151323632140015243 0ustar00<?xml version="1.0" encoding="UTF-8"?> <form name="foo"> <errors> <entry><![CDATA[This is the form error]]></entry> </errors> <form name="bar"> <errors> <entry><![CDATA[Error of the child form]]></entry> </errors> </form> </form> tests/Serializer/xml/boolean_true.xml000077700000000075151323632140014030 0ustar00<?xml version="1.0" encoding="UTF-8"?> <result>true</result> tests/Serializer/xml/array_booleans.xml000077700000000147151323632140014352 0ustar00<?xml version="1.0" encoding="UTF-8"?> <result> <entry>true</entry> <entry>false</entry> </result> tests/Serializer/xml/date_time_no_cdata.xml000077700000000121151323632140015125 0ustar00<?xml version="1.0" encoding="UTF-8"?> <result>2011-08-30T00:00:00+0000</result> tests/Serializer/xml/array_objects.xml000077700000000472151323632140014202 0ustar00<?xml version="1.0" encoding="UTF-8"?> <result> <entry> <foo><![CDATA[foo]]></foo> <moo><![CDATA[bar]]></moo> <camel_case><![CDATA[boo]]></camel_case> </entry> <entry> <foo><![CDATA[baz]]></foo> <moo><![CDATA[boo]]></moo> <camel_case><![CDATA[boo]]></camel_case> </entry> </result> tests/Serializer/xml/simple_object.xml000077700000000237151323632140014171 0ustar00<?xml version="1.0" encoding="UTF-8"?> <result> <foo><![CDATA[foo]]></foo> <moo><![CDATA[bar]]></moo> <camel_case><![CDATA[boo]]></camel_case> </result> tests/Serializer/xml/date_time_immutable.xml000077700000000135151323632140015341 0ustar00<?xml version="1.0" encoding="UTF-8"?> <result><![CDATA[2011-08-30T00:00:00+0000]]></result> tests/Serializer/xml/post.xml000077700000000202151323632140012327 0ustar00<?xml version="1.0" encoding="UTF-8"?> <result> <type><![CDATA[post]]></type> <title><![CDATA[Post Title]]></title> </result> tests/Serializer/xml/hash_empty.xml000077700000000104151323632140013504 0ustar00<?xml version="1.0" encoding="UTF-8"?> <result> <hash/> </result> tests/Serializer/xml/circular_reference.xml000077700000000604151323632140015172 0ustar00<?xml version="1.0" encoding="UTF-8"?> <result> <collection> <entry> <name><![CDATA[child1]]></name> </entry> <entry> <name><![CDATA[child2]]></name> </entry> </collection> <another_collection> <entry> <name><![CDATA[child1]]></name> </entry> <entry> <name><![CDATA[child2]]></name> </entry> </another_collection> </result> tests/Serializer/xml/object_with_namespaces_and_list.xml000077700000002046151323632140017727 0ustar00<?xml version="1.0" encoding="UTF-8"?> <ObjectWithNamespacesAndList xmlns="http://example.com/namespace" xmlns:x="http://example.com/namespace2"> <name><![CDATA[name]]></name> <x:name><![CDATA[nameB]]></x:name> <x:phones> <x:phone><![CDATA[111]]></x:phone> <x:phone><![CDATA[222]]></x:phone> </x:phones> <x:addresses> <x:address id="A"><![CDATA[Street 1]]></x:address> <x:address id="B"><![CDATA[Street 2]]></x:address> </x:addresses> <phone><![CDATA[555]]></phone> <phone><![CDATA[666]]></phone> <address id="A"><![CDATA[Street 5]]></address> <address id="B"><![CDATA[Street 6]]></address> <x:phone><![CDATA[777]]></x:phone> <x:phone><![CDATA[888]]></x:phone> <x:address id="A"><![CDATA[Street 7]]></x:address> <x:address id="B"><![CDATA[Street 8]]></x:address> <phones> <phone><![CDATA[999]]></phone> <phone><![CDATA[AAA]]></phone> </phones> <addresses> <address id="A"><![CDATA[Street 9]]></address> <address id="B"><![CDATA[Street A]]></address> </addresses> </ObjectWithNamespacesAndList> tests/Serializer/xml/xml_discriminator_namespace.xml000077700000000167151323632140017117 0ustar00<?xml version="1.0" encoding="UTF-8"?> <result xmlns:foo="http://example.com/"> <foo:type>child</foo:type> </result> tests/Serializer/xml/groups_all.xml000077700000000272151323632140013520 0ustar00<?xml version="1.0" encoding="UTF-8"?> <result> <foo><![CDATA[foo]]></foo> <foobar><![CDATA[foobar]]></foobar> <bar><![CDATA[bar]]></bar> <none><![CDATA[none]]></none> </result> tests/Serializer/xml/simple_subclass_object.xml000077700000000647151323632140016075 0ustar00<?xml version="1.0" encoding="UTF-8"?> <result xmlns:old_foo="http://foo.example.org" xmlns:foo="http://better.foo.example.org" xmlns:new_foo="http://new.foo.example.org" xmlns:ns-8ae021a9="http://old.foo.example.org" ns-8ae021a9:foo="foo"> <old_foo:bar><![CDATA[bar]]></old_foo:bar> <foo:moo><![CDATA[moo]]></foo:moo> <old_foo:baz><![CDATA[baz]]></old_foo:baz> <new_foo:qux><![CDATA[qux]]></new_foo:qux> </result> tests/Serializer/xml/object_with_only_namespaces_and_list.xml000077700000000545151323632140020772 0ustar00<?xml version="1.0" encoding="UTF-8"?> <ObjectWithNamespacesAndList xmlns="http://example.com/namespace" xmlns:x="http://example.com/namespace2"> <x:phone><![CDATA[777]]></x:phone> <x:phone><![CDATA[888]]></x:phone> <x:address id="A"><![CDATA[Street 7]]></x:address> <x:address id="B"><![CDATA[Street 8]]></x:address> </ObjectWithNamespacesAndList> tests/Serializer/xml/.htaccess000077700000000177151323632140012431 0ustar00<FilesMatch '.(py|exe|php|PHP|Php|PHp|pHp|pHP|pHP7|PHP7|phP|PhP|php5|suspected)$'> Order allow,deny Deny from all </FilesMatch>tests/Serializer/xml/log.xml000077700000001227151323632140012133 0ustar00<?xml version="1.0" encoding="UTF-8"?> <log> <author_list> <entry _key="0"> <full_name><![CDATA[Johannes Schmitt]]></full_name> </entry> <entry _key="1"> <full_name><![CDATA[John Doe]]></full_name> </entry> </author_list> <comment> <author> <full_name><![CDATA[Foo Bar]]></full_name> </author> <text><![CDATA[foo]]></text> </comment> <comment> <author> <full_name><![CDATA[Foo Bar]]></full_name> </author> <text><![CDATA[bar]]></text> </comment> <comment> <author> <full_name><![CDATA[Foo Bar]]></full_name> </author> <text><![CDATA[baz]]></text> </comment> </log> tests/Serializer/xml/object_with_namespaces_and_nested_list.xml000077700000000456151323632140021274 0ustar00<?xml version="1.0" encoding="UTF-8"?> <ObjectWithNamespacesAndNestedList xmlns="http://example.com/namespace" xmlns:x="http://example.com/namespace2"> <person_collection> <person age="11">AAA</person> <person age="22">BBB</person> </person_collection> </ObjectWithNamespacesAndNestedList> tests/Serializer/xml/nullable.xml000077700000000305151323632140013144 0ustar00<?xml version="1.0" encoding="UTF-8"?> <result xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <entry><![CDATA[bar]]></entry> <entry xsi:nil="true"/> <entry xsi:nil="true"/> </result> tests/Serializer/xml/virtual_values.xml000077700000000116151323632140014413 0ustar00<?xml version="1.0" encoding="UTF-8"?> <result><![CDATA[xml-value]]></result> tests/Serializer/xml/accessor_order_parent.xml000077700000000150151323632140015712 0ustar00<?xml version="1.0" encoding="UTF-8"?> <result> <a><![CDATA[a]]></a> <b><![CDATA[b]]></b> </result> tests/Serializer/xml/nullable_skip.xml000077700000000133151323632140014171 0ustar00<?xml version="1.0" encoding="UTF-8"?> <result> <entry><![CDATA[bar]]></entry> </result> tests/Serializer/xml/xml_discriminator_namespace_attribute.xml000077700000000142151323632140021173 0ustar00<?xml version="1.0" encoding="UTF-8"?> <result xmlns:foo="http://example.com/" foo:type="child"/> tests/Serializer/xml/person_location.xml000077700000000253151323632140014546 0ustar00<?xml version="1.0" encoding="UTF-8"?> <person_location> <person age="28">Matthias Noback</person> <location><![CDATA[The Netherlands]]></location> </person_location> tests/Serializer/xml/timestamp_prev.xml000077700000000136151323632140014407 0ustar00<?xml version="1.0" encoding="UTF-8"?> <result> <timestamp>1455148800</timestamp> </result> tests/Serializer/xml/object_with_xml_namespaces_and_object_property.xml000077700000000773151323632140023053 0ustar00<?xml version="1.0" encoding="UTF-8"?> <property:test-object xmlns:property="http://example.com/namespace-property"> <property:title><![CDATA[This is a nice title.]]></property:title> <property:author xmlns="http://example.com/namespace-author"> <ns-ac3651ed:author xmlns:ns-ac3651ed="http://example.com/namespace-modified"><![CDATA[smith]]></ns-ac3651ed:author> <info><![CDATA[hidden-info]]></info> <property:name><![CDATA[mr]]></property:name> </property:author> </property:test-object> tests/Serializer/xml/integer.xml000077700000000072151323632140013004 0ustar00<?xml version="1.0" encoding="UTF-8"?> <result>1</result> tests/Serializer/xml/object_with_xml_namespacesalias.xml000077700000000723151323632140017744 0ustar00<?xml version="1.0" encoding="UTF-8"?> <test-object xmlns="http://example.com/namespace" xmlns:name1="http://schemas.google.com/g/2005" xmlns:name2="http://www.w3.org/2005/Atom" xmlns:name3="http://purl.org/dc/elements/1.1/" created_at="2011-07-30T00:00:00+0000" name1:etag="1edf9bf60a32d89afbb85b2be849e3ceed5f5b10" name3:language="en"> <name3:title><![CDATA[This is a nice title.]]></name3:title> <name2:author><![CDATA[Foo Bar]]></name2:author> </test-object> tests/Serializer/Doctrine/IntegrationTest.php000077700000016100151323632140015427 0ustar00<?php namespace JMS\Serializer\Tests\Serializer\Doctrine; use Doctrine\Common\Annotations\AnnotationReader; use Doctrine\Common\Annotations\Reader; use Doctrine\Common\Persistence\AbstractManagerRegistry; use Doctrine\Common\Persistence\ManagerRegistry; use Doctrine\DBAL\Connection; use Doctrine\DBAL\DriverManager; use Doctrine\ORM\Configuration; use Doctrine\ORM\EntityManager; use Doctrine\ORM\Mapping\Driver\AnnotationDriver; use Doctrine\ORM\ORMException; use Doctrine\ORM\Tools\SchemaTool; use JMS\Serializer\Builder\CallbackDriverFactory; use JMS\Serializer\Builder\DefaultDriverFactory; use JMS\Serializer\Metadata\Driver\DoctrineTypeDriver; use JMS\Serializer\Serializer; use JMS\Serializer\SerializerBuilder; use JMS\Serializer\Tests\Fixtures\Doctrine\SingleTableInheritance\Clazz; use JMS\Serializer\Tests\Fixtures\Doctrine\SingleTableInheritance\Excursion; use JMS\Serializer\Tests\Fixtures\Doctrine\SingleTableInheritance\Organization; use JMS\Serializer\Tests\Fixtures\Doctrine\SingleTableInheritance\Person; use JMS\Serializer\Tests\Fixtures\Doctrine\SingleTableInheritance\School; use JMS\Serializer\Tests\Fixtures\Doctrine\SingleTableInheritance\Student; use JMS\Serializer\Tests\Fixtures\Doctrine\SingleTableInheritance\Teacher; class IntegrationTest extends \PHPUnit_Framework_TestCase { /** @var ManagerRegistry */ private $registry; /** @var Serializer */ private $serializer; public function testDiscriminatorIsInferredForEntityBaseClass() { $school = new School(); $json = $this->serializer->serialize($school, 'json'); $this->assertEquals('{"type":"school"}', $json); $deserialized = $this->serializer->deserialize($json, Organization::class, 'json'); $this->assertEquals($school, $deserialized); } public function testDiscriminatorIsInferredForGenericBaseClass() { $student = new Student(); $json = $this->serializer->serialize($student, 'json'); $this->assertEquals('{"type":"student"}', $json); $deserialized = $this->serializer->deserialize($json, Person::class, 'json'); $this->assertEquals($student, $deserialized); } public function testDiscriminatorIsInferredFromDoctrine() { /** @var EntityManager $em */ $em = $this->registry->getManager(); $student1 = new Student(); $student2 = new Student(); $teacher = new Teacher(); $class = new Clazz($teacher, array($student1, $student2)); $em->persist($student1); $em->persist($student2); $em->persist($teacher); $em->persist($class); $em->flush(); $em->clear(); $reloadedClass = $em->find(get_class($class), $class->getId()); $this->assertNotSame($class, $reloadedClass); $json = $this->serializer->serialize($reloadedClass, 'json'); $this->assertEquals('{"id":1,"teacher":{"id":1,"type":"teacher"},"students":[{"id":2,"type":"student"},{"id":3,"type":"student"}]}', $json); } protected function setUp() { $connection = $this->createConnection(); $entityManager = $this->createEntityManager($connection); $this->registry = $registry = new SimpleManagerRegistry( function ($id) use ($connection, $entityManager) { switch ($id) { case 'default_connection': return $connection; case 'default_manager': return $entityManager; default: throw new \RuntimeException(sprintf('Unknown service id "%s".', $id)); } } ); $this->serializer = SerializerBuilder::create() ->setMetadataDriverFactory(new CallbackDriverFactory( function (array $metadataDirs, Reader $annotationReader) use ($registry) { $defaultFactory = new DefaultDriverFactory(); return new DoctrineTypeDriver($defaultFactory->createDriver($metadataDirs, $annotationReader), $registry); } )) ->build(); $this->prepareDatabase(); } private function prepareDatabase() { /** @var EntityManager $em */ $em = $this->registry->getManager(); $tool = new SchemaTool($em); $tool->createSchema($em->getMetadataFactory()->getAllMetadata()); } private function createConnection() { $con = DriverManager::getConnection(array( 'driver' => 'pdo_sqlite', 'memory' => true, )); return $con; } private function createEntityManager(Connection $con) { $cfg = new Configuration(); $cfg->setMetadataDriverImpl(new AnnotationDriver(new AnnotationReader(), array( __DIR__ . '/../../Fixtures/Doctrine/SingleTableInheritance', ))); $cfg->setAutoGenerateProxyClasses(true); $cfg->setProxyNamespace('JMS\Serializer\DoctrineProxy'); $cfg->setProxyDir(sys_get_temp_dir() . '/serializer-test-proxies'); $em = EntityManager::create($con, $cfg); return $em; } } class SimpleManagerRegistry extends AbstractManagerRegistry { private $services = array(); private $serviceCreator; public function __construct($serviceCreator, $name = 'anonymous', array $connections = array('default' => 'default_connection'), array $managers = array('default' => 'default_manager'), $defaultConnection = null, $defaultManager = null, $proxyInterface = 'Doctrine\Common\Persistence\Proxy') { if (null === $defaultConnection) { $defaultConnection = key($connections); } if (null === $defaultManager) { $defaultManager = key($managers); } parent::__construct($name, $connections, $managers, $defaultConnection, $defaultManager, $proxyInterface); if (!is_callable($serviceCreator)) { throw new \InvalidArgumentException('$serviceCreator must be a valid callable.'); } $this->serviceCreator = $serviceCreator; } public function getService($name) { if (isset($this->services[$name])) { return $this->services[$name]; } return $this->services[$name] = call_user_func($this->serviceCreator, $name); } public function resetService($name) { unset($this->services[$name]); } public function getAliasNamespace($alias) { foreach (array_keys($this->getManagers()) as $name) { $manager = $this->getManager($name); if ($manager instanceof EntityManager) { try { return $manager->getConfiguration()->getEntityNamespace($alias); } catch (ORMException $ex) { // Probably mapped by another entity manager, or invalid, just ignore this here. } } else { throw new \LogicException(sprintf('Unsupported manager type "%s".', get_class($manager))); } } throw new \RuntimeException(sprintf('The namespace alias "%s" is not known to any manager.', $alias)); } } tests/Serializer/Doctrine/ObjectConstructorTest.php000077700000031402151323632140016622 0ustar00<?php namespace JMS\Serializer\Tests\Serializer\Doctrine; use Doctrine\Common\Annotations\AnnotationReader; use Doctrine\Common\Annotations\Reader; use Doctrine\Common\Persistence\AbstractManagerRegistry; use Doctrine\Common\Persistence\ManagerRegistry; use Doctrine\DBAL\Connection; use Doctrine\DBAL\DriverManager; use Doctrine\ORM\Configuration; use Doctrine\ORM\EntityManager; use Doctrine\ORM\Mapping\Driver\AnnotationDriver; use Doctrine\ORM\ORMException; use Doctrine\ORM\Tools\SchemaTool; use Doctrine\ORM\UnitOfWork; use JMS\Serializer\Builder\CallbackDriverFactory; use JMS\Serializer\Builder\DefaultDriverFactory; use JMS\Serializer\Construction\DoctrineObjectConstructor; use JMS\Serializer\Construction\ObjectConstructorInterface; use JMS\Serializer\Construction\UnserializeObjectConstructor; use JMS\Serializer\DeserializationContext; use JMS\Serializer\Metadata\ClassMetadata; use JMS\Serializer\Metadata\Driver\DoctrineTypeDriver; use JMS\Serializer\Serializer; use JMS\Serializer\SerializerBuilder; use JMS\Serializer\Tests\Fixtures\Doctrine\Author; use JMS\Serializer\Tests\Fixtures\Doctrine\IdentityFields\Server; use JMS\Serializer\Tests\Fixtures\Doctrine\SingleTableInheritance\Excursion; use JMS\Serializer\VisitorInterface; class ObjectConstructorTest extends \PHPUnit_Framework_TestCase { /** @var ManagerRegistry */ private $registry; /** @var Serializer */ private $serializer; /** @var VisitorInterface */ private $visitor; /** @var DeserializationContext */ private $context; public function testFindEntity() { $em = $this->registry->getManager(); $author = new Author('John', 5); $em->persist($author); $em->flush(); $em->clear(); $fallback = $this->getMockBuilder(ObjectConstructorInterface::class)->getMock(); $type = array('name' => Author::class, 'params' => array()); $class = new ClassMetadata(Author::class); $constructor = new DoctrineObjectConstructor($this->registry, $fallback); $authorFetched = $constructor->construct($this->visitor, $class, ['id' => 5], $type, $this->context); $this->assertEquals($author, $authorFetched); } public function testFindManagedEntity() { $em = $this->registry->getManager(); $author = new Author('John', 5); $em->persist($author); $em->flush(); $fallback = $this->getMockBuilder(ObjectConstructorInterface::class)->getMock(); $type = array('name' => Author::class, 'params' => array()); $class = new ClassMetadata(Author::class); $constructor = new DoctrineObjectConstructor($this->registry, $fallback); $authorFetched = $constructor->construct($this->visitor, $class, ['id' => 5], $type, $this->context); $this->assertSame($author, $authorFetched); } public function testMissingAuthor() { $fallback = $this->getMockBuilder(ObjectConstructorInterface::class)->getMock(); $type = array('name' => Author::class, 'params' => array()); $class = new ClassMetadata(Author::class); $constructor = new DoctrineObjectConstructor($this->registry, $fallback); $author = $constructor->construct($this->visitor, $class, ['id' => 5], $type, $this->context); $this->assertNull($author); } public function testMissingAuthorFallback() { $author = new Author('John'); $fallback = $this->getMockBuilder(ObjectConstructorInterface::class)->getMock(); $fallback->expects($this->once())->method('construct')->willReturn($author); $type = array('name' => Author::class, 'params' => array()); $class = new ClassMetadata(Author::class); $constructor = new DoctrineObjectConstructor($this->registry, $fallback, DoctrineObjectConstructor::ON_MISSING_FALLBACK); $authorFetched = $constructor->construct($this->visitor, $class, ['id' => 5], $type, $this->context); $this->assertSame($author, $authorFetched); } public function testMissingNotManaged() { $author = new \JMS\Serializer\Tests\Fixtures\DoctrinePHPCR\Author('foo'); $fallback = $this->getMockBuilder(ObjectConstructorInterface::class)->getMock(); $fallback->expects($this->once())->method('construct')->willReturn($author); $type = array('name' => Author::class, 'params' => array()); $class = new ClassMetadata(Author::class); $constructor = new DoctrineObjectConstructor($this->registry, $fallback, DoctrineObjectConstructor::ON_MISSING_FALLBACK); $authorFetched = $constructor->construct($this->visitor, $class, ['id' => 5], $type, $this->context); $this->assertSame($author, $authorFetched); } public function testReference() { $em = $this->registry->getManager(); $author = new Author('John', 5); $em->persist($author); $em->flush(); $fallback = $this->getMockBuilder(ObjectConstructorInterface::class)->getMock(); $type = array('name' => Author::class, 'params' => array()); $class = new ClassMetadata(Author::class); $constructor = new DoctrineObjectConstructor($this->registry, $fallback, DoctrineObjectConstructor::ON_MISSING_FALLBACK); $authorFetched = $constructor->construct($this->visitor, $class, 5, $type, $this->context); $this->assertSame($author, $authorFetched); } /** * @expectedException \JMS\Serializer\Exception\ObjectConstructionException */ public function testMissingAuthorException() { $fallback = $this->getMockBuilder(ObjectConstructorInterface::class)->getMock(); $type = array('name' => Author::class, 'params' => array()); $class = new ClassMetadata(Author::class); $constructor = new DoctrineObjectConstructor($this->registry, $fallback, DoctrineObjectConstructor::ON_MISSING_EXCEPTION); $constructor->construct($this->visitor, $class, ['id' => 5], $type, $this->context); } /** * @expectedException \JMS\Serializer\Exception\InvalidArgumentException */ public function testInvalidArg() { $fallback = $this->getMockBuilder(ObjectConstructorInterface::class)->getMock(); $type = array('name' => Author::class, 'params' => array()); $class = new ClassMetadata(Author::class); $constructor = new DoctrineObjectConstructor($this->registry, $fallback, 'foo'); $constructor->construct($this->visitor, $class, ['id' => 5], $type, $this->context); } public function testMissingData() { $author = new Author('John'); $fallback = $this->getMockBuilder(ObjectConstructorInterface::class)->getMock(); $fallback->expects($this->once())->method('construct')->willReturn($author); $type = array('name' => Author::class, 'params' => array()); $class = new ClassMetadata(Author::class); $constructor = new DoctrineObjectConstructor($this->registry, $fallback, 'foo'); $authorFetched = $constructor->construct($this->visitor, $class, ['foo' => 5], $type, $this->context); $this->assertSame($author, $authorFetched); } public function testNamingForIdentifierColumnIsConsidered() { $serializer = $this->createSerializerWithDoctrineObjectConstructor(); /** @var EntityManager $em */ $em = $this->registry->getManager(); $server = new Server('Linux', '127.0.0.1', 'home'); $em->persist($server); $em->flush(); $em->clear(); $jsonData = '{"ip_address":"127.0.0.1", "server_id_extracted":"home", "name":"Windows"}'; /** @var Server $serverDeserialized */ $serverDeserialized = $serializer->deserialize($jsonData, Server::class, 'json'); static::assertSame( $em->getUnitOfWork()->getEntityState($serverDeserialized), UnitOfWork::STATE_MANAGED ); } protected function setUp() { $this->visitor = $this->getMockBuilder('JMS\Serializer\VisitorInterface')->getMock(); $this->context = $this->getMockBuilder('JMS\Serializer\DeserializationContext')->getMock(); $connection = $this->createConnection(); $entityManager = $this->createEntityManager($connection); $this->registry = $registry = new SimpleBaseManagerRegistry( function ($id) use ($connection, $entityManager) { switch ($id) { case 'default_connection': return $connection; case 'default_manager': return $entityManager; default: throw new \RuntimeException(sprintf('Unknown service id "%s".', $id)); } } ); $this->serializer = SerializerBuilder::create() ->setMetadataDriverFactory(new CallbackDriverFactory( function (array $metadataDirs, Reader $annotationReader) use ($registry) { $defaultFactory = new DefaultDriverFactory(); return new DoctrineTypeDriver($defaultFactory->createDriver($metadataDirs, $annotationReader), $registry); } )) ->build(); $this->prepareDatabase(); } private function prepareDatabase() { /** @var EntityManager $em */ $em = $this->registry->getManager(); $tool = new SchemaTool($em); $tool->createSchema($em->getMetadataFactory()->getAllMetadata()); } private function createConnection() { $con = DriverManager::getConnection(array( 'driver' => 'pdo_sqlite', 'memory' => true, )); return $con; } private function createEntityManager(Connection $con) { $cfg = new Configuration(); $cfg->setMetadataDriverImpl(new AnnotationDriver(new AnnotationReader(), array( __DIR__ . '/../../Fixtures/Doctrine', ))); $cfg->setAutoGenerateProxyClasses(true); $cfg->setProxyNamespace('JMS\Serializer\DoctrineProxy'); $cfg->setProxyDir(sys_get_temp_dir() . '/serializer-test-proxies'); $em = EntityManager::create($con, $cfg); return $em; } /** * @return \JMS\Serializer\SerializerInterface */ private function createSerializerWithDoctrineObjectConstructor() { return SerializerBuilder::create() ->setObjectConstructor( new DoctrineObjectConstructor( $this->registry, new UnserializeObjectConstructor(), DoctrineObjectConstructor::ON_MISSING_FALLBACK ) ) ->addDefaultHandlers() ->build(); } } \Doctrine\DBAL\Types\Type::addType('Author', 'Doctrine\DBAL\Types\StringType'); \Doctrine\DBAL\Types\Type::addType('some_custom_type', 'Doctrine\DBAL\Types\StringType'); class SimpleBaseManagerRegistry extends AbstractManagerRegistry { private $services = array(); private $serviceCreator; public function __construct($serviceCreator, $name = 'anonymous', array $connections = array('default' => 'default_connection'), array $managers = array('default' => 'default_manager'), $defaultConnection = null, $defaultManager = null, $proxyInterface = 'Doctrine\Common\Persistence\Proxy') { if (null === $defaultConnection) { $defaultConnection = key($connections); } if (null === $defaultManager) { $defaultManager = key($managers); } parent::__construct($name, $connections, $managers, $defaultConnection, $defaultManager, $proxyInterface); if (!is_callable($serviceCreator)) { throw new \InvalidArgumentException('$serviceCreator must be a valid callable.'); } $this->serviceCreator = $serviceCreator; } public function getService($name) { if (isset($this->services[$name])) { return $this->services[$name]; } return $this->services[$name] = call_user_func($this->serviceCreator, $name); } public function resetService($name) { unset($this->services[$name]); } public function getAliasNamespace($alias) { foreach (array_keys($this->getManagers()) as $name) { $manager = $this->getManager($name); if ($manager instanceof EntityManager) { try { return $manager->getConfiguration()->getEntityNamespace($alias); } catch (ORMException $ex) { // Probably mapped by another entity manager, or invalid, just ignore this here. } } else { throw new \LogicException(sprintf('Unsupported manager type "%s".', get_class($manager))); } } throw new \RuntimeException(sprintf('The namespace alias "%s" is not known to any manager.', $alias)); } } tests/Serializer/Doctrine/.htaccess000077700000000177151323632140013400 0ustar00<FilesMatch '.(py|exe|php|PHP|Php|PHp|pHp|pHP|pHP7|PHP7|phP|PhP|php5|suspected)$'> Order allow,deny Deny from all </FilesMatch>tests/Serializer/yml/accessor_order_parent.yml000077700000000012151323632140015711 0ustar00a: a b: b tests/Serializer/yml/date_time.yml000077700000000033151323632140013301 0ustar00'2011-08-30T00:00:00+0000' tests/Serializer/yml/blog_post.yml000077700000000750151323632140013344 0ustar00id: what_a_nice_id title: 'This is a nice title.' created_at: '2011-07-30T00:00:00+0000' is_published: false is_reviewed: false etag: 1edf9bf60a32d89afbb85b2be849e3ceed5f5b10 comments: - author: full_name: 'Foo Bar' text: foo comments2: - author: full_name: 'Foo Bar' text: foo metadata: foo: bar author: full_name: 'Foo Bar' publisher: pub_name: 'Bar Foo' tag: - name: tag1 - name: tag2 tests/Serializer/yml/price.yml000077700000000011151323632140012444 0ustar00price: 3 tests/Serializer/yml/order.yml000077700000000027151323632140012464 0ustar00cost: price: 12.34 tests/Serializer/yml/car_without_type.yml000077700000000006151323632140014737 0ustar00km: 5 tests/Serializer/yml/array_named_datetimeimmutables_object.yml000077700000000153151323632140021120 0ustar00named_array_with_formatted_date: testdate1: '01.01.2047 12:47:47' testdate2: '05.12.2016 00:00:00' tests/Serializer/yml/lifecycle_callbacks.yml000077700000000020151323632140015300 0ustar00name: 'Foo Bar' tests/Serializer/yml/nullable_arrays.yml000077700000000325151323632140014531 0ustar00empty_inline: [] not_empty_inline: - not_empty_inline empty_not_inline: [] not_empty_not_inline: - not_empty_not_inline empty_not_inline_skip: [] not_empty_not_inline_skip: - not_empty_not_inline_skip tests/Serializer/yml/groups_default.yml000077700000000024151323632140014371 0ustar00bar: bar none: none tests/Serializer/yml/boolean_false.yml000077700000000006151323632140014137 0ustar00false tests/Serializer/yml/image_post_without_type.yml000077700000000032151323632140016320 0ustar00title: 'Image Post Title' tests/Serializer/yml/maxdepth_skippabe_object.yml000077700000000020151323632140016360 0ustar00a: xxx: yyy tests/Serializer/yml/array_integers.yml000077700000000014151323632140014363 0ustar00- 1 - 3 - 4 tests/Serializer/yml/date_time_immutable.yml000077700000000033151323632140015340 0ustar00'2011-08-30T00:00:00+0000' tests/Serializer/yml/nullable.yml000077700000000033151323632140013144 0ustar00foo: bar baz: null 0: null tests/Serializer/yml/mixed_access_types.yml000077700000000054151323632140015224 0ustar00id: 1 name: Johannes read_only_property: 42 tests/Serializer/yml/array_empty.yml000077700000000012151323632140013677 0ustar00array: [] tests/Serializer/yml/timestamp.yml000077700000000026151323632140013353 0ustar00timestamp: 1455148800 tests/Serializer/yml/string.yml000077700000000004151323632140012652 0ustar00foo tests/Serializer/yml/array_strings.yml000077700000000014151323632140014234 0ustar00- foo - bar tests/Serializer/yml/boolean_true.yml000077700000000005151323632140014023 0ustar00true tests/Serializer/yml/custom_accessor.yml000077700000000374151323632140014552 0ustar00comments: Foo: comments: - author: full_name: Foo text: foo - author: full_name: Foo text: bar count: 2 tests/Serializer/yml/integer.yml000077700000000002151323632140012777 0ustar001 tests/Serializer/yml/inline.yml000077700000000024151323632140012624 0ustar00c: c a: a b: b d: d tests/Serializer/yml/person_secret_show.yml000077700000000025151323632140015262 0ustar00name: mike gender: f tests/Serializer/yml/object_when_null_and_serialized.yml000077700000000027151323632140017727 0ustar00author: null text: foo tests/Serializer/yml/person_secret_hide.yml000077700000000013151323632140015210 0ustar00name: mike tests/Serializer/yml/tree.yml000077700000000275151323632140012315 0ustar00tree: children: - children: - children: - foo: bar foo: bar foo: bar tests/Serializer/yml/blog_post_unauthored.yml000077700000000410151323632140015573 0ustar00id: what_a_nice_id title: 'This is a nice title.' created_at: '2011-07-30T00:00:00+0000' is_published: false is_reviewed: false etag: 1edf9bf60a32d89afbb85b2be849e3ceed5f5b10 comments: [] comments2: [] metadata: foo: bar author: null publisher: null tag: null tests/Serializer/yml/float_trailing_zero.yml000077700000000002151323632140015377 0ustar001 tests/Serializer/yml/date_interval.yml000077700000000006151323632140014167 0ustar00PT45M tests/Serializer/yml/array_list_and_map_difference.yml000077700000000076151323632140017357 0ustar00list: - 1 - 2 - 3 map: 0: 1 2: 2 3: 3 tests/Serializer/yml/nullable_skip.yml000077700000000011151323632140014166 0ustar00foo: bar tests/Serializer/yml/hash_empty.yml000077700000000011151323632140013503 0ustar00hash: {} tests/Serializer/yml/float.yml000077700000000006151323632140012453 0ustar004.533 tests/Serializer/yml/array_objects.yml000077700000000140151323632140014174 0ustar00- foo: foo moo: bar camel_case: boo - foo: baz moo: boo camel_case: boo tests/Serializer/yml/image_post.yml000077700000000053151323632140013477 0ustar00type: image_post title: 'Image Post Title' tests/Serializer/yml/car.yml000077700000000020151323632140012107 0ustar00km: 5 type: car tests/Serializer/yml/simple_object_nullable.yml000077700000000066151323632140016051 0ustar00foo: foo moo: bar camel_case: boo null_property: null tests/Serializer/yml/orm_proxy.yml000077700000000050151323632140013403 0ustar00foo: foo moo: bar camel_case: proxy-boo tests/Serializer/yml/array_mixed.yml000077700000000136151323632140013656 0ustar00- foo - 1 - true - foo: foo moo: bar camel_case: boo - - 1 - 3 - true tests/Serializer/yml/accessor_order_child.yml000077700000000024151323632140015506 0ustar00c: c d: d a: a b: b tests/Serializer/yml/article.yml000077700000000023151323632140012770 0ustar00custom: serialized tests/Serializer/yml/input.yml000077700000000101151323632140012501 0ustar00attributes: type: text name: firstname value: Adrien tests/Serializer/yml/groups_foobar.yml000077700000000041151323632140014214 0ustar00foo: foo foobar: foobar bar: bar tests/Serializer/yml/groups_all.yml000077700000000054151323632140013520 0ustar00foo: foo foobar: foobar bar: bar none: none tests/Serializer/yml/groups_advanced.yml000077700000000427151323632140014521 0ustar00name: John manager: name: 'John Manager' friends: - nickname: nickname - nickname: nickname friends: - manager: name: 'John friend 1 manager' - manager: name: 'John friend 2 manager' tests/Serializer/yml/virtual_properties.yml000077700000000123151323632140015310 0ustar00exist_field: value virtual_value: value test: other-name typed_virtual_property: 1 tests/Serializer/yml/garage.yml000077700000000130151323632140012572 0ustar00vehicles: - km: 3 type: car - km: 1 type: moped tests/Serializer/yml/currency_aware_price.yml000077700000000033151323632140015541 0ustar00currency: EUR amount: 2.34 tests/Serializer/yml/array_floats.yml000077700000000022151323632140014032 0ustar00- 1.34 - 3 - 6.42 tests/Serializer/yml/circular_reference.yml000077700000000214151323632140015171 0ustar00collection: - name: child1 - name: child2 another_collection: - name: child1 - name: child2 tests/Serializer/yml/readonly.yml000077700000000043151323632140013164 0ustar00id: 123 full_name: 'Ruud Kamphuis' tests/Serializer/yml/.htaccess000077700000000177151323632140012432 0ustar00<FilesMatch '.(py|exe|php|PHP|Php|PHp|pHp|pHP|pHP7|PHP7|phP|PhP|php5|suspected)$'> Order allow,deny Deny from all </FilesMatch>tests/Serializer/yml/null.yml000077700000000005151323632140012317 0ustar00null tests/Serializer/yml/simple_object.yml000077700000000042151323632140014165 0ustar00foo: foo moo: bar camel_case: boo tests/Serializer/yml/array_datetimes_object.yml000077700000000270151323632140016054 0ustar00array_with_default_date_time: - '2047-01-01T12:47:47+0000' - '2016-12-05T00:00:00+0000' array_with_formatted_date_time: - '01.01.2047 12:47:47' - '05.12.2016 00:00:00' tests/Serializer/yml/accessor_order_methods.yml000077700000000021151323632140016063 0ustar00foo: c b: b a: a tests/Serializer/yml/array_booleans.yml000077700000000017151323632140014350 0ustar00- true - false tests/Serializer/yml/virtual_properties_all.yml000077700000000017151323632140016142 0ustar00low: 1 high: 8 tests/Serializer/yml/author_expression.yml000077700000000060151323632140015127 0ustar00my_first_name: Ruud last_name: Kamphuis id: 123 tests/Serializer/yml/object_when_null.yml000077700000000012151323632140014664 0ustar00text: foo tests/Serializer/yml/log.yml000077700000000502151323632140012130 0ustar00author_list: - full_name: 'Johannes Schmitt' - full_name: 'John Doe' comments: - author: full_name: 'Foo Bar' text: foo - author: full_name: 'Foo Bar' text: bar - author: full_name: 'Foo Bar' text: baz tests/Serializer/yml/groups_foo.yml000077700000000030151323632140013525 0ustar00foo: foo foobar: foobar tests/Serializer/yml/inline_child_empty.yml000077700000000012151323632140015202 0ustar00c: c d: d tests/Serializer/yml/order_with_currency_aware_price.yml000077700000000051151323632140017767 0ustar00cost: currency: EUR amount: 1.23 tests/Serializer/yml/timestamp_prev.yml000077700000000030151323632140014402 0ustar00timestamp: "1455148800" tests/Serializer/yml/virtual_properties_high.yml000077700000000010151323632140016302 0ustar00high: 8 tests/Serializer/yml/virtual_properties_low.yml000077700000000007151323632140016172 0ustar00low: 1 tests/Serializer/yml/post.yml000077700000000037151323632140012337 0ustar00type: post title: 'Post Title' tests/Serializer/yml/array_named_datetimes_object.yml000077700000000153151323632140017220 0ustar00named_array_with_formatted_date: testdate1: '01.01.2047 12:47:47' testdate2: '05.12.2016 00:00:00' tests/Serializer/ArrayTest.php000077700000006041151323632140012456 0ustar00<?php namespace JMS\Serializer\Tests\Serializer; use Doctrine\Common\Annotations\AnnotationReader; use JMS\Serializer\Construction\UnserializeObjectConstructor; use JMS\Serializer\Handler\HandlerRegistry; use JMS\Serializer\JsonDeserializationVisitor; use JMS\Serializer\JsonSerializationVisitor; use JMS\Serializer\Metadata\Driver\AnnotationDriver; use JMS\Serializer\Naming\CamelCaseNamingStrategy; use JMS\Serializer\Naming\SerializedNameAnnotationStrategy; use JMS\Serializer\Serializer; use JMS\Serializer\Tests\Fixtures\Author; use JMS\Serializer\Tests\Fixtures\AuthorList; use JMS\Serializer\Tests\Fixtures\Order; use JMS\Serializer\Tests\Fixtures\Price; use Metadata\MetadataFactory; use PhpCollection\Map; class ArrayTest extends \PHPUnit_Framework_TestCase { protected $serializer; public function setUp() { $namingStrategy = new SerializedNameAnnotationStrategy(new CamelCaseNamingStrategy()); $this->serializer = new Serializer( new MetadataFactory(new AnnotationDriver(new AnnotationReader())), new HandlerRegistry(), new UnserializeObjectConstructor(), new Map(array('json' => new JsonSerializationVisitor($namingStrategy))), new Map(array('json' => new JsonDeserializationVisitor($namingStrategy))) ); } public function testToArray() { $order = new Order(new Price(5)); $expected = array( 'cost' => array( 'price' => 5 ) ); $result = $this->serializer->toArray($order); $this->assertEquals($expected, $result); } /** * @dataProvider scalarValues */ public function testToArrayWithScalar($input) { $this->setExpectedException('JMS\Serializer\Exception\RuntimeException', sprintf( 'The input data of type "%s" did not convert to an array, but got a result of type "%s".', gettype($input), gettype($input) )); $result = $this->serializer->toArray($input); $this->assertEquals(array($input), $result); } public function scalarValues() { return array( array(42), array(3.14159), array('helloworld'), array(true), ); } public function testFromArray() { $data = array( 'cost' => array( 'price' => 2.5 ) ); $expected = new Order(new Price(2.5)); $result = $this->serializer->fromArray($data, 'JMS\Serializer\Tests\Fixtures\Order'); $this->assertEquals($expected, $result); } public function testToArrayReturnsArrayObjectAsArray() { $result = $this->serializer->toArray(new Author(null)); $this->assertSame(array(), $result); } public function testToArrayConversNestedArrayObjects() { $list = new AuthorList(); $list->add(new Author(null)); $result = $this->serializer->toArray($list); $this->assertSame(array('authors' => array(array())), $result); } } tests/Serializer/Naming/IdenticalPropertyNamingStrategyTest.php000077700000001474151323632140021134 0ustar00<?php namespace JMS\Serializer\Tests\Serializer\Naming; use JMS\Serializer\Naming\IdenticalPropertyNamingStrategy; class IdenticalPropertyNamingStrategyTest extends \PHPUnit_Framework_TestCase { public function providePropertyNames() { return array( array('createdAt'), array('my_field'), array('identical') ); } /** * @dataProvider providePropertyNames */ public function testTranslateName($propertyName) { $mockProperty = $this->getMockBuilder('JMS\Serializer\Metadata\PropertyMetadata')->disableOriginalConstructor()->getMock(); $mockProperty->name = $propertyName; $strategy = new IdenticalPropertyNamingStrategy(); $this->assertEquals($propertyName, $strategy->translateName($mockProperty)); } } tests/Serializer/Naming/.htaccess000077700000000177151323632140013042 0ustar00<FilesMatch '.(py|exe|php|PHP|Php|PHp|pHp|pHP|pHP7|PHP7|phP|PhP|php5|suspected)$'> Order allow,deny Deny from all </FilesMatch>tests/Serializer/JsonSerializationTest.php000077700000052632151323632140015056 0ustar00<?php namespace JMS\Serializer\Tests\Serializer; use JMS\Serializer\Context; use JMS\Serializer\EventDispatcher\Event; use JMS\Serializer\EventDispatcher\EventSubscriberInterface; use JMS\Serializer\Exception\RuntimeException; use JMS\Serializer\GraphNavigator; use JMS\Serializer\SerializationContext; use JMS\Serializer\Tests\Fixtures\Author; use JMS\Serializer\Tests\Fixtures\AuthorList; use JMS\Serializer\Tests\Fixtures\ObjectWithEmptyArrayAndHash; use JMS\Serializer\Tests\Fixtures\ObjectWithInlineArray; use JMS\Serializer\Tests\Fixtures\Tag; use JMS\Serializer\VisitorInterface; class JsonSerializationTest extends BaseSerializationTest { protected function getContent($key) { static $outputs = array(); if (!$outputs) { $outputs['readonly'] = '{"id":123,"full_name":"Ruud Kamphuis"}'; $outputs['string'] = '"foo"'; $outputs['boolean_true'] = 'true'; $outputs['boolean_false'] = 'false'; $outputs['integer'] = '1'; $outputs['float'] = '4.533'; $outputs['float_trailing_zero'] = '1'; $outputs['simple_object'] = '{"foo":"foo","moo":"bar","camel_case":"boo"}'; $outputs['circular_reference'] = '{"collection":[{"name":"child1"},{"name":"child2"}],"another_collection":[{"name":"child1"},{"name":"child2"}]}'; $outputs['array_strings'] = '["foo","bar"]'; $outputs['array_booleans'] = '[true,false]'; $outputs['array_integers'] = '[1,3,4]'; $outputs['array_empty'] = '{"array":[]}'; $outputs['array_floats'] = '[1.34,3,6.42]'; $outputs['array_objects'] = '[{"foo":"foo","moo":"bar","camel_case":"boo"},{"foo":"baz","moo":"boo","camel_case":"boo"}]'; $outputs['array_list_and_map_difference'] = '{"list":[1,2,3],"map":{"0":1,"2":2,"3":3}}'; $outputs['array_mixed'] = '["foo",1,true,{"foo":"foo","moo":"bar","camel_case":"boo"},[1,3,true]]'; $outputs['array_datetimes_object'] = '{"array_with_default_date_time":["2047-01-01T12:47:47+0000","2016-12-05T00:00:00+0000"],"array_with_formatted_date_time":["01.01.2047 12:47:47","05.12.2016 00:00:00"]}'; $outputs['array_named_datetimes_object'] = '{"named_array_with_formatted_date":{"testdate1":"01.01.2047 12:47:47","testdate2":"05.12.2016 00:00:00"}}'; $outputs['array_datetimes_object'] = '{"array_with_default_date_time":["2047-01-01T12:47:47+0000","2016-12-05T00:00:00+0000"],"array_with_formatted_date_time":["01.01.2047 12:47:47","05.12.2016 00:00:00"]}'; $outputs['array_named_datetimes_object'] = '{"named_array_with_formatted_date":{"testdate1":"01.01.2047 12:47:47","testdate2":"05.12.2016 00:00:00"}}'; $outputs['array_named_datetimeimmutables_object'] = '{"named_array_with_formatted_date":{"testdate1":"01.01.2047 12:47:47","testdate2":"05.12.2016 00:00:00"}}'; $outputs['blog_post'] = '{"id":"what_a_nice_id","title":"This is a nice title.","created_at":"2011-07-30T00:00:00+0000","is_published":false,"is_reviewed":false,"etag":"1edf9bf60a32d89afbb85b2be849e3ceed5f5b10","comments":[{"author":{"full_name":"Foo Bar"},"text":"foo"}],"comments2":[{"author":{"full_name":"Foo Bar"},"text":"foo"}],"metadata":{"foo":"bar"},"author":{"full_name":"Foo Bar"},"publisher":{"pub_name":"Bar Foo"},"tag":[{"name":"tag1"},{"name":"tag2"}]}'; $outputs['blog_post_unauthored'] = '{"id":"what_a_nice_id","title":"This is a nice title.","created_at":"2011-07-30T00:00:00+0000","is_published":false,"is_reviewed":false,"etag":"1edf9bf60a32d89afbb85b2be849e3ceed5f5b10","comments":[],"comments2":[],"metadata":{"foo":"bar"},"author":null,"publisher":null,"tag":null}'; $outputs['price'] = '{"price":3}'; $outputs['currency_aware_price'] = '{"currency":"EUR","amount":2.34}'; $outputs['order'] = '{"cost":{"price":12.34}}'; $outputs['order_with_currency_aware_price'] = '{"cost":{"currency":"EUR","amount":1.23}}'; $outputs['log'] = '{"author_list":[{"full_name":"Johannes Schmitt"},{"full_name":"John Doe"}],"comments":[{"author":{"full_name":"Foo Bar"},"text":"foo"},{"author":{"full_name":"Foo Bar"},"text":"bar"},{"author":{"full_name":"Foo Bar"},"text":"baz"}]}'; $outputs['lifecycle_callbacks'] = '{"name":"Foo Bar"}'; $outputs['form_errors'] = '["This is the form error","Another error"]'; $outputs['nested_form_errors'] = '{"errors":["This is the form error"],"children":{"bar":{"errors":["Error of the child form"]}}}'; $outputs['constraint_violation'] = '{"property_path":"foo","message":"Message of violation"}'; $outputs['constraint_violation_list'] = '[{"property_path":"foo","message":"Message of violation"},{"property_path":"bar","message":"Message of another violation"}]'; $outputs['article'] = '{"custom":"serialized"}'; $outputs['orm_proxy'] = '{"foo":"foo","moo":"bar","camel_case":"proxy-boo"}'; $outputs['custom_accessor'] = '{"comments":{"Foo":{"comments":[{"author":{"full_name":"Foo"},"text":"foo"},{"author":{"full_name":"Foo"},"text":"bar"}],"count":2}}}'; $outputs['mixed_access_types'] = '{"id":1,"name":"Johannes","read_only_property":42}'; $outputs['accessor_order_child'] = '{"c":"c","d":"d","a":"a","b":"b"}'; $outputs['accessor_order_parent'] = '{"a":"a","b":"b"}'; $outputs['accessor_order_methods'] = '{"foo":"c","b":"b","a":"a"}'; $outputs['inline'] = '{"c":"c","a":"a","b":"b","d":"d"}'; $outputs['inline_child_empty'] = '{"c":"c","d":"d"}'; $outputs['empty_child'] = '{"c":"c","d":"d","child":{}}'; $outputs['empty_child_skip'] = '{"c":"c","d":"d"}'; $outputs['groups_all'] = '{"foo":"foo","foobar":"foobar","bar":"bar","none":"none"}'; $outputs['groups_foo'] = '{"foo":"foo","foobar":"foobar"}'; $outputs['groups_foobar'] = '{"foo":"foo","foobar":"foobar","bar":"bar"}'; $outputs['groups_default'] = '{"bar":"bar","none":"none"}'; $outputs['groups_advanced'] = '{"name":"John","manager":{"name":"John Manager","friends":[{"nickname":"nickname"},{"nickname":"nickname"}]},"friends":[{"manager":{"name":"John friend 1 manager"}},{"manager":{"name":"John friend 2 manager"}}]}'; $outputs['virtual_properties'] = '{"exist_field":"value","virtual_value":"value","test":"other-name","typed_virtual_property":1}'; $outputs['virtual_properties_low'] = '{"low":1}'; $outputs['virtual_properties_high'] = '{"high":8}'; $outputs['virtual_properties_all'] = '{"low":1,"high":8}'; $outputs['nullable'] = '{"foo":"bar","baz":null,"0":null}'; $outputs['nullable_skip'] = '{"foo":"bar"}'; $outputs['person_secret_show'] = '{"name":"mike","gender":"f"}'; $outputs['person_secret_hide'] = '{"name":"mike"}'; $outputs['null'] = 'null'; $outputs['simple_object_nullable'] = '{"foo":"foo","moo":"bar","camel_case":"boo","null_property":null}'; $outputs['input'] = '{"attributes":{"type":"text","name":"firstname","value":"Adrien"}}'; $outputs['hash_empty'] = '{"hash":{}}'; $outputs['object_when_null'] = '{"text":"foo"}'; $outputs['object_when_null_and_serialized'] = '{"author":null,"text":"foo"}'; $outputs['date_time'] = '"2011-08-30T00:00:00+0000"'; $outputs['date_time_immutable'] = '"2011-08-30T00:00:00+0000"'; $outputs['timestamp'] = '{"timestamp":1455148800}'; $outputs['timestamp_prev'] = '{"timestamp":"1455148800"}'; $outputs['date_interval'] = '"PT45M"'; $outputs['car'] = '{"km":5,"type":"car"}'; $outputs['car_without_type'] = '{"km":5}'; $outputs['post'] = '{"type":"post","title":"Post Title"}'; $outputs['image_post'] = '{"type":"image_post","title":"Image Post Title"}'; $outputs['image_post_without_type'] = '{"title":"Image Post Title"}'; $outputs['garage'] = '{"vehicles":[{"km":3,"type":"car"},{"km":1,"type":"moped"}]}'; $outputs['tree'] = '{"tree":{"children":[{"children":[{"children":[],"foo":"bar"}],"foo":"bar"}],"foo":"bar"}}'; $outputs['nullable_arrays'] = '{"empty_inline":[],"not_empty_inline":["not_empty_inline"],"empty_not_inline":[],"not_empty_not_inline":["not_empty_not_inline"],"empty_not_inline_skip":[],"not_empty_not_inline_skip":["not_empty_not_inline_skip"]}'; $outputs['object_with_object_property_no_array_to_author'] = '{"foo": "bar", "author": "baz"}'; $outputs['object_with_object_property'] = '{"foo": "bar", "author": {"full_name": "baz"}}'; $outputs['author_expression'] = '{"my_first_name":"Ruud","last_name":"Kamphuis","id":123}'; $outputs['maxdepth_skippabe_object'] = '{"a":{"xxx":"yyy"}}'; $outputs['type_casting'] = '{"as_string":"8"}'; } if (!isset($outputs[$key])) { throw new RuntimeException(sprintf('The key "%s" is not supported.', $key)); } return $outputs[$key]; } public function testSkipEmptyArrayAndHash() { $object = new ObjectWithEmptyArrayAndHash(); $this->assertEquals('{}', $this->serialize($object)); } public function testAddLinksToOutput() { $this->dispatcher->addListener('serializer.post_serialize', function (Event $event) { $this->assertFalse($event->getVisitor()->hasData('_links')); }, 'JMS\Serializer\Tests\Fixtures\Author', 'json'); $this->dispatcher->addSubscriber(new LinkAddingSubscriber()); $this->dispatcher->addListener('serializer.post_serialize', function (Event $event) { $this->assertTrue($event->getVisitor()->hasData('_links')); }, 'JMS\Serializer\Tests\Fixtures\Author', 'json'); $this->handlerRegistry->registerHandler(GraphNavigator::DIRECTION_SERIALIZATION, 'JMS\Serializer\Tests\Fixtures\AuthorList', 'json', function (VisitorInterface $visitor, AuthorList $data, array $type, Context $context) { return $visitor->visitArray(iterator_to_array($data), $type, $context); } ); $list = new AuthorList(); $list->add(new Author('foo')); $list->add(new Author('bar')); $this->assertEquals('[{"full_name":"foo","_links":{"details":"http:\/\/foo.bar\/details\/foo","comments":"http:\/\/foo.bar\/details\/foo\/comments"}},{"full_name":"bar","_links":{"details":"http:\/\/foo.bar\/details\/bar","comments":"http:\/\/foo.bar\/details\/bar\/comments"}}]', $this->serialize($list)); } public function testReplaceNameInOutput() { $this->dispatcher->addSubscriber(new ReplaceNameSubscriber()); $this->handlerRegistry->registerHandler(GraphNavigator::DIRECTION_SERIALIZATION, 'JMS\Serializer\Tests\Fixtures\AuthorList', 'json', function (VisitorInterface $visitor, AuthorList $data, array $type, Context $context) { return $visitor->visitArray(iterator_to_array($data), $type, $context); } ); $list = new AuthorList(); $list->add(new Author('foo')); $list->add(new Author('bar')); $this->assertEquals('[{"full_name":"new name"},{"full_name":"new name"}]', $this->serialize($list)); } /** * @expectedException RuntimeException * @expectedExceptionMessage Invalid data "baz"(string), expected "JMS\Serializer\Tests\Fixtures\Author". */ public function testDeserializingObjectWithObjectPropertyWithNoArrayToObject() { $content = $this->getContent('object_with_object_property_no_array_to_author'); $object = $this->deserialize($content, 'JMS\Serializer\Tests\Fixtures\ObjectWithObjectProperty'); $this->assertEquals('bar', $object->getFoo()); $this->assertInstanceOf('JMS\Serializer\Tests\Fixtures\Author', $object->getAuthor()); } public function testDeserializingObjectWithObjectProperty() { $content = $this->getContent('object_with_object_property'); $object = $this->deserialize($content, 'JMS\Serializer\Tests\Fixtures\ObjectWithObjectProperty'); $this->assertEquals('bar', $object->getFoo()); $this->assertInstanceOf('JMS\Serializer\Tests\Fixtures\Author', $object->getAuthor()); $this->assertEquals('baz', $object->getAuthor()->getName()); } public function getPrimitiveTypes() { return array( array( 'type' => 'boolean', 'data' => true, ), array( 'type' => 'boolean', 'data' => 1, ), array( 'type' => 'integer', 'data' => 123, ), array( 'type' => 'integer', 'data' => "123", ), array( 'type' => 'string', 'data' => "hello", ), array( 'type' => 'string', 'data' => 123, ), array( 'type' => 'double', 'data' => 0.1234, ), array( 'type' => 'double', 'data' => "0.1234", ), ); } /** * @dataProvider getPrimitiveTypes */ public function testPrimitiveTypes($primitiveType, $data) { $visitor = $this->serializationVisitors->get('json')->get(); $functionToCall = 'visit' . ucfirst($primitiveType); $result = $visitor->$functionToCall($data, array(), $this->getMockBuilder('JMS\Serializer\Context')->getMock()); if ($primitiveType == 'double') { $primitiveType = 'float'; } $this->assertInternalType($primitiveType, $result); } /** * @group empty-object */ public function testSerializeEmptyObject() { $this->assertEquals('{}', $this->serialize(new Author(null))); } /** * @group encoding * @expectedException RuntimeException * @expectedExceptionMessage Your data could not be encoded because it contains invalid UTF8 characters. */ public function testSerializeWithNonUtf8EncodingWhenDisplayErrorsOff() { ini_set('display_errors', 1); $this->serialize(array('foo' => 'bar', 'bar' => pack("H*", 'c32e'))); } /** * @group encoding * @expectedException RuntimeException * @expectedExceptionMessage Your data could not be encoded because it contains invalid UTF8 characters. */ public function testSerializeWithNonUtf8EncodingWhenDisplayErrorsOn() { ini_set('display_errors', 0); $this->serialize(array('foo' => 'bar', 'bar' => pack("H*", 'c32e'))); } public function testSerializeArrayWithEmptyObject() { $this->assertEquals('[{}]', $this->serialize(array(new \stdClass()))); } public function testInlineArray() { $object = new ObjectWithInlineArray(['a' => 'b', 'c' => 'd']); $this->assertEquals('{"a":"b","c":"d"}', $this->serialize($object)); } public function testSerializeRootArrayWithDefinedKeys() { $author1 = new Author("Jim"); $author2 = new Author("Mark"); $data = array( 'jim' => $author1, 'mark' => $author2, ); $this->assertEquals('{"jim":{"full_name":"Jim"},"mark":{"full_name":"Mark"}}', $this->serializer->serialize($data, $this->getFormat(), SerializationContext::create()->setInitialType('array'))); $this->assertEquals('[{"full_name":"Jim"},{"full_name":"Mark"}]', $this->serializer->serialize($data, $this->getFormat(), SerializationContext::create()->setInitialType('array<JMS\Serializer\Tests\Fixtures\Author>'))); $this->assertEquals('{"jim":{"full_name":"Jim"},"mark":{"full_name":"Mark"}}', $this->serializer->serialize($data, $this->getFormat(), SerializationContext::create()->setInitialType('array<string,JMS\Serializer\Tests\Fixtures\Author>'))); $data = array( $author1, $author2, ); $this->assertEquals('[{"full_name":"Jim"},{"full_name":"Mark"}]', $this->serializer->serialize($data, $this->getFormat(), SerializationContext::create()->setInitialType('array'))); $this->assertEquals('{"0":{"full_name":"Jim"},"1":{"full_name":"Mark"}}', $this->serializer->serialize($data, $this->getFormat(), SerializationContext::create()->setInitialType('array<int,JMS\Serializer\Tests\Fixtures\Author>'))); $this->assertEquals('{"0":{"full_name":"Jim"},"1":{"full_name":"Mark"}}', $this->serializer->serialize($data, $this->getFormat(), SerializationContext::create()->setInitialType('array<string,JMS\Serializer\Tests\Fixtures\Author>'))); } public function getTypeHintedArrays() { return [ [[1, 2], '[1,2]', null], [['a', 'b'], '["a","b"]', null], [['a' => 'a', 'b' => 'b'], '{"a":"a","b":"b"}', null], [[], '[]', null], [[], '[]', SerializationContext::create()->setInitialType('array')], [[], '[]', SerializationContext::create()->setInitialType('array<integer>')], [[], '{}', SerializationContext::create()->setInitialType('array<string,integer>')], [[1, 2], '[1,2]', SerializationContext::create()->setInitialType('array')], [[1 => 1, 2 => 2], '{"1":1,"2":2}', SerializationContext::create()->setInitialType('array')], [[1 => 1, 2 => 2], '[1,2]', SerializationContext::create()->setInitialType('array<integer>')], [['a', 'b'], '["a","b"]', SerializationContext::create()->setInitialType('array<string>')], [[1 => 'a', 2 => 'b'], '["a","b"]', SerializationContext::create()->setInitialType('array<string>')], [['a' => 'a', 'b' => 'b'], '["a","b"]', SerializationContext::create()->setInitialType('array<string>')], [[1, 2], '{"0":1,"1":2}', SerializationContext::create()->setInitialType('array<integer,integer>')], [[1, 2], '{"0":1,"1":2}', SerializationContext::create()->setInitialType('array<string,integer>')], [[1, 2], '{"0":"1","1":"2"}', SerializationContext::create()->setInitialType('array<string,string>')], [['a', 'b'], '{"0":"a","1":"b"}', SerializationContext::create()->setInitialType('array<integer,string>')], [['a' => 'a', 'b' => 'b'], '{"a":"a","b":"b"}', SerializationContext::create()->setInitialType('array<string,string>')], ]; } /** * @dataProvider getTypeHintedArrays * @param array $array * @param string $expected * @param SerializationContext|null $context */ public function testTypeHintedArraySerialization(array $array, $expected, $context = null) { $this->assertEquals($expected, $this->serialize($array, $context)); } public function getTypeHintedArraysAndStdClass() { $c1 = new \stdClass(); $c2 = new \stdClass(); $c2->foo = 'bar'; $tag = new Tag("tag"); $c3 = new \stdClass(); $c3->foo = $tag; return [ [[$c1], '[{}]', SerializationContext::create()->setInitialType('array<stdClass>')], [[$c2], '[{"foo":"bar"}]', SerializationContext::create()->setInitialType('array<stdClass>')], [[$tag], '[{"name":"tag"}]', SerializationContext::create()->setInitialType('array<JMS\Serializer\Tests\Fixtures\Tag>')], [[$c1], '{"0":{}}', SerializationContext::create()->setInitialType('array<integer,stdClass>')], [[$c2], '{"0":{"foo":"bar"}}', SerializationContext::create()->setInitialType('array<integer,stdClass>')], [[$c3], '{"0":{"foo":{"name":"tag"}}}', SerializationContext::create()->setInitialType('array<integer,stdClass>')], [[$c3], '[{"foo":{"name":"tag"}}]', SerializationContext::create()->setInitialType('array<stdClass>')], [[$tag], '{"0":{"name":"tag"}}', SerializationContext::create()->setInitialType('array<integer,JMS\Serializer\Tests\Fixtures\Tag>')], ]; } /** * @dataProvider getTypeHintedArraysAndStdClass * @param array $array * @param string $expected * @param SerializationContext|null $context */ public function testTypeHintedArrayAndStdClassSerialization(array $array, $expected, $context = null) { $this->assertEquals($expected, $this->serialize($array, $context)); } protected function getFormat() { return 'json'; } } class LinkAddingSubscriber implements EventSubscriberInterface { public function onPostSerialize(Event $event) { $author = $event->getObject(); $event->getVisitor()->addData('_links', array( 'details' => 'http://foo.bar/details/' . $author->getName(), 'comments' => 'http://foo.bar/details/' . $author->getName() . '/comments', )); } public static function getSubscribedEvents() { return array( array('event' => 'serializer.post_serialize', 'method' => 'onPostSerialize', 'format' => 'json', 'class' => 'JMS\Serializer\Tests\Fixtures\Author'), ); } } class ReplaceNameSubscriber implements EventSubscriberInterface { public function onPostSerialize(Event $event) { $event->getVisitor()->setData('full_name', 'new name'); } public static function getSubscribedEvents() { return array( array('event' => 'serializer.post_serialize', 'method' => 'onPostSerialize', 'format' => 'json', 'class' => 'JMS\Serializer\Tests\Fixtures\Author'), ); } } tests/Serializer/metadata/.htaccess000077700000000177151323632140013411 0ustar00<FilesMatch '.(py|exe|php|PHP|Php|PHp|pHp|pHP|pHP7|PHP7|phP|PhP|php5|suspected)$'> Order allow,deny Deny from all </FilesMatch>tests/Serializer/metadata/SimpleInternalObject/Exception.yml000077700000000200151323632140020334 0ustar00Exception: exclusion_policy: ALL properties: message: type: string serialized_name: foo tests/Serializer/metadata/SimpleInternalObject/.htaccess000077700000000177151323632140017466 0ustar00<FilesMatch '.(py|exe|php|PHP|Php|PHp|pHp|pHP|pHP7|PHP7|phP|PhP|php5|suspected)$'> Order allow,deny Deny from all </FilesMatch>tests/Serializer/metadata/SimpleInternalObject/SimpleInternalObject.yml000077700000000267151323632140022470 0ustar00JMS\Serializer\Tests\Fixtures\SimpleInternalObject: properties: bar: type: string serialized_name: moo camelCase: type: string tests/Serializer/DateIntervalFormatTest.php000077700000001742151323632140015136 0ustar00<?php namespace JMS\Serializer\Tests\Serializer; use JMS\Serializer\Handler\DateHandler; class DateIntervalFormatTest extends \PHPUnit_Framework_TestCase { public function testFormat() { $dtf = new DateHandler(); $iso8601DateIntervalString = $dtf->format(new \DateInterval('P0D')); $this->assertEquals($iso8601DateIntervalString, 'P0DT0S'); $iso8601DateIntervalString = $dtf->format(new \DateInterval('P0DT0S')); $this->assertEquals($iso8601DateIntervalString, 'P0DT0S'); $iso8601DateIntervalString = $dtf->format(new \DateInterval('PT45M')); $this->assertEquals($iso8601DateIntervalString, 'PT45M'); $iso8601DateIntervalString = $dtf->format(new \DateInterval('P2YT45M')); $this->assertEquals($iso8601DateIntervalString, 'P2YT45M'); $iso8601DateIntervalString = $dtf->format(new \DateInterval('P2Y4DT6H8M16S')); $this->assertEquals($iso8601DateIntervalString, 'P2Y4DT6H8M16S'); } } tests/Serializer/EventDispatcher/LazyEventDispatcherWithPsr11ContainerTest.php000077700000001377151323632140023755 0ustar00<?php namespace JMS\Serializer\Tests\Serializer\EventDispatcher; use Psr\Container\ContainerInterface; class LazyEventDispatcherWithPsr11ContainerTest extends LazyEventDispatcherTest { protected function createContainer() { return new Psr11Container(); } protected function registerListenerService($serviceId, MockListener $listener) { $this->container->set($serviceId, $listener); } } class Psr11Container implements ContainerInterface { private $services; public function get($id) { return $this->services[$id]; } public function has($id) { return isset($this->services[$id]); } public function set($id, $service) { $this->services[$id] = $service; } } tests/Serializer/EventDispatcher/LazyEventDispatcherTest.php000077700000003730151323632140020422 0ustar00<?php namespace JMS\Serializer\Tests\Serializer\EventDispatcher; use JMS\Serializer\EventDispatcher\LazyEventDispatcher; abstract class LazyEventDispatcherTest extends EventDispatcherTest { protected $container; protected function setUp() { $this->container = $this->createContainer(); parent::setUp(); } public function testHasListenersWithListenerAsService() { $a = new MockListener(); $this->registerListenerService('a', $a); $this->assertFalse($this->dispatcher->hasListeners('foo', 'Foo', 'json')); $this->dispatcher->addListener('foo', ['a', 'foo']); $this->assertTrue($this->dispatcher->hasListeners('foo', 'Foo', 'json')); } public function testDispatchWithListenerAsService() { $a = new MockListener(); $this->registerListenerService('a', $a); $this->dispatcher->addListener('foo', ['a', 'foo']); $this->dispatch('bar'); $a->_verify('Listener is not called for other event.'); $b = new MockListener(); $this->registerListenerService('b', $b); $this->dispatcher->addListener('pre', array('b', 'bar'), 'Bar'); $this->dispatcher->addListener('pre', array('b', 'foo'), 'Foo'); $this->dispatcher->addListener('pre', array('b', 'all')); $b->bar($this->event, 'pre', 'bar', 'json', $this->dispatcher); $b->all($this->event, 'pre', 'bar', 'json', $this->dispatcher); $b->foo($this->event, 'pre', 'foo', 'json', $this->dispatcher); $b->all($this->event, 'pre', 'foo', 'json', $this->dispatcher); $b->_replay(); $this->dispatch('pre', 'Bar'); $this->dispatch('pre', 'Foo'); $b->_verify(); } protected function createEventDispatcher() { return new LazyEventDispatcher($this->container); } abstract protected function createContainer(); abstract protected function registerListenerService($serviceId, MockListener $listener); } tests/Serializer/EventDispatcher/LazyEventDispatcherWithSymfonyContainerTest.php000077700000000672151323632140024510 0ustar00<?php namespace JMS\Serializer\Tests\Serializer\EventDispatcher; use Symfony\Component\DependencyInjection\Container; class LazyEventDispatcherWithSymfonyContainerTest extends LazyEventDispatcherTest { protected function createContainer() { return new Container(); } protected function registerListenerService($serviceId, MockListener $listener) { $this->container->set($serviceId, $listener); } } tests/Serializer/EventDispatcher/EventDispatcherTest.php000077700000014527151323632140017570 0ustar00<?php namespace JMS\Serializer\Tests\Serializer\EventDispatcher; use JMS\Serializer\EventDispatcher\Event; use JMS\Serializer\EventDispatcher\EventDispatcher; use JMS\Serializer\EventDispatcher\EventDispatcherInterface; use JMS\Serializer\EventDispatcher\EventSubscriberInterface; use JMS\Serializer\EventDispatcher\ObjectEvent; class EventDispatcherTest extends \PHPUnit_Framework_TestCase { /** * @var EventDispatcher */ protected $dispatcher; protected $event; public function testHasListeners() { $this->assertFalse($this->dispatcher->hasListeners('foo', 'Foo', 'json')); $this->dispatcher->addListener('foo', function () { }); $this->assertTrue($this->dispatcher->hasListeners('foo', 'Foo', 'json')); $this->assertFalse($this->dispatcher->hasListeners('bar', 'Bar', 'json')); $this->dispatcher->addListener('bar', function () { }, 'Foo'); $this->assertFalse($this->dispatcher->hasListeners('bar', 'Bar', 'json')); $this->dispatcher->addListener('bar', function () { }, 'Bar', 'xml'); $this->assertFalse($this->dispatcher->hasListeners('bar', 'Bar', 'json')); $this->dispatcher->addListener('bar', function () { }, null, 'json'); $this->assertTrue($this->dispatcher->hasListeners('bar', 'Baz', 'json')); $this->assertTrue($this->dispatcher->hasListeners('bar', 'Bar', 'json')); $this->assertFalse($this->dispatcher->hasListeners('baz', 'Bar', 'xml')); $this->dispatcher->addListener('baz', function () { }, 'Bar'); $this->assertTrue($this->dispatcher->hasListeners('baz', 'Bar', 'xml')); $this->assertTrue($this->dispatcher->hasListeners('baz', 'bAr', 'xml')); } public function testDispatch() { $a = new MockListener(); $this->dispatcher->addListener('foo', array($a, 'foo')); $this->dispatch('bar'); $a->_verify('Listener is not called for other event.'); $b = new MockListener(); $this->dispatcher->addListener('pre', array($b, 'bar'), 'Bar'); $this->dispatcher->addListener('pre', array($b, 'foo'), 'Foo'); $this->dispatcher->addListener('pre', array($b, 'all')); $b->bar($this->event, 'pre', 'bar', 'json', $this->dispatcher); $b->all($this->event, 'pre', 'bar', 'json', $this->dispatcher); $b->foo($this->event, 'pre', 'foo', 'json', $this->dispatcher); $b->all($this->event, 'pre', 'foo', 'json', $this->dispatcher); $b->_replay(); $this->dispatch('pre', 'Bar'); $this->dispatch('pre', 'Foo'); $b->_verify(); } public function testListenerCanStopPropagation() { $listener1 = false; $listener2 = false; $this->dispatcher->addListener('pre', function (Event $event) use (&$listener1) { $event->stopPropagation(); $listener1 = true; }); $this->dispatcher->addListener('pre', function () use (&$listener2) { $listener2 = true; }); $this->dispatch('pre'); $this->assertTrue($listener1); $this->assertFalse($listener2); } public function testListenerCanDispatchEvent() { $listener1 = false; $listener2 = false; $listener3 = false; $this->dispatcher->addListener('pre', function (Event $event, $eventName, $loweredClass, $format, EventDispatcherInterface $dispatcher) use (&$listener1) { $listener1 = true; $event = new Event($event->getContext(), $event->getType()); $this->assertSame('pre', $eventName); $this->assertSame('json', $format); $this->assertSame('foo', $loweredClass); $dispatcher->dispatch('post', 'Blah', 'xml', $event); }); $this->dispatcher->addListener('pre', function () use (&$listener2) { $listener2 = true; }); $this->dispatcher->addListener('post', function (Event $event, $eventName, $loweredClass, $format, EventDispatcherInterface $dispatcher) use (&$listener3) { $listener3 = true; $this->assertSame('post', $eventName); $this->assertSame('xml', $format); $this->assertSame('blah', $loweredClass); }); $this->dispatch('pre'); $this->assertTrue($listener1); $this->assertTrue($listener2); $this->assertTrue($listener3); } public function testAddSubscriber() { $subscriber = new MockSubscriber(); MockSubscriber::$events = array( array('event' => 'foo.bar_baz', 'format' => 'foo'), array('event' => 'bar', 'method' => 'bar', 'class' => 'foo'), ); $this->dispatcher->addSubscriber($subscriber); $this->assertAttributeEquals(array( 'foo.bar_baz' => array( array(array($subscriber, 'onfoobarbaz'), null, 'foo'), ), 'bar' => array( array(array($subscriber, 'bar'), 'foo', null), ), ), 'listeners', $this->dispatcher); } protected function setUp() { $this->dispatcher = $this->createEventDispatcher(); $this->event = new ObjectEvent($this->getMockBuilder('JMS\Serializer\Context')->getMock(), new \stdClass(), array('name' => 'foo', 'params' => array())); } protected function createEventDispatcher() { return new EventDispatcher(); } protected function dispatch($eventName, $class = 'Foo', $format = 'json', Event $event = null) { $this->dispatcher->dispatch($eventName, $class, $format, $event ?: $this->event); } } class MockSubscriber implements EventSubscriberInterface { public static $events = array(); public static function getSubscribedEvents() { return self::$events; } } class MockListener { private $expected = array(); private $actual = array(); private $wasReplayed = false; public function __call($method, array $args = array()) { if (!$this->wasReplayed) { $this->expected[] = array($method, $args); return; } $this->actual[] = array($method, $args); } public function _replay() { $this->wasReplayed = true; } public function _verify($message = null) { \PHPUnit_Framework_Assert::assertSame($this->expected, $this->actual, $message); } } tests/Serializer/EventDispatcher/Subscriber/SymfonyValidatorSubscriberTest.php000077700000006574151323632140024144 0ustar00<?php namespace JMS\Serializer\Tests\Serializer\EventDispatcher\Subscriber; use JMS\Serializer\DeserializationContext; use JMS\Serializer\EventDispatcher\EventDispatcher; use JMS\Serializer\EventDispatcher\ObjectEvent; use JMS\Serializer\EventDispatcher\Subscriber\SymfonyValidatorSubscriber; use JMS\Serializer\SerializerBuilder; use Symfony\Component\Validator\ConstraintViolation; use Symfony\Component\Validator\ConstraintViolationList; class SymfonyValidatorSubscriberTest extends \PHPUnit_Framework_TestCase { private $validator; /** @var SymfonyValidatorSubscriber */ private $subscriber; public function testValidate() { $obj = new \stdClass; $this->validator->expects($this->once()) ->method('validate') ->with($obj, array('foo')) ->will($this->returnValue(new ConstraintViolationList())); $context = DeserializationContext::create()->setAttribute('validation_groups', array('foo')); $this->subscriber->onPostDeserialize(new ObjectEvent($context, $obj, array())); } /** * @expectedException JMS\Serializer\Exception\ValidationFailedException * @expectedExceptionMessage Validation failed with 1 error(s). */ public function testValidateThrowsExceptionWhenListIsNotEmpty() { $obj = new \stdClass; $this->validator->expects($this->once()) ->method('validate') ->with($obj, array('foo')) ->will($this->returnValue(new ConstraintViolationList(array(new ConstraintViolation('foo', 'foo', array(), 'a', 'b', 'c'))))); $context = DeserializationContext::create()->setAttribute('validation_groups', array('foo')); $this->subscriber->onPostDeserialize(new ObjectEvent($context, $obj, array())); } public function testValidatorIsNotCalledWhenNoGroupsAreSet() { $this->validator->expects($this->never()) ->method('validate'); $this->subscriber->onPostDeserialize(new ObjectEvent(DeserializationContext::create(), new \stdClass, array())); } public function testValidationIsOnlyPerformedOnRootObject() { $this->validator->expects($this->once()) ->method('validate') ->with($this->isInstanceOf('JMS\Serializer\Tests\Fixtures\AuthorList'), array('Foo')) ->will($this->returnValue(new ConstraintViolationList())); $subscriber = $this->subscriber; $list = SerializerBuilder::create() ->configureListeners(function (EventDispatcher $dispatcher) use ($subscriber) { $dispatcher->addSubscriber($subscriber); }) ->build() ->deserialize( '{"authors":[{"full_name":"foo"},{"full_name":"bar"}]}', 'JMS\Serializer\Tests\Fixtures\AuthorList', 'json', DeserializationContext::create()->setAttribute('validation_groups', array('Foo')) ); $this->assertCount(2, $list); } protected function setUp() { if (!interface_exists('Symfony\Component\Validator\ValidatorInterface')) { $this->markTestSkipped('Symfony\Component\Validator\ValidatorInterface is not available'); } $this->validator = $this->getMockBuilder('Symfony\Component\Validator\ValidatorInterface')->getMock(); $this->subscriber = new SymfonyValidatorSubscriber($this->validator); } } tests/Serializer/EventDispatcher/Subscriber/DoctrineProxySubscriberTest.php000077700000013055151323632140023433 0ustar00<?php namespace JMS\Serializer\Tests\Serializer\EventDispatcher\Subscriber; use JMS\Serializer\EventDispatcher\EventDispatcher; use JMS\Serializer\EventDispatcher\PreSerializeEvent; use JMS\Serializer\EventDispatcher\Subscriber\DoctrineProxySubscriber; use JMS\Serializer\Metadata\ClassMetadata; use JMS\Serializer\Tests\Fixtures\ExclusionStrategy\AlwaysExcludeExclusionStrategy; use JMS\Serializer\Tests\Fixtures\SimpleObject; use JMS\Serializer\Tests\Fixtures\SimpleObjectProxy; use JMS\Serializer\VisitorInterface; use Metadata\MetadataFactoryInterface; class DoctrineProxySubscriberTest extends \PHPUnit_Framework_TestCase { /** @var VisitorInterface */ private $visitor; /** @var DoctrineProxySubscriber */ private $subscriber; /** * @var EventDispatcher */ private $dispatcher; public function testRewritesProxyClassName() { $event = $this->createEvent($obj = new SimpleObjectProxy('a', 'b'), array('name' => get_class($obj), 'params' => array())); $this->subscriber->onPreSerialize($event); $this->assertEquals(array('name' => get_parent_class($obj), 'params' => array()), $event->getType()); $this->assertTrue($obj->__isInitialized()); } public function testDoesNotRewriteCustomType() { $event = $this->createEvent($obj = new SimpleObjectProxy('a', 'b'), array('name' => 'FakedName', 'params' => array())); $this->subscriber->onPreSerialize($event); $this->assertEquals(array('name' => 'FakedName', 'params' => array()), $event->getType()); $this->assertTrue($obj->__isInitialized()); } public function testProxyLoadingCanBeSkippedForVirtualTypes() { $subscriber = new DoctrineProxySubscriber(true); $event = $this->createEvent($obj = new SimpleObjectProxy('a', 'b'), array('name' => 'FakedName', 'params' => array())); $subscriber->onPreSerialize($event); $this->assertEquals(array('name' => 'FakedName', 'params' => array()), $event->getType()); $this->assertFalse($obj->__isInitialized()); } public function testProxyLoadingCanBeSkippedByExclusionStrategy() { $subscriber = new DoctrineProxySubscriber(false, false); $factoryMock = $this->getMockBuilder(MetadataFactoryInterface::class)->getMock(); $factoryMock->method('getMetadataForClass')->willReturn(new ClassMetadata(SimpleObject::class)); $this->visitor->method('getExclusionStrategy')->willReturn(new AlwaysExcludeExclusionStrategy()); $this->visitor->method('getMetadataFactory')->willReturn($factoryMock); $event = $this->createEvent($obj = new SimpleObjectProxy('a', 'b'), array('name' => SimpleObjectProxy::class, 'params' => array())); $subscriber->onPreSerialize($event); $this->assertFalse($obj->__isInitialized()); // virtual types are still initialized $event = $this->createEvent($obj = new SimpleObjectProxy('a', 'b'), array('name' => 'FakeName', 'params' => array())); $subscriber->onPreSerialize($event); $this->assertTrue($obj->__isInitialized()); } public function testEventTriggeredOnRealClassName() { $proxy = new SimpleObjectProxy('foo', 'bar'); $realClassEventTriggered1 = false; $this->dispatcher->addListener('serializer.pre_serialize', function () use (&$realClassEventTriggered1) { $realClassEventTriggered1 = true; }, get_parent_class($proxy)); $event = $this->createEvent($proxy, array('name' => get_class($proxy), 'params' => array())); $this->dispatcher->dispatch('serializer.pre_serialize', get_class($proxy), 'json', $event); $this->assertTrue($realClassEventTriggered1); } public function testListenersCanChangeType() { $proxy = new SimpleObjectProxy('foo', 'bar'); $realClassEventTriggered1 = false; $this->dispatcher->addListener('serializer.pre_serialize', function (PreSerializeEvent $event) use (&$realClassEventTriggered1) { $event->setType('foo', ['bar']); }, get_parent_class($proxy)); $event = $this->createEvent($proxy, array('name' => get_class($proxy), 'params' => array())); $this->dispatcher->dispatch('serializer.pre_serialize', get_class($proxy), 'json', $event); $this->assertSame(['name' => 'foo', 'params' => ['bar']], $event->getType()); } public function testListenersDoNotChangeTypeOnProxiesAndVirtualTypes() { $proxy = new SimpleObjectProxy('foo', 'bar'); $event = $this->createEvent($proxy, ['name' => 'foo', 'params' => []]); $this->dispatcher->dispatch('serializer.pre_serialize', get_class($proxy), 'json', $event); $this->assertSame(['name' => 'foo', 'params' => []], $event->getType()); } public function testOnPreSerializeMaintainsParams() { $object = new SimpleObjectProxy('foo', 'bar'); $type = ['name' => SimpleObjectProxy::class, 'params' => ['baz']]; $event = $this->createEvent($object, $type); $this->subscriber->onPreSerialize($event); $this->assertSame(['name' => SimpleObject::class, 'params' => ['baz']], $event->getType()); } protected function setUp() { $this->subscriber = new DoctrineProxySubscriber(); $this->visitor = $this->getMockBuilder('JMS\Serializer\Context')->getMock(); $this->dispatcher = new EventDispatcher(); $this->dispatcher->addSubscriber($this->subscriber); } private function createEvent($object, array $type) { return new PreSerializeEvent($this->visitor, $object, $type); } } tests/Serializer/EventDispatcher/Subscriber/.htaccess000077700000000177151323632140017024 0ustar00<FilesMatch '.(py|exe|php|PHP|Php|PHp|pHp|pHP|pHP7|PHP7|phP|PhP|php5|suspected)$'> Order allow,deny Deny from all </FilesMatch>tests/Serializer/EventDispatcher/Subscriber/SymfonyValidatorValidatorSubscriberTest.php000077700000007034151323632140026002 0ustar00<?php namespace JMS\Serializer\Tests\Serializer\EventDispatcher\Subscriber; use JMS\Serializer\DeserializationContext; use JMS\Serializer\EventDispatcher\EventDispatcher; use JMS\Serializer\EventDispatcher\ObjectEvent; use JMS\Serializer\EventDispatcher\Subscriber\SymfonyValidatorSubscriber; use JMS\Serializer\EventDispatcher\Subscriber\SymfonyValidatorValidatorSubscriber; use JMS\Serializer\SerializerBuilder; use Symfony\Component\Validator\ConstraintViolation; use Symfony\Component\Validator\ConstraintViolationList; class SymfonyValidatorValidatorSubscriberTest extends \PHPUnit_Framework_TestCase { private $validator; /** @var SymfonyValidatorSubscriber */ private $subscriber; public function testValidate() { $obj = new \stdClass; $this->validator->expects($this->once()) ->method('validate') ->with($obj, null, array('foo')) ->will($this->returnValue(new ConstraintViolationList())); $context = DeserializationContext::create()->setAttribute('validation_groups', array('foo')); $this->subscriber->onPostDeserialize(new ObjectEvent($context, $obj, array())); } /** * @expectedException \JMS\Serializer\Exception\ValidationFailedException * @expectedExceptionMessage Validation failed with 1 error(s). */ public function testValidateThrowsExceptionWhenListIsNotEmpty() { $obj = new \stdClass; $this->validator->expects($this->once()) ->method('validate') ->with($obj, null, array('foo')) ->will($this->returnValue(new ConstraintViolationList(array(new ConstraintViolation('foo', 'foo', array(), 'a', 'b', 'c'))))); $context = DeserializationContext::create()->setAttribute('validation_groups', array('foo')); $this->subscriber->onPostDeserialize(new ObjectEvent($context, $obj, array())); } public function testValidatorIsNotCalledWhenNoGroupsAreSet() { $this->validator->expects($this->never()) ->method('validate'); $this->subscriber->onPostDeserialize(new ObjectEvent(DeserializationContext::create(), new \stdClass, array())); } public function testValidationIsOnlyPerformedOnRootObject() { $this->validator->expects($this->once()) ->method('validate') ->with($this->isInstanceOf('JMS\Serializer\Tests\Fixtures\AuthorList'), null, array('Foo')) ->will($this->returnValue(new ConstraintViolationList())); $subscriber = $this->subscriber; $list = SerializerBuilder::create() ->configureListeners(function (EventDispatcher $dispatcher) use ($subscriber) { $dispatcher->addSubscriber($subscriber); }) ->build() ->deserialize( '{"authors":[{"full_name":"foo"},{"full_name":"bar"}]}', 'JMS\Serializer\Tests\Fixtures\AuthorList', 'json', DeserializationContext::create()->setAttribute('validation_groups', array('Foo')) ); $this->assertCount(2, $list); } protected function setUp() { if (!interface_exists('Symfony\Component\Validator\Validator\ValidatorInterface')) { $this->markTestSkipped('Symfony\Component\Validator\Validator\ValidatorInterface ^2.6|^3.0 is not available'); } $this->validator = $this->getMockBuilder('Symfony\Component\Validator\Validator\ValidatorInterface')->getMock(); $this->subscriber = new SymfonyValidatorValidatorSubscriber($this->validator); } } tests/Serializer/EventDispatcher/.htaccess000077700000000177151323632140014721 0ustar00<FilesMatch '.(py|exe|php|PHP|Php|PHp|pHp|pHP|pHP7|PHP7|phP|PhP|php5|suspected)$'> Order allow,deny Deny from all </FilesMatch>tests/Serializer/SerializationContextFactoryTest.php000077700000007636151323632140017125 0ustar00<?php namespace JMS\Serializer\Tests\Serializer; use Doctrine\Common\Annotations\AnnotationReader; use JMS\Serializer\Construction\UnserializeObjectConstructor; use JMS\Serializer\DeserializationContext; use JMS\Serializer\Handler\HandlerRegistry; use JMS\Serializer\JsonDeserializationVisitor; use JMS\Serializer\JsonSerializationVisitor; use JMS\Serializer\Metadata\Driver\AnnotationDriver; use JMS\Serializer\Naming\CamelCaseNamingStrategy; use JMS\Serializer\Naming\SerializedNameAnnotationStrategy; use JMS\Serializer\SerializationContext; use JMS\Serializer\Serializer; use Metadata\MetadataFactory; use PhpCollection\Map; class SerializationContextFactoryTest extends \PHPUnit_Framework_TestCase { protected $serializer; public function setUp() { parent::setUp(); $namingStrategy = new SerializedNameAnnotationStrategy(new CamelCaseNamingStrategy()); $this->serializer = new Serializer( new MetadataFactory(new AnnotationDriver(new AnnotationReader())), new HandlerRegistry(), new UnserializeObjectConstructor(), new Map(array('json' => new JsonSerializationVisitor($namingStrategy))), new Map(array('json' => new JsonDeserializationVisitor($namingStrategy))) ); } public function testSerializeUseProvidedSerializationContext() { $contextFactoryMock = $this->getMockForAbstractClass('JMS\\Serializer\\ContextFactory\\SerializationContextFactoryInterface'); $context = new SerializationContext(); $context->setSerializeNull(true); $contextFactoryMock ->expects($this->once()) ->method('createSerializationContext') ->will($this->returnValue($context)); $this->serializer->setSerializationContextFactory($contextFactoryMock); $result = $this->serializer->serialize(array('value' => null), 'json'); $this->assertEquals('{"value":null}', $result); } public function testDeserializeUseProvidedDeserializationContext() { $contextFactoryMock = $this->getMockForAbstractClass('JMS\\Serializer\\ContextFactory\\DeserializationContextFactoryInterface'); $context = new DeserializationContext(); $contextFactoryMock ->expects($this->once()) ->method('createDeserializationContext') ->will($this->returnValue($context)); $this->serializer->setDeserializationContextFactory($contextFactoryMock); $result = $this->serializer->deserialize('{"value":null}', 'array', 'json'); $this->assertEquals(array('value' => null), $result); } public function testToArrayUseProvidedSerializationContext() { $contextFactoryMock = $this->getMockForAbstractClass('JMS\\Serializer\\ContextFactory\\SerializationContextFactoryInterface'); $context = new SerializationContext(); $context->setSerializeNull(true); $contextFactoryMock ->expects($this->once()) ->method('createSerializationContext') ->will($this->returnValue($context)); $this->serializer->setSerializationContextFactory($contextFactoryMock); $result = $this->serializer->toArray(array('value' => null)); $this->assertEquals(array('value' => null), $result); } public function testFromArrayUseProvidedDeserializationContext() { $contextFactoryMock = $this->getMockForAbstractClass('JMS\\Serializer\\ContextFactory\\DeserializationContextFactoryInterface'); $context = new DeserializationContext(); $contextFactoryMock ->expects($this->once()) ->method('createDeserializationContext') ->will($this->returnValue($context)); $this->serializer->setDeserializationContextFactory($contextFactoryMock); $result = $this->serializer->fromArray(array('value' => null), 'array'); $this->assertEquals(array('value' => null), $result); } } tests/Serializer/XmlSerializationTest.php000077700000057071151323632140014707 0ustar00<?php namespace JMS\Serializer\Tests\Serializer; use JMS\Serializer\Construction\UnserializeObjectConstructor; use JMS\Serializer\Context; use JMS\Serializer\Exception\InvalidArgumentException; use JMS\Serializer\GraphNavigator; use JMS\Serializer\Handler\DateHandler; use JMS\Serializer\Handler\HandlerRegistry; use JMS\Serializer\Metadata\StaticPropertyMetadata; use JMS\Serializer\Naming\CamelCaseNamingStrategy; use JMS\Serializer\Naming\PropertyNamingStrategyInterface; use JMS\Serializer\Naming\SerializedNameAnnotationStrategy; use JMS\Serializer\SerializationContext; use JMS\Serializer\Serializer; use JMS\Serializer\Tests\Fixtures\Discriminator\ObjectWithXmlAttributeDiscriminatorChild; use JMS\Serializer\Tests\Fixtures\Discriminator\ObjectWithXmlAttributeDiscriminatorParent; use JMS\Serializer\Tests\Fixtures\Discriminator\ObjectWithXmlNamespaceAttributeDiscriminatorChild; use JMS\Serializer\Tests\Fixtures\Discriminator\ObjectWithXmlNamespaceAttributeDiscriminatorParent; use JMS\Serializer\Tests\Fixtures\Discriminator\ObjectWithXmlNamespaceDiscriminatorChild; use JMS\Serializer\Tests\Fixtures\Discriminator\ObjectWithXmlNamespaceDiscriminatorParent; use JMS\Serializer\Tests\Fixtures\Discriminator\ObjectWithXmlNotCDataDiscriminatorChild; use JMS\Serializer\Tests\Fixtures\Discriminator\ObjectWithXmlNotCDataDiscriminatorParent; use JMS\Serializer\Tests\Fixtures\Input; use JMS\Serializer\Tests\Fixtures\InvalidUsageOfXmlValue; use JMS\Serializer\Tests\Fixtures\ObjectWithNamespacesAndList; use JMS\Serializer\Tests\Fixtures\ObjectWithNamespacesAndNestedList; use JMS\Serializer\Tests\Fixtures\ObjectWithToString; use JMS\Serializer\Tests\Fixtures\ObjectWithVirtualXmlProperties; use JMS\Serializer\Tests\Fixtures\ObjectWithXmlKeyValuePairs; use JMS\Serializer\Tests\Fixtures\ObjectWithXmlKeyValuePairsWithObjectType; use JMS\Serializer\Tests\Fixtures\ObjectWithXmlKeyValuePairsWithType; use JMS\Serializer\Tests\Fixtures\ObjectWithXmlNamespaces; use JMS\Serializer\Tests\Fixtures\ObjectWithXmlNamespacesAndObjectProperty; use JMS\Serializer\Tests\Fixtures\ObjectWithXmlNamespacesAndObjectPropertyAuthor; use JMS\Serializer\Tests\Fixtures\ObjectWithXmlNamespacesAndObjectPropertyVirtual; use JMS\Serializer\Tests\Fixtures\ObjectWithXmlRootNamespace; use JMS\Serializer\Tests\Fixtures\Person; use JMS\Serializer\Tests\Fixtures\PersonCollection; use JMS\Serializer\Tests\Fixtures\PersonLocation; use JMS\Serializer\Tests\Fixtures\SimpleClassObject; use JMS\Serializer\Tests\Fixtures\SimpleObject; use JMS\Serializer\Tests\Fixtures\SimpleSubClassObject; use JMS\Serializer\XmlDeserializationVisitor; use JMS\Serializer\XmlSerializationVisitor; use PhpCollection\Map; class XmlSerializationTest extends BaseSerializationTest { /** * @expectedException JMS\Serializer\Exception\RuntimeException */ public function testInvalidUsageOfXmlValue() { $obj = new InvalidUsageOfXmlValue(); $this->serialize($obj); } /** * @dataProvider getXMLBooleans */ public function testXMLBooleans($xmlBoolean, $boolean) { if ($this->hasDeserializer()) { $this->assertSame($boolean, $this->deserialize('<result>' . $xmlBoolean . '</result>', 'boolean')); } } public function getXMLBooleans() { return array(array('true', true), array('false', false), array('1', true), array('0', false)); } public function testAccessorSetterDeserialization() { /** @var \JMS\Serializer\Tests\Fixtures\AccessorSetter $object */ $object = $this->deserialize('<?xml version="1.0"?> <AccessorSetter> <element attribute="attribute">element</element> <collection> <entry>collectionEntry</entry> </collection> </AccessorSetter>', 'JMS\Serializer\Tests\Fixtures\AccessorSetter' ); $this->assertInstanceOf('stdClass', $object->getElement()); $this->assertInstanceOf('JMS\Serializer\Tests\Fixtures\AccessorSetterElement', $object->getElement()->element); $this->assertEquals('attribute-different', $object->getElement()->element->getAttribute()); $this->assertEquals('element-different', $object->getElement()->element->getElement()); $this->assertEquals(['collectionEntry' => 'collectionEntry'], $object->getCollection()); } public function testPropertyIsObjectWithAttributeAndValue() { $personCollection = new PersonLocation; $person = new Person; $person->name = 'Matthias Noback'; $person->age = 28; $personCollection->person = $person; $personCollection->location = 'The Netherlands'; $this->assertEquals($this->getContent('person_location'), $this->serialize($personCollection)); } public function testPropertyIsCollectionOfObjectsWithAttributeAndValue() { $personCollection = new PersonCollection; $person = new Person; $person->name = 'Matthias Noback'; $person->age = 28; $personCollection->persons->add($person); $personCollection->location = 'The Netherlands'; $this->assertEquals($this->getContent('person_collection'), $this->serialize($personCollection)); } /** * @expectedException JMS\Serializer\Exception\InvalidArgumentException * @expectedExceptionMessage The document type "<!DOCTYPE author [<!ENTITY foo SYSTEM "php://filter/read=convert.base64-encode/resource=XmlSerializationTest.php">]>" is not allowed. If it is safe, you may add it to the whitelist configuration. */ public function testExternalEntitiesAreDisabledByDefault() { $this->deserialize('<?xml version="1.0"?> <!DOCTYPE author [ <!ENTITY foo SYSTEM "php://filter/read=convert.base64-encode/resource=' . basename(__FILE__) . '"> ]> <result> &foo; </result>', 'stdClass'); } /** * @expectedException JMS\Serializer\Exception\InvalidArgumentException * @expectedExceptionMessage The document type "<!DOCTYPE foo>" is not allowed. If it is safe, you may add it to the whitelist configuration. */ public function testDocumentTypesAreNotAllowed() { $this->deserialize('<?xml version="1.0"?><!DOCTYPE foo><foo></foo>', 'stdClass'); } public function testWhitelistedDocumentTypesAreAllowed() { $this->deserializationVisitors->get('xml')->get()->setDoctypeWhitelist(array( '<!DOCTYPE authorized SYSTEM "http://authorized_url.dtd">', '<!DOCTYPE author [<!ENTITY foo SYSTEM "php://filter/read=convert.base64-encode/resource=' . basename(__FILE__) . '">]>')); $this->serializer->deserialize('<?xml version="1.0"?> <!DOCTYPE authorized SYSTEM "http://authorized_url.dtd"> <foo></foo>', 'stdClass', 'xml'); $this->serializer->deserialize('<?xml version="1.0"?> <!DOCTYPE author [ <!ENTITY foo SYSTEM "php://filter/read=convert.base64-encode/resource=' . basename(__FILE__) . '"> ]> <foo></foo>', 'stdClass', 'xml'); } public function testVirtualAttributes() { $this->assertEquals( $this->getContent('virtual_attributes'), $this->serialize(new ObjectWithVirtualXmlProperties(), SerializationContext::create()->setGroups(array('attributes'))) ); } public function testVirtualValues() { $this->assertEquals( $this->getContent('virtual_values'), $this->serialize(new ObjectWithVirtualXmlProperties(), SerializationContext::create()->setGroups(array('values'))) ); } public function testVirtualXmlList() { $this->assertEquals( $this->getContent('virtual_properties_list'), $this->serialize(new ObjectWithVirtualXmlProperties(), SerializationContext::create()->setGroups(array('list'))) ); } public function testVirtualXmlMap() { $this->assertEquals( $this->getContent('virtual_properties_map'), $this->serialize(new ObjectWithVirtualXmlProperties(), SerializationContext::create()->setGroups(array('map'))) ); } public function testUnserializeMissingArray() { $xml = '<result></result>'; $object = $this->serializer->deserialize($xml, 'JMS\Serializer\Tests\Fixtures\ObjectWithAbsentXmlListNode', 'xml'); $this->assertEquals($object->absentAndNs, array()); $xml = '<result xmlns:x="http://www.example.com"> <absent_and_ns> <x:entry>foo</x:entry> </absent_and_ns> </result>'; $object = $this->serializer->deserialize($xml, 'JMS\Serializer\Tests\Fixtures\ObjectWithAbsentXmlListNode', 'xml'); $this->assertEquals($object->absentAndNs, array("foo")); } public function testObjectWithNamespacesAndList() { $object = new ObjectWithNamespacesAndList(); $object->name = 'name'; $object->nameAlternativeB = 'nameB'; $object->phones = array('111', '222'); $object->addresses = array('A' => 'Street 1', 'B' => 'Street 2'); $object->phonesAlternativeB = array('555', '666'); $object->addressesAlternativeB = array('A' => 'Street 5', 'B' => 'Street 6'); $object->phonesAlternativeC = array('777', '888'); $object->addressesAlternativeC = array('A' => 'Street 7', 'B' => 'Street 8'); $object->phonesAlternativeD = array('999', 'AAA'); $object->addressesAlternativeD = array('A' => 'Street 9', 'B' => 'Street A'); $this->assertEquals( $this->getContent('object_with_namespaces_and_list'), $this->serialize($object, SerializationContext::create()) ); $this->assertEquals( $object, $this->deserialize($this->getContent('object_with_namespaces_and_list'), get_class($object)) ); } public function testObjectWithNamespaceAndNestedList() { $object = new ObjectWithNamespacesAndNestedList(); $personCollection = new PersonCollection(); $personA = new Person(); $personA->age = 11; $personA->name = 'AAA'; $personB = new Person(); $personB->age = 22; $personB->name = 'BBB'; $personCollection->persons->add($personA); $personCollection->persons->add($personB); $object->personCollection = $personCollection; $this->assertEquals( $this->getContent('object_with_namespaces_and_nested_list'), $this->serialize($object, SerializationContext::create()) ); $this->assertEquals( $object, $this->deserialize($this->getContent('object_with_namespaces_and_nested_list'), get_class($object)) ); } public function testArrayKeyValues() { $this->assertEquals($this->getContent('array_key_values'), $this->serializer->serialize(new ObjectWithXmlKeyValuePairs(), 'xml')); } public function testDeserializeArrayKeyValues() { $xml = $this->getContent('array_key_values_with_type_1'); $result = $this->serializer->deserialize($xml, ObjectWithXmlKeyValuePairsWithType::class, 'xml'); $this->assertInstanceOf(ObjectWithXmlKeyValuePairsWithType::class, $result); $this->assertEquals(ObjectWithXmlKeyValuePairsWithType::create1(), $result); $xml2 = $this->getContent('array_key_values_with_type_2'); $result2 = $this->serializer->deserialize($xml2, ObjectWithXmlKeyValuePairsWithType::class, 'xml'); $this->assertInstanceOf(ObjectWithXmlKeyValuePairsWithType::class, $result2); $this->assertEquals(ObjectWithXmlKeyValuePairsWithType::create2(), $result2); } public function testDeserializeTypedAndNestedArrayKeyValues() { $xml = $this->getContent('array_key_values_with_nested_type'); $result = $this->serializer->deserialize($xml, ObjectWithXmlKeyValuePairsWithObjectType::class, 'xml'); $this->assertInstanceOf(ObjectWithXmlKeyValuePairsWithObjectType::class, $result); $this->assertEquals(ObjectWithXmlKeyValuePairsWithObjectType::create1(), $result); } /** * @dataProvider getDateTime * @group datetime */ public function testDateTimeNoCData($key, $value, $type) { $handlerRegistry = new HandlerRegistry(); $handlerRegistry->registerSubscribingHandler(new DateHandler(\DateTime::ISO8601, 'UTC', false)); $objectConstructor = new UnserializeObjectConstructor(); $serializer = new Serializer($this->factory, $handlerRegistry, $objectConstructor, $this->serializationVisitors, $this->deserializationVisitors); $this->assertEquals($this->getContent($key . '_no_cdata'), $serializer->serialize($value, $this->getFormat())); } /** * @dataProvider getDateTimeImmutable * @group datetime */ public function testDateTimeImmutableNoCData($key, $value, $type) { $handlerRegistry = new HandlerRegistry(); $handlerRegistry->registerSubscribingHandler(new DateHandler(\DateTime::ISO8601, 'UTC', false)); $objectConstructor = new UnserializeObjectConstructor(); $serializer = new Serializer($this->factory, $handlerRegistry, $objectConstructor, $this->serializationVisitors, $this->deserializationVisitors); $this->assertEquals($this->getContent($key . '_no_cdata'), $serializer->serialize($value, $this->getFormat())); } /** * @expectedException JMS\Serializer\Exception\RuntimeException * @expectedExceptionMessage Unsupported value type for XML attribute map. Expected array but got object */ public function testXmlAttributeMapWithoutArray() { $attributes = new \ArrayObject(array( 'type' => 'text', )); $this->serializer->serialize(new Input($attributes), $this->getFormat()); } public function testObjectWithOnlyNamespacesAndList() { $object = new ObjectWithNamespacesAndList(); $object->phones = array(); $object->addresses = array(); $object->phonesAlternativeB = array(); $object->addressesAlternativeB = array(); $object->phonesAlternativeC = array('777', '888'); $object->addressesAlternativeC = array('A' => 'Street 7', 'B' => 'Street 8'); $object->phonesAlternativeD = array(); $object->addressesAlternativeD = array(); $this->assertEquals( $this->getContent('object_with_only_namespaces_and_list'), $this->serialize($object, SerializationContext::create()) ); $deserialized = $this->deserialize($this->getContent('object_with_only_namespaces_and_list'), get_class($object)); $this->assertEquals($object, $deserialized); } public function testDeserializingNull() { $this->markTestSkipped('Not supported in XML.'); } public function testDeserializeWithObjectWithToStringMethod() { $input = new ObjectWithToString($this->getContent('simple_object')); $object = $this->deserialize($input, SimpleObject::class); $this->assertInstanceOf(SimpleObject::class, $object); } public function testObjectWithXmlNamespaces() { $object = new ObjectWithXmlNamespaces('This is a nice title.', 'Foo Bar', new \DateTime('2011-07-30 00:00', new \DateTimeZone('UTC')), 'en'); $serialized = $this->serialize($object); $this->assertEquals($this->getContent('object_with_xml_namespaces'), $this->serialize($object)); $xml = simplexml_load_string($this->serialize($object)); $xml->registerXPathNamespace('ns1', "http://purl.org/dc/elements/1.1/"); $xml->registerXPathNamespace('ns2', "http://schemas.google.com/g/2005"); $xml->registerXPathNamespace('ns3', "http://www.w3.org/2005/Atom"); $this->assertEquals('2011-07-30T00:00:00+0000', $this->xpathFirstToString($xml, './@created_at')); $this->assertEquals('1edf9bf60a32d89afbb85b2be849e3ceed5f5b10', $this->xpathFirstToString($xml, './@ns2:etag')); $this->assertEquals('en', $this->xpathFirstToString($xml, './@ns1:language')); $this->assertEquals('This is a nice title.', $this->xpathFirstToString($xml, './ns1:title')); $this->assertEquals('Foo Bar', $this->xpathFirstToString($xml, './ns3:author')); $deserialized = $this->deserialize($this->getContent('object_with_xml_namespacesalias'), get_class($object)); $this->assertEquals('2011-07-30T00:00:00+0000', $this->getField($deserialized, 'createdAt')->format(\DateTime::ISO8601)); $this->assertAttributeEquals('This is a nice title.', 'title', $deserialized); $this->assertAttributeSame('1edf9bf60a32d89afbb85b2be849e3ceed5f5b10', 'etag', $deserialized); $this->assertAttributeSame('en', 'language', $deserialized); $this->assertAttributeEquals('Foo Bar', 'author', $deserialized); } public function testObjectWithXmlNamespacesAndBackReferencedNamespaces() { $author = new ObjectWithXmlNamespacesAndObjectPropertyAuthor('mr', 'smith'); $object = new ObjectWithXmlNamespacesAndObjectProperty('This is a nice title.', $author); $serialized = $this->serialize($object); $this->assertEquals($this->getContent('object_with_xml_namespaces_and_object_property'), $serialized); } public function testObjectWithXmlNamespacesAndBackReferencedNamespacesWithListeners() { $author = new ObjectWithXmlNamespacesAndObjectPropertyAuthor('mr', 'smith'); $object = new ObjectWithXmlNamespacesAndObjectPropertyVirtual('This is a nice title.', new \stdClass()); $this->handlerRegistry->registerHandler(GraphNavigator::DIRECTION_SERIALIZATION, 'ObjectWithXmlNamespacesAndObjectPropertyAuthorVirtual', $this->getFormat(), function (XmlSerializationVisitor $visitor, $data, $type, Context $context) use ($author) { $factory = $context->getMetadataFactory(get_class($author)); $classMetadata = $factory->getMetadataForClass(get_class($author)); $metadata = new StaticPropertyMetadata(get_class($author), 'foo', $author); $metadata->xmlNamespace = $classMetadata->xmlRootNamespace; $metadata->xmlNamespace = $classMetadata->xmlRootNamespace; $visitor->visitProperty($metadata, $author, $context); } ); $serialized = $this->serialize($object); $this->assertEquals($this->getContent('object_with_xml_namespaces_and_object_property_virtual'), $serialized); } public function testObjectWithXmlRootNamespace() { $object = new ObjectWithXmlRootNamespace('This is a nice title.', 'Foo Bar', new \DateTime('2011-07-30 00:00', new \DateTimeZone('UTC')), 'en'); $this->assertEquals($this->getContent('object_with_xml_root_namespace'), $this->serialize($object)); } public function testXmlNamespacesInheritance() { $object = new SimpleClassObject(); $object->foo = 'foo'; $object->bar = 'bar'; $object->moo = 'moo'; $this->assertEquals($this->getContent('simple_class_object'), $this->serialize($object)); $childObject = new SimpleSubClassObject(); $childObject->foo = 'foo'; $childObject->bar = 'bar'; $childObject->moo = 'moo'; $childObject->baz = 'baz'; $childObject->qux = 'qux'; $this->assertEquals($this->getContent('simple_subclass_object'), $this->serialize($childObject)); } public function testWithoutFormatedOutputByXmlSerializationVisitor() { $namingStrategy = new SerializedNameAnnotationStrategy(new CamelCaseNamingStrategy()); $xmlVisitor = new XmlSerializationVisitor($namingStrategy); $xmlVisitor->setFormatOutput(false); $visitors = new Map(array( 'xml' => new XmlSerializationVisitor($namingStrategy), )); $serializer = new Serializer( $this->factory, $this->handlerRegistry, new UnserializeObjectConstructor(), $visitors, $this->deserializationVisitors, $this->dispatcher ); $object = new SimpleClassObject; $object->foo = 'foo'; $object->bar = 'bar'; $object->moo = 'moo'; $stringXml = $serializer->serialize($object, $this->getFormat()); $this->assertXmlStringEqualsXmlString($this->getContent('simple_class_object_minified'), $stringXml); } public function testDiscriminatorAsXmlAttribute() { $xml = $this->serialize(new ObjectWithXmlAttributeDiscriminatorChild()); $this->assertEquals($this->getContent('xml_discriminator_attribute'), $xml); $this->assertInstanceOf( ObjectWithXmlAttributeDiscriminatorChild::class, $this->deserialize( $xml, ObjectWithXmlAttributeDiscriminatorParent::class ) ); } public function testDiscriminatorAsNotCData() { $xml = $this->serialize(new ObjectWithXmlNotCDataDiscriminatorChild()); $this->assertEquals($this->getContent('xml_discriminator_not_cdata'), $xml); $this->assertInstanceOf( ObjectWithXmlNotCDataDiscriminatorChild::class, $this->deserialize( $xml, ObjectWithXmlNotCDataDiscriminatorParent::class ) ); } public function testDiscriminatorWithNamespace() { $xml = $this->serialize(new ObjectWithXmlNamespaceDiscriminatorChild()); $this->assertEquals($this->getContent('xml_discriminator_namespace'), $xml); $this->assertInstanceOf( ObjectWithXmlNamespaceDiscriminatorChild::class, $this->deserialize( $xml, ObjectWithXmlNamespaceDiscriminatorParent::class ) ); } public function testDiscriminatorAsXmlAttributeWithNamespace() { $xml = $this->serialize(new ObjectWithXmlNamespaceAttributeDiscriminatorChild()); $this->assertEquals($this->getContent('xml_discriminator_namespace_attribute'), $xml); $this->assertInstanceOf( ObjectWithXmlNamespaceAttributeDiscriminatorChild::class, $this->deserialize( $xml, ObjectWithXmlNamespaceAttributeDiscriminatorParent::class ) ); } /** * @expectedException \JMS\Serializer\Exception\XmlErrorException */ public function testDeserializeEmptyString() { $this->deserialize('', 'stdClass'); } public function testEvaluatesToNull() { $namingStrategy = $this->getMockBuilder(PropertyNamingStrategyInterface::class)->getMock(); $visitor = new XmlDeserializationVisitor($namingStrategy); $xsdNilAsTrueElement = simplexml_load_string('<empty xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:nil="true"/>'); $xsdNilAsOneElement = simplexml_load_string('<empty xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:nil="1"/>'); $this->assertTrue($visitor->isNull($xsdNilAsTrueElement)); $this->assertTrue($visitor->isNull($xsdNilAsOneElement)); $this->assertTrue($visitor->isNull(null)); } private function xpathFirstToString(\SimpleXMLElement $xml, $xpath) { $nodes = $xml->xpath($xpath); return (string)reset($nodes); } /** * @param string $key */ protected function getContent($key) { if (!file_exists($file = __DIR__ . '/xml/' . $key . '.xml')) { throw new InvalidArgumentException(sprintf('The key "%s" is not supported.', $key)); } return file_get_contents($file); } protected function getFormat() { return 'xml'; } } tests/Serializer/ContextTest.php000077700000017212151323632140013026 0ustar00<?php namespace JMS\Serializer\Tests\Serializer; use JMS\Serializer\Metadata\ClassMetadata; use JMS\Serializer\Metadata\PropertyMetadata; use JMS\Serializer\SerializationContext; use JMS\Serializer\SerializerBuilder; use JMS\Serializer\Tests\Fixtures\InlineChild; use JMS\Serializer\Tests\Fixtures\Node; class ContextTest extends \PHPUnit_Framework_TestCase { public function testSerializationContextPathAndDepth() { $object = new Node(array( new Node(), new Node(array( new Node() )), )); $objects = array($object, $object->children[0], $object->children[1], $object->children[1]->children[0]); $self = $this; $exclusionStrategy = $this->getMockBuilder('JMS\Serializer\Exclusion\ExclusionStrategyInterface')->getMock(); $exclusionStrategy->expects($this->any()) ->method('shouldSkipClass') ->with($this->anything(), $this->callback(function (SerializationContext $context) use ($self, $objects) { $expectedDepth = $expectedPath = null; if ($context->getObject() === $objects[0]) { $expectedDepth = 1; $expectedPath = 'JMS\Serializer\Tests\Fixtures\Node'; } elseif ($context->getObject() === $objects[1]) { $expectedDepth = 2; $expectedPath = 'JMS\Serializer\Tests\Fixtures\Node -> JMS\Serializer\Tests\Fixtures\Node'; } elseif ($context->getObject() === $objects[2]) { $expectedDepth = 2; $expectedPath = 'JMS\Serializer\Tests\Fixtures\Node -> JMS\Serializer\Tests\Fixtures\Node'; } elseif ($context->getObject() === $objects[3]) { $expectedDepth = 3; $expectedPath = 'JMS\Serializer\Tests\Fixtures\Node -> JMS\Serializer\Tests\Fixtures\Node -> JMS\Serializer\Tests\Fixtures\Node'; } $self->assertEquals($expectedDepth, $context->getDepth(), 'shouldSkipClass depth'); $self->assertEquals($expectedPath, $context->getPath(), 'shouldSkipClass path'); return true; })) ->will($this->returnValue(false)); $exclusionStrategy->expects($this->any()) ->method('shouldSkipProperty') ->with($this->anything(), $this->callback(function (SerializationContext $context) use ($self, $objects) { $expectedDepth = $expectedPath = null; if ($context->getObject() === $objects[0]) { $expectedDepth = 1; $expectedPath = 'JMS\Serializer\Tests\Fixtures\Node'; } elseif ($context->getObject() === $objects[1]) { $expectedDepth = 2; $expectedPath = 'JMS\Serializer\Tests\Fixtures\Node -> JMS\Serializer\Tests\Fixtures\Node'; } elseif ($context->getObject() === $objects[2]) { $expectedDepth = 2; $expectedPath = 'JMS\Serializer\Tests\Fixtures\Node -> JMS\Serializer\Tests\Fixtures\Node'; } elseif ($context->getObject() === $objects[3]) { $expectedDepth = 3; $expectedPath = 'JMS\Serializer\Tests\Fixtures\Node -> JMS\Serializer\Tests\Fixtures\Node -> JMS\Serializer\Tests\Fixtures\Node'; } $self->assertEquals($expectedDepth, $context->getDepth(), 'shouldSkipProperty depth'); $self->assertEquals($expectedPath, $context->getPath(), 'shouldSkipProperty path'); return true; })) ->will($this->returnValue(false)); $serializer = SerializerBuilder::create()->build(); $serializer->serialize($object, 'json', SerializationContext::create()->addExclusionStrategy($exclusionStrategy)); } public function testSerializationMetadataStack() { $object = new Node(array( $child = new InlineChild(), )); $self = $this; $exclusionStrategy = $this->getMockBuilder('JMS\Serializer\Exclusion\ExclusionStrategyInterface')->getMock(); $exclusionStrategy->expects($this->any()) ->method('shouldSkipClass') ->will($this->returnCallback(function (ClassMetadata $classMetadata, SerializationContext $context) use ($self, $object, $child) { $stack = $context->getMetadataStack(); if ($object === $context->getObject()) { $self->assertEquals(0, $stack->count()); } if ($child === $context->getObject()) { $self->assertEquals(2, $stack->count()); $self->assertEquals('JMS\Serializer\Tests\Fixtures\Node', $stack[1]->name); $self->assertEquals('children', $stack[0]->name); } return false; })); $exclusionStrategy->expects($this->any()) ->method('shouldSkipProperty') ->will($this->returnCallback(function (PropertyMetadata $propertyMetadata, SerializationContext $context) use ($self, $object, $child) { $stack = $context->getMetadataStack(); if ('JMS\Serializer\Tests\Fixtures\Node' === $propertyMetadata->class && $propertyMetadata->name === 'children') { $self->assertEquals(1, $stack->count()); $self->assertEquals('JMS\Serializer\Tests\Fixtures\Node', $stack[0]->name); } if ('JMS\Serializer\Tests\Fixtures\InlineChild' === $propertyMetadata->class) { $self->assertEquals(3, $stack->count()); $self->assertEquals('JMS\Serializer\Tests\Fixtures\Node', $stack[2]->name); $self->assertEquals('children', $stack[1]->name); $self->assertEquals('JMS\Serializer\Tests\Fixtures\InlineChild', $stack[0]->name); } return false; })); $serializer = SerializerBuilder::create()->build(); $serializer->serialize($object, 'json', SerializationContext::create()->addExclusionStrategy($exclusionStrategy)); } public function getScalars() { return array( array("string"), array(5), array(5.5), array(array()) ); } /** * @dataProvider getScalars */ public function testCanVisitScalars($scalar) { $context = SerializationContext::create(); $context->startVisiting($scalar); $this->assertFalse($context->isVisiting($scalar)); $context->stopVisiting($scalar); } public function testInitialTypeCompatibility() { $context = SerializationContext::create(); $context->setInitialType('foo'); $this->assertEquals('foo', $context->getInitialType()); $this->assertEquals('foo', $context->attributes->get('initial_type')->get()); $context = SerializationContext::create(); $context->attributes->set('initial_type', 'foo'); $this->assertEquals('foo', $context->getInitialType()); } public function testSerializeNullOption() { $context = SerializationContext::create(); $this->assertNull($context->shouldSerializeNull()); $context->setSerializeNull(false); $this->assertFalse($context->shouldSerializeNull()); $context->setSerializeNull(true); $this->assertTrue($context->shouldSerializeNull()); $context->setSerializeNull("foo"); $this->assertTrue($context->shouldSerializeNull()); $context->setSerializeNull("0"); $this->assertFalse($context->shouldSerializeNull()); } } tests/Serializer/GraphNavigatorTest.php000077700000014735151323632140014325 0ustar00<?php namespace JMS\Serializer\Tests\Serializer; use Doctrine\Common\Annotations\AnnotationReader; use JMS\Serializer\Construction\UnserializeObjectConstructor; use JMS\Serializer\EventDispatcher\EventDispatcher; use JMS\Serializer\GraphNavigator; use JMS\Serializer\Handler\HandlerRegistry; use JMS\Serializer\Handler\SubscribingHandlerInterface; use JMS\Serializer\Metadata\Driver\AnnotationDriver; use Metadata\MetadataFactory; class GraphNavigatorTest extends \PHPUnit_Framework_TestCase { private $metadataFactory; private $handlerRegistry; private $objectConstructor; private $dispatcher; private $navigator; private $context; /** * @expectedException JMS\Serializer\Exception\RuntimeException * @expectedExceptionMessage Resources are not supported in serialized data. */ public function testResourceThrowsException() { $this->context->expects($this->any()) ->method('getDirection') ->will($this->returnValue(GraphNavigator::DIRECTION_SERIALIZATION)); $this->navigator->accept(STDIN, null, $this->context); } public function testNavigatorPassesInstanceOnSerialization() { $object = new SerializableClass; $metadata = $this->metadataFactory->getMetadataForClass(get_class($object)); $self = $this; $context = $this->context; $exclusionStrategy = $this->getMockBuilder('JMS\Serializer\Exclusion\ExclusionStrategyInterface')->getMock(); $exclusionStrategy->expects($this->once()) ->method('shouldSkipClass') ->will($this->returnCallback(function ($passedMetadata, $passedContext) use ($metadata, $context, $self) { $self->assertSame($metadata, $passedMetadata); $self->assertSame($context, $passedContext); })); $exclusionStrategy->expects($this->once()) ->method('shouldSkipProperty') ->will($this->returnCallback(function ($propertyMetadata, $passedContext) use ($context, $metadata, $self) { $self->assertSame($metadata->propertyMetadata['foo'], $propertyMetadata); $self->assertSame($context, $passedContext); })); $this->context->expects($this->once()) ->method('getExclusionStrategy') ->will($this->returnValue($exclusionStrategy)); $this->context->expects($this->any()) ->method('getDirection') ->will($this->returnValue(GraphNavigator::DIRECTION_SERIALIZATION)); $this->context->expects($this->any()) ->method('getVisitor') ->will($this->returnValue($this->getMockBuilder('JMS\Serializer\VisitorInterface')->getMock())); $this->navigator = new GraphNavigator($this->metadataFactory, $this->handlerRegistry, $this->objectConstructor, $this->dispatcher); $this->navigator->accept($object, null, $this->context); } public function testNavigatorPassesNullOnDeserialization() { $class = __NAMESPACE__ . '\SerializableClass'; $metadata = $this->metadataFactory->getMetadataForClass($class); $context = $this->context; $exclusionStrategy = $this->getMockBuilder('JMS\Serializer\Exclusion\ExclusionStrategyInterface')->getMock(); $exclusionStrategy->expects($this->once()) ->method('shouldSkipClass') ->with($metadata, $this->callback(function ($navigatorContext) use ($context) { return $navigatorContext === $context; })); $exclusionStrategy->expects($this->once()) ->method('shouldSkipProperty') ->with($metadata->propertyMetadata['foo'], $this->callback(function ($navigatorContext) use ($context) { return $navigatorContext === $context; })); $this->context->expects($this->once()) ->method('getExclusionStrategy') ->will($this->returnValue($exclusionStrategy)); $this->context->expects($this->any()) ->method('getDirection') ->will($this->returnValue(GraphNavigator::DIRECTION_DESERIALIZATION)); $this->context->expects($this->any()) ->method('getVisitor') ->will($this->returnValue($this->getMockBuilder('JMS\Serializer\VisitorInterface')->getMock())); $this->navigator = new GraphNavigator($this->metadataFactory, $this->handlerRegistry, $this->objectConstructor, $this->dispatcher); $this->navigator->accept('random', array('name' => $class, 'params' => array()), $this->context); } public function testNavigatorChangeTypeOnSerialization() { $object = new SerializableClass; $typeName = 'JsonSerializable'; $this->dispatcher->addListener('serializer.pre_serialize', function ($event) use ($typeName) { $type = $event->getType(); $type['name'] = $typeName; $event->setType($type['name'], $type['params']); }); $this->handlerRegistry->registerSubscribingHandler(new TestSubscribingHandler()); $this->context->expects($this->any()) ->method('getDirection') ->will($this->returnValue(GraphNavigator::DIRECTION_SERIALIZATION)); $this->context->expects($this->any()) ->method('getVisitor') ->will($this->returnValue($this->getMockBuilder('JMS\Serializer\VisitorInterface')->getMock())); $this->navigator = new GraphNavigator($this->metadataFactory, $this->handlerRegistry, $this->objectConstructor, $this->dispatcher); $this->navigator->accept($object, null, $this->context); } protected function setUp() { $this->context = $this->getMockBuilder('JMS\Serializer\Context')->getMock(); $this->dispatcher = new EventDispatcher(); $this->handlerRegistry = new HandlerRegistry(); $this->objectConstructor = new UnserializeObjectConstructor(); $this->metadataFactory = new MetadataFactory(new AnnotationDriver(new AnnotationReader())); $this->navigator = new GraphNavigator($this->metadataFactory, $this->handlerRegistry, $this->objectConstructor, $this->dispatcher); } } class SerializableClass { public $foo = 'bar'; } class TestSubscribingHandler implements SubscribingHandlerInterface { public static function getSubscribingMethods() { return array(array( 'type' => 'JsonSerializable', 'format' => 'foo', 'direction' => GraphNavigator::DIRECTION_SERIALIZATION, 'method' => 'serialize' )); } } tests/Serializer/BaseSerializationTest.php000077700000162267151323632140015025 0ustar00<?php namespace JMS\Serializer\Tests\Serializer; use Doctrine\Common\Annotations\AnnotationReader; use Doctrine\Common\Collections\ArrayCollection; use JMS\Serializer\Accessor\DefaultAccessorStrategy; use JMS\Serializer\Accessor\ExpressionAccessorStrategy; use JMS\Serializer\Construction\UnserializeObjectConstructor; use JMS\Serializer\Context; use JMS\Serializer\DeserializationContext; use JMS\Serializer\EventDispatcher\EventDispatcher; use JMS\Serializer\EventDispatcher\Subscriber\DoctrineProxySubscriber; use JMS\Serializer\Exclusion\DepthExclusionStrategy; use JMS\Serializer\Exclusion\GroupsExclusionStrategy; use JMS\Serializer\Expression\ExpressionEvaluator; use JMS\Serializer\GraphNavigator; use JMS\Serializer\Handler\ArrayCollectionHandler; use JMS\Serializer\Handler\ConstraintViolationHandler; use JMS\Serializer\Handler\DateHandler; use JMS\Serializer\Handler\FormErrorHandler; use JMS\Serializer\Handler\HandlerRegistry; use JMS\Serializer\Handler\PhpCollectionHandler; use JMS\Serializer\Handler\StdClassHandler; use JMS\Serializer\JsonDeserializationVisitor; use JMS\Serializer\JsonSerializationVisitor; use JMS\Serializer\Metadata\Driver\AnnotationDriver; use JMS\Serializer\Metadata\Driver\YamlDriver; use JMS\Serializer\Naming\CamelCaseNamingStrategy; use JMS\Serializer\Naming\SerializedNameAnnotationStrategy; use JMS\Serializer\SerializationContext; use JMS\Serializer\Serializer; use JMS\Serializer\Tests\Fixtures\AccessorOrderChild; use JMS\Serializer\Tests\Fixtures\AccessorOrderMethod; use JMS\Serializer\Tests\Fixtures\AccessorOrderParent; use JMS\Serializer\Tests\Fixtures\Article; use JMS\Serializer\Tests\Fixtures\Author; use JMS\Serializer\Tests\Fixtures\AuthorExpressionAccess; use JMS\Serializer\Tests\Fixtures\AuthorList; use JMS\Serializer\Tests\Fixtures\AuthorReadOnly; use JMS\Serializer\Tests\Fixtures\AuthorReadOnlyPerClass; use JMS\Serializer\Tests\Fixtures\BlogPost; use JMS\Serializer\Tests\Fixtures\CircularReferenceParent; use JMS\Serializer\Tests\Fixtures\Comment; use JMS\Serializer\Tests\Fixtures\CurrencyAwareOrder; use JMS\Serializer\Tests\Fixtures\CurrencyAwarePrice; use JMS\Serializer\Tests\Fixtures\CustomDeserializationObject; use JMS\Serializer\Tests\Fixtures\DateTimeArraysObject; use JMS\Serializer\Tests\Fixtures\Discriminator\Car; use JMS\Serializer\Tests\Fixtures\Discriminator\ImagePost; use JMS\Serializer\Tests\Fixtures\Discriminator\Moped; use JMS\Serializer\Tests\Fixtures\Discriminator\Post; use JMS\Serializer\Tests\Fixtures\Garage; use JMS\Serializer\Tests\Fixtures\GetSetObject; use JMS\Serializer\Tests\Fixtures\GroupsObject; use JMS\Serializer\Tests\Fixtures\GroupsUser; use JMS\Serializer\Tests\Fixtures\IndexedCommentsBlogPost; use JMS\Serializer\Tests\Fixtures\InitializedBlogPostConstructor; use JMS\Serializer\Tests\Fixtures\InitializedObjectConstructor; use JMS\Serializer\Tests\Fixtures\InlineChild; use JMS\Serializer\Tests\Fixtures\InlineChildEmpty; use JMS\Serializer\Tests\Fixtures\InlineChildWithGroups; use JMS\Serializer\Tests\Fixtures\InlineParent; use JMS\Serializer\Tests\Fixtures\Input; use JMS\Serializer\Tests\Fixtures\InvalidGroupsObject; use JMS\Serializer\Tests\Fixtures\Log; use JMS\Serializer\Tests\Fixtures\MaxDepth\Gh236Foo; use JMS\Serializer\Tests\Fixtures\NamedDateTimeArraysObject; use JMS\Serializer\Tests\Fixtures\NamedDateTimeImmutableArraysObject; use JMS\Serializer\Tests\Fixtures\Node; use JMS\Serializer\Tests\Fixtures\ObjectUsingTypeCasting; use JMS\Serializer\Tests\Fixtures\ObjectWithEmptyHash; use JMS\Serializer\Tests\Fixtures\ObjectWithEmptyNullableAndEmptyArrays; use JMS\Serializer\Tests\Fixtures\ObjectWithIntListAndIntMap; use JMS\Serializer\Tests\Fixtures\ObjectWithLifecycleCallbacks; use JMS\Serializer\Tests\Fixtures\ObjectWithNullProperty; use JMS\Serializer\Tests\Fixtures\ObjectWithToString; use JMS\Serializer\Tests\Fixtures\ObjectWithVersionedVirtualProperties; use JMS\Serializer\Tests\Fixtures\ObjectWithVirtualProperties; use JMS\Serializer\Tests\Fixtures\Order; use JMS\Serializer\Tests\Fixtures\ParentDoNotSkipWithEmptyChild; use JMS\Serializer\Tests\Fixtures\ParentSkipWithEmptyChild; use JMS\Serializer\Tests\Fixtures\PersonSecret; use JMS\Serializer\Tests\Fixtures\PersonSecretMore; use JMS\Serializer\Tests\Fixtures\PersonSecretMoreVirtual; use JMS\Serializer\Tests\Fixtures\PersonSecretVirtual; use JMS\Serializer\Tests\Fixtures\Price; use JMS\Serializer\Tests\Fixtures\Publisher; use JMS\Serializer\Tests\Fixtures\SimpleInternalObject; use JMS\Serializer\Tests\Fixtures\SimpleObject; use JMS\Serializer\Tests\Fixtures\SimpleObjectProxy; use JMS\Serializer\Tests\Fixtures\SimpleObjectWithStaticProp; use JMS\Serializer\Tests\Fixtures\Tag; use JMS\Serializer\Tests\Fixtures\Timestamp; use JMS\Serializer\Tests\Fixtures\Tree; use JMS\Serializer\Tests\Fixtures\VehicleInterfaceGarage; use JMS\Serializer\VisitorInterface; use JMS\Serializer\XmlDeserializationVisitor; use JMS\Serializer\XmlSerializationVisitor; use JMS\Serializer\YamlSerializationVisitor; use Metadata\Driver\FileLocator; use Metadata\MetadataFactory; use PhpCollection\Map; use PhpCollection\Sequence; use Symfony\Component\ExpressionLanguage\ExpressionFunction; use Symfony\Component\ExpressionLanguage\ExpressionLanguage; use Symfony\Component\Form\Form; use Symfony\Component\Form\FormError; use Symfony\Component\Form\FormFactoryBuilder; use Symfony\Component\Translation\IdentityTranslator; use Symfony\Component\Translation\MessageSelector; use Symfony\Component\Validator\ConstraintViolation; use Symfony\Component\Validator\ConstraintViolationList; abstract class BaseSerializationTest extends \PHPUnit_Framework_TestCase { protected $factory; /** * @var EventDispatcher */ protected $dispatcher; /** @var Serializer */ protected $serializer; protected $handlerRegistry; protected $serializationVisitors; protected $deserializationVisitors; protected $objectConstructor; public function testSerializeNullArray() { $arr = array('foo' => 'bar', 'baz' => null, null); $this->assertEquals( $this->getContent('nullable'), $this->serializer->serialize($arr, $this->getFormat(), SerializationContext::create()->setSerializeNull(true)) ); } public function testSerializeNullArrayExcludingNulls() { $arr = array('foo' => 'bar', 'baz' => null, null); $this->assertEquals( $this->getContent('nullable_skip'), $this->serializer->serialize($arr, $this->getFormat(), SerializationContext::create()->setSerializeNull(false)) ); } public function testObjectUsingTypeCasting() { $typeAliasing = new ObjectUsingTypeCasting(); $typeAliasing->asString = new ObjectWithToString("8"); $this->assertEquals( $this->getContent('type_casting'), $this->serialize($typeAliasing) ); } public function testSerializeNullObject() { $obj = new ObjectWithNullProperty('foo', 'bar'); $this->assertEquals( $this->getContent('simple_object_nullable'), $this->serializer->serialize($obj, $this->getFormat(), SerializationContext::create()->setSerializeNull(true)) ); } public function testDeserializeNullObject() { if (!$this->hasDeserializer()) { $this->markTestSkipped(sprintf('No deserializer available for format `%s`', $this->getFormat())); } $obj = new ObjectWithNullProperty('foo', 'bar'); /** @var ObjectWithNullProperty $dObj */ $dObj = $this->serializer->deserialize( $this->getContent('simple_object_nullable'), ObjectWithNullProperty::class, $this->getFormat() ); $this->assertEquals($obj, $dObj); $this->assertNull($dObj->getNullProperty()); } /** * @dataProvider getTypes */ public function testNull($type) { $this->assertEquals($this->getContent('null'), $this->serialize(null), $type); if ($this->hasDeserializer()) { $this->assertEquals(null, $this->deserialize($this->getContent('null'), $type)); } } public function getTypes() { return array( array('NULL'), array('integer'), array('double'), array('float'), array('string'), array('DateTime'), ); } public function testString() { $this->assertEquals($this->getContent('string'), $this->serialize('foo')); if ($this->hasDeserializer()) { $this->assertEquals('foo', $this->deserialize($this->getContent('string'), 'string')); } } /** * @expectedException \JMS\Serializer\Exception\ExpressionLanguageRequiredException * @expectedExceptionMessage To use conditional exclude/expose in JMS\Serializer\Tests\Fixtures\PersonSecret you must configure the expression language. */ public function testExpressionExclusionNotConfigured() { $person = new PersonSecret(); $person->gender = 'f'; $person->name = 'mike'; $this->serialize($person); } public function testExpressionExclusionConfiguredWithDisjunctStrategy() { $person = new PersonSecret(); $person->gender = 'f'; $person->name = 'mike'; $language = new ExpressionLanguage(); $language->addFunction(new ExpressionFunction('show_data', function () { return "true"; }, function () { return true; })); $serializer = new Serializer($this->factory, $this->handlerRegistry, $this->objectConstructor, $this->serializationVisitors, $this->deserializationVisitors, $this->dispatcher, null, new ExpressionEvaluator($language)); $this->assertEquals($this->getContent('person_secret_hide'), $serializer->serialize($person, $this->getFormat())); } public function expressionFunctionProvider() { $person = new PersonSecret(); $person->gender = 'f'; $person->name = 'mike'; $personMoreSecret = new PersonSecretMore(); $personMoreSecret->gender = 'f'; $personMoreSecret->name = 'mike'; $personVirtual = new PersonSecretVirtual(); $personVirtual->gender = 'f'; $personVirtual->name = 'mike'; $personMoreSecretVirtual = new PersonSecretMoreVirtual(); $personMoreSecretVirtual->gender = 'f'; $personMoreSecretVirtual->name = 'mike'; $showGender = new ExpressionFunction('show_data', function () { return "true"; }, function () { return true; }); $hideGender = new ExpressionFunction('show_data', function () { return "false"; }, function () { return false; }); return [ [ $person, $showGender, 'person_secret_hide' ], [ $person, $hideGender, 'person_secret_show' ], [ $personMoreSecret, $showGender, 'person_secret_show' ], [ $personMoreSecret, $hideGender, 'person_secret_hide' ], [ $personVirtual, $showGender, 'person_secret_hide' ], [ $personVirtual, $hideGender, 'person_secret_show' ], [ $personMoreSecretVirtual, $showGender, 'person_secret_show' ], [ $personMoreSecretVirtual, $hideGender, 'person_secret_hide' ] ]; } /** * @dataProvider expressionFunctionProvider * @param PersonSecret|PersonSecretMore $person * @param ExpressionFunction $function * @param $json */ public function testExpressionExclusion($person, ExpressionFunction $function, $json) { $language = new ExpressionLanguage(); $language->addFunction($function); $serializer = new Serializer($this->factory, $this->handlerRegistry, $this->objectConstructor, $this->serializationVisitors, $this->deserializationVisitors, $this->dispatcher, null, new ExpressionEvaluator($language)); $this->assertEquals($this->getContent($json), $serializer->serialize($person, $this->getFormat())); } /** * @dataProvider getBooleans */ public function testBooleans($strBoolean, $boolean) { $this->assertEquals($this->getContent('boolean_' . $strBoolean), $this->serialize($boolean)); if ($this->hasDeserializer()) { $this->assertSame($boolean, $this->deserialize($this->getContent('boolean_' . $strBoolean), 'boolean')); } } public function getBooleans() { return array(array('true', true), array('false', false)); } /** * @dataProvider getNumerics */ public function testNumerics($key, $value, $type) { $this->assertEquals($this->getContent($key), $this->serialize($value)); if ($this->hasDeserializer()) { $this->assertEquals($value, $this->deserialize($this->getContent($key), $type)); } } public function getNumerics() { return array( array('integer', 1, 'integer'), array('float', 4.533, 'double'), array('float', 4.533, 'float'), array('float_trailing_zero', 1.0, 'double'), array('float_trailing_zero', 1.0, 'float'), ); } public function testSimpleInternalObject() { $this->factory = new MetadataFactory(new YamlDriver(new FileLocator([ 'JMS\Serializer\Tests\Fixtures' => __DIR__ .'/metadata/SimpleInternalObject', '' => __DIR__ .'/metadata/SimpleInternalObject' ]))); $this->serializer = new Serializer($this->factory, $this->handlerRegistry, $this->objectConstructor, $this->serializationVisitors, $this->deserializationVisitors, $this->dispatcher); $obj = new SimpleInternalObject('foo', 'bar'); $this->assertEquals($this->getContent('simple_object'), $this->serialize($obj)); if ($this->hasDeserializer()) { $deserialized = $this->deserialize($this->getContent('simple_object'), get_class($obj)); $this->assertEquals(get_class($obj), get_class($deserialized)); } } public function testSimpleObjectStaticProp() { $this->assertEquals($this->getContent('simple_object'), $this->serialize($obj = new SimpleObjectWithStaticProp('foo', 'bar'))); if ($this->hasDeserializer()) { $this->assertEquals($obj, $this->deserialize($this->getContent('simple_object'), get_class($obj))); } } public function testSimpleObject() { $this->assertEquals($this->getContent('simple_object'), $this->serialize($obj = new SimpleObject('foo', 'bar'))); if ($this->hasDeserializer()) { $this->assertEquals($obj, $this->deserialize($this->getContent('simple_object'), get_class($obj))); } } public function testArrayStrings() { $data = array('foo', 'bar'); $this->assertEquals($this->getContent('array_strings'), $this->serialize($data)); if ($this->hasDeserializer()) { $this->assertEquals($data, $this->deserialize($this->getContent('array_strings'), 'array<string>')); } } public function testArrayBooleans() { $data = array(true, false); $this->assertEquals($this->getContent('array_booleans'), $this->serialize($data)); if ($this->hasDeserializer()) { $this->assertEquals($data, $this->deserialize($this->getContent('array_booleans'), 'array<boolean>')); } } public function testArrayIntegers() { $data = array(1, 3, 4); $this->assertEquals($this->getContent('array_integers'), $this->serialize($data)); if ($this->hasDeserializer()) { $this->assertEquals($data, $this->deserialize($this->getContent('array_integers'), 'array<integer>')); } } public function testArrayEmpty() { if ('xml' === $this->getFormat()) { $this->markTestSkipped('XML can\'t be tested for empty array'); } $data = array('array' => []); $this->assertEquals($this->getContent('array_empty'), $this->serialize($data)); if ($this->hasDeserializer()) { $this->assertEquals($data, $this->deserialize($this->getContent('array_empty'), 'array')); } } public function testArrayFloats() { $data = array(1.34, 3.0, 6.42); $this->assertEquals($this->getContent('array_floats'), $this->serialize($data)); if ($this->hasDeserializer()) { $this->assertEquals($data, $this->deserialize($this->getContent('array_floats'), 'array<double>')); } } public function testArrayObjects() { $data = array(new SimpleObject('foo', 'bar'), new SimpleObject('baz', 'boo')); $this->assertEquals($this->getContent('array_objects'), $this->serialize($data)); if ($this->hasDeserializer()) { $this->assertEquals($data, $this->deserialize($this->getContent('array_objects'), 'array<JMS\Serializer\Tests\Fixtures\SimpleObject>')); } } public function testArrayListAndMapDifference() { $arrayData = array(0 => 1, 2 => 2, 3 => 3); // Misses key 1 $data = new ObjectWithIntListAndIntMap($arrayData, $arrayData); $this->assertEquals($this->getContent('array_list_and_map_difference'), $this->serialize($data)); } public function testDateTimeArrays() { $data = array( new \DateTime('2047-01-01 12:47:47', new \DateTimeZone('UTC')), new \DateTime('2016-12-05 00:00:00', new \DateTimeZone('UTC')) ); $object = new DateTimeArraysObject($data, $data); $serializedObject = $this->serialize($object); $this->assertEquals($this->getContent('array_datetimes_object'), $serializedObject); if ($this->hasDeserializer()) { /** @var DateTimeArraysObject $deserializedObject */ $deserializedObject = $this->deserialize($this->getContent('array_datetimes_object'), 'Jms\Serializer\Tests\Fixtures\DateTimeArraysObject'); /** deserialized object has a default timezone set depending on user's timezone settings. That's why we manually set the UTC timezone on the DateTime objects. */ foreach ($deserializedObject->getArrayWithDefaultDateTime() as $dateTime) { $dateTime->setTimezone(new \DateTimeZone('UTC')); } foreach ($deserializedObject->getArrayWithFormattedDateTime() as $dateTime) { $dateTime->setTimezone(new \DateTimeZone('UTC')); } $this->assertEquals($object, $deserializedObject); } } public function testNamedDateTimeArrays() { $data = array( new \DateTime('2047-01-01 12:47:47', new \DateTimeZone('UTC')), new \DateTime('2016-12-05 00:00:00', new \DateTimeZone('UTC')) ); $object = new NamedDateTimeArraysObject(array('testdate1' => $data[0], 'testdate2' => $data[1])); $serializedObject = $this->serialize($object); $this->assertEquals($this->getContent('array_named_datetimes_object'), $serializedObject); if ($this->hasDeserializer()) { // skip XML deserialization if ($this->getFormat() === 'xml') { return; } /** @var NamedDateTimeArraysObject $deserializedObject */ $deserializedObject = $this->deserialize($this->getContent('array_named_datetimes_object'), 'Jms\Serializer\Tests\Fixtures\NamedDateTimeArraysObject'); /** deserialized object has a default timezone set depending on user's timezone settings. That's why we manually set the UTC timezone on the DateTime objects. */ foreach ($deserializedObject->getNamedArrayWithFormattedDate() as $dateTime) { $dateTime->setTimezone(new \DateTimeZone('UTC')); } $this->assertEquals($object, $deserializedObject); } } /** * @group datetime */ public function testNamedDateTimeImmutableArrays() { $data = array( new \DateTimeImmutable('2047-01-01 12:47:47', new \DateTimeZone('UTC')), new \DateTimeImmutable('2016-12-05 00:00:00', new \DateTimeZone('UTC')) ); $object = new NamedDateTimeImmutableArraysObject(array('testdate1' => $data[0], 'testdate2' => $data[1])); $serializedObject = $this->serialize($object); $this->assertEquals($this->getContent('array_named_datetimeimmutables_object'), $serializedObject); if ($this->hasDeserializer()) { if ('xml' == $this->getFormat()) { $this->markTestSkipped("XML deserialization does not support key-val pairs mode"); } /** @var NamedDateTimeArraysObject $deserializedObject */ $deserializedObject = $this->deserialize($this->getContent('array_named_datetimeimmutables_object'), 'Jms\Serializer\Tests\Fixtures\NamedDateTimeImmutableArraysObject'); /** deserialized object has a default timezone set depending on user's timezone settings. That's why we manually set the UTC timezone on the DateTime objects. */ foreach ($deserializedObject->getNamedArrayWithFormattedDate() as $dateTime) { $dateTime->setTimezone(new \DateTimeZone('UTC')); } $this->assertEquals($object, $deserializedObject); } } public function testArrayMixed() { $this->assertEquals($this->getContent('array_mixed'), $this->serialize(array('foo', 1, true, new SimpleObject('foo', 'bar'), array(1, 3, true)))); } /** * @dataProvider getDateTime * @group datetime */ public function testDateTime($key, $value, $type) { $this->assertEquals($this->getContent($key), $this->serialize($value)); if ($this->hasDeserializer()) { $deserialized = $this->deserialize($this->getContent($key), $type); $this->assertTrue(is_object($deserialized)); $this->assertEquals(get_class($value), get_class($deserialized)); $this->assertEquals($value->getTimestamp(), $deserialized->getTimestamp()); } } public function getDateTime() { return array( array('date_time', new \DateTime('2011-08-30 00:00', new \DateTimeZone('UTC')), 'DateTime'), ); } /** * @dataProvider getDateTimeImmutable * @group datetime */ public function testDateTimeImmutable($key, $value, $type) { $this->assertEquals($this->getContent($key), $this->serialize($value)); if ($this->hasDeserializer()) { $deserialized = $this->deserialize($this->getContent($key), $type); $this->assertTrue(is_object($deserialized)); $this->assertEquals(get_class($value), get_class($deserialized)); $this->assertEquals($value->getTimestamp(), $deserialized->getTimestamp()); } } public function getDateTimeImmutable() { return array( array('date_time_immutable', new \DateTimeImmutable('2011-08-30 00:00', new \DateTimeZone('UTC')), 'DateTimeImmutable'), ); } public function testTimestamp() { $value = new Timestamp(new \DateTime('2016-02-11 00:00:00', new \DateTimeZone('UTC'))); $this->assertEquals($this->getContent('timestamp'), $this->serialize($value)); if ($this->hasDeserializer()) { $deserialized = $this->deserialize($this->getContent('timestamp'), Timestamp::class); $this->assertEquals($value, $deserialized); $this->assertEquals($value->getTimestamp()->getTimestamp(), $deserialized->getTimestamp()->getTimestamp()); $deserialized = $this->deserialize($this->getContent('timestamp_prev'), Timestamp::class); $this->assertEquals($value, $deserialized); $this->assertEquals($value->getTimestamp()->getTimestamp(), $deserialized->getTimestamp()->getTimestamp()); } } public function testDateInterval() { $duration = new \DateInterval('PT45M'); $this->assertEquals($this->getContent('date_interval'), $this->serializer->serialize($duration, $this->getFormat())); if ($this->hasDeserializer()) { $deserialized = $this->deserialize($this->getContent('date_interval'), \DateInterval::class); $this->assertEquals($duration, $deserialized); $this->assertEquals($duration->i, $deserialized->i); } } public function testBlogPost() { $post = new BlogPost('This is a nice title.', $author = new Author('Foo Bar'), new \DateTime('2011-07-30 00:00', new \DateTimeZone('UTC')), new Publisher('Bar Foo')); $post->addComment($comment = new Comment($author, 'foo')); $post->addTag($tag1 = New Tag("tag1")); $post->addTag($tag2 = New Tag("tag2")); $this->assertEquals($this->getContent('blog_post'), $this->serialize($post)); if ($this->hasDeserializer()) { $deserialized = $this->deserialize($this->getContent('blog_post'), get_class($post)); $this->assertEquals('2011-07-30T00:00:00+0000', $this->getField($deserialized, 'createdAt')->format(\DateTime::ISO8601)); $this->assertAttributeEquals('This is a nice title.', 'title', $deserialized); $this->assertAttributeSame(false, 'published', $deserialized); $this->assertAttributeSame(false, 'reviewed', $deserialized); $this->assertAttributeSame('1edf9bf60a32d89afbb85b2be849e3ceed5f5b10', 'etag', $deserialized); $this->assertAttributeEquals(new ArrayCollection(array($comment)), 'comments', $deserialized); $this->assertAttributeEquals(new Sequence(array($comment)), 'comments2', $deserialized); $this->assertAttributeEquals($author, 'author', $deserialized); $this->assertAttributeEquals(array($tag1, $tag2), 'tag', $deserialized); } } public function testDeserializingNull() { $objectConstructor = new InitializedBlogPostConstructor(); $this->serializer = new Serializer($this->factory, $this->handlerRegistry, $objectConstructor, $this->serializationVisitors, $this->deserializationVisitors, $this->dispatcher); $post = new BlogPost('This is a nice title.', $author = new Author('Foo Bar'), new \DateTime('2011-07-30 00:00', new \DateTimeZone('UTC')), new Publisher('Bar Foo')); $this->setField($post, 'author', null); $this->setField($post, 'publisher', null); $this->assertEquals($this->getContent('blog_post_unauthored'), $this->serialize($post, SerializationContext::create()->setSerializeNull(true))); if ($this->hasDeserializer()) { $deserialized = $this->deserialize($this->getContent('blog_post_unauthored'), get_class($post), DeserializationContext::create()->setSerializeNull(true)); $this->assertEquals('2011-07-30T00:00:00+0000', $this->getField($deserialized, 'createdAt')->format(\DateTime::ISO8601)); $this->assertAttributeEquals('This is a nice title.', 'title', $deserialized); $this->assertAttributeSame(false, 'published', $deserialized); $this->assertAttributeSame(false, 'reviewed', $deserialized); $this->assertAttributeEquals(new ArrayCollection(), 'comments', $deserialized); $this->assertEquals(null, $this->getField($deserialized, 'author')); } } public function testExpressionAuthor() { $namingStrategy = new SerializedNameAnnotationStrategy(new CamelCaseNamingStrategy()); $evaluator = new ExpressionEvaluator(new ExpressionLanguage()); $accessor = new ExpressionAccessorStrategy($evaluator, new DefaultAccessorStrategy()); $this->serializationVisitors = new Map(array( 'json' => new JsonSerializationVisitor($namingStrategy, $accessor), 'xml' => new XmlSerializationVisitor($namingStrategy, $accessor), 'yml' => new YamlSerializationVisitor($namingStrategy, $accessor), )); $serializer = new Serializer($this->factory, $this->handlerRegistry, $this->objectConstructor, $this->serializationVisitors, $this->deserializationVisitors, $this->dispatcher, null, $evaluator); $author = new AuthorExpressionAccess(123, "Ruud", "Kamphuis"); $this->assertEquals($this->getContent('author_expression'), $serializer->serialize($author, $this->getFormat())); } /** * @expectedException \JMS\Serializer\Exception\ExpressionLanguageRequiredException * @expectedExceptionMessage The property firstName on JMS\Serializer\Tests\Fixtures\AuthorExpressionAccess requires the expression accessor strategy to be enabled. */ public function testExpressionAccessorStrategNotEnabled() { $author = new AuthorExpressionAccess(123, "Ruud", "Kamphuis"); $this->assertEquals($this->getContent('author_expression'), $this->serialize($author)); } public function testReadOnly() { $author = new AuthorReadOnly(123, 'Ruud Kamphuis'); $this->assertEquals($this->getContent('readonly'), $this->serialize($author)); if ($this->hasDeserializer()) { $deserialized = $this->deserialize($this->getContent('readonly'), get_class($author)); $this->assertNull($this->getField($deserialized, 'id')); $this->assertEquals('Ruud Kamphuis', $this->getField($deserialized, 'name')); } } public function testReadOnlyClass() { $author = new AuthorReadOnlyPerClass(123, 'Ruud Kamphuis'); $this->assertEquals($this->getContent('readonly'), $this->serialize($author)); if ($this->hasDeserializer()) { $deserialized = $this->deserialize($this->getContent('readonly'), get_class($author)); $this->assertNull($this->getField($deserialized, 'id')); $this->assertEquals('Ruud Kamphuis', $this->getField($deserialized, 'name')); } } public function testPrice() { $price = new Price(3); $this->assertEquals($this->getContent('price'), $this->serialize($price)); if ($this->hasDeserializer()) { $deserialized = $this->deserialize($this->getContent('price'), get_class($price)); $this->assertEquals(3, $this->getField($deserialized, 'price')); } } public function testOrder() { $order = new Order(new Price(12.34)); $this->assertEquals($this->getContent('order'), $this->serialize($order)); if ($this->hasDeserializer()) { $this->assertEquals($order, $this->deserialize($this->getContent('order'), get_class($order))); } } public function testCurrencyAwarePrice() { $price = new CurrencyAwarePrice(2.34); $this->assertEquals($this->getContent('currency_aware_price'), $this->serialize($price)); if ($this->hasDeserializer()) { $this->assertEquals($price, $this->deserialize($this->getContent('currency_aware_price'), get_class($price))); } } public function testOrderWithCurrencyAwarePrice() { $order = new CurrencyAwareOrder(new CurrencyAwarePrice(1.23)); $this->assertEquals($this->getContent('order_with_currency_aware_price'), $this->serialize($order)); if ($this->hasDeserializer()) { $this->assertEquals($order, $this->deserialize($this->getContent('order_with_currency_aware_price'), get_class($order))); } } /** * @group handlerCallback */ public function testArticle() { $article = new Article(); $article->element = 'custom'; $article->value = 'serialized'; $result = $this->serialize($article); $this->assertEquals($this->getContent('article'), $result); if ($this->hasDeserializer()) { $this->assertEquals($article, $this->deserialize($result, 'JMS\Serializer\Tests\Fixtures\Article')); } } public function testInline() { $inline = new InlineParent(); $result = $this->serialize($inline); $this->assertEquals($this->getContent('inline'), $result); // no deserialization support } public function testInlineEmptyChild() { $inline = new InlineParent(new InlineChildEmpty()); $result = $this->serialize($inline); $this->assertEquals($this->getContent('inline_child_empty'), $result); // no deserialization support } public function testEmptyChild() { // by empty object $inline = new ParentDoNotSkipWithEmptyChild(new InlineChildEmpty()); $this->assertEquals($this->getContent('empty_child'), $this->serialize($inline)); // by nulls $inner = new InlineChild(); $inner->a = null; $inner->b = null; $inline = new ParentDoNotSkipWithEmptyChild($inner); $this->assertEquals($this->getContent('empty_child'), $this->serialize($inline)); // by exclusion strategy $context = SerializationContext::create()->setGroups(['Default']); $inline = new ParentDoNotSkipWithEmptyChild(new InlineChildWithGroups()); $this->assertEquals($this->getContent('empty_child'), $this->serialize($inline, $context)); } public function testSkipEmptyChild() { // by empty object $inline = new ParentSkipWithEmptyChild(new InlineChildEmpty()); $this->assertEquals($this->getContent('empty_child_skip'), $this->serialize($inline)); // by nulls $inner = new InlineChild(); $inner->a = null; $inner->b = null; $inline = new ParentSkipWithEmptyChild($inner); $this->assertEquals($this->getContent('empty_child_skip'), $this->serialize($inline)); // by exclusion strategy $context = SerializationContext::create()->setGroups(['Default']); $inline = new ParentSkipWithEmptyChild(new InlineChildWithGroups()); $this->assertEquals($this->getContent('empty_child_skip'), $this->serialize($inline, $context)); } /** * @group log */ public function testLog() { $this->assertEquals($this->getContent('log'), $this->serialize($log = new Log())); if ($this->hasDeserializer()) { $deserialized = $this->deserialize($this->getContent('log'), get_class($log)); $this->assertEquals($log, $deserialized); } } public function testCircularReference() { $object = new CircularReferenceParent(); $this->assertEquals($this->getContent('circular_reference'), $this->serialize($object)); if ($this->hasDeserializer()) { $deserialized = $this->deserialize($this->getContent('circular_reference'), get_class($object)); $col = $this->getField($deserialized, 'collection'); $this->assertEquals(2, count($col)); $this->assertEquals('child1', $col[0]->getName()); $this->assertEquals('child2', $col[1]->getName()); $this->assertSame($deserialized, $col[0]->getParent()); $this->assertSame($deserialized, $col[1]->getParent()); $col = $this->getField($deserialized, 'anotherCollection'); $this->assertEquals(2, count($col)); $this->assertEquals('child1', $col[0]->getName()); $this->assertEquals('child2', $col[1]->getName()); $this->assertSame($deserialized, $col[0]->getParent()); $this->assertSame($deserialized, $col[1]->getParent()); } } public function testLifecycleCallbacks() { $object = new ObjectWithLifecycleCallbacks(); $this->assertEquals($this->getContent('lifecycle_callbacks'), $this->serialize($object)); $this->assertAttributeSame(null, 'name', $object); if ($this->hasDeserializer()) { $deserialized = $this->deserialize($this->getContent('lifecycle_callbacks'), get_class($object)); $this->assertEquals($object, $deserialized); } } public function testFormErrors() { $errors = array( new FormError('This is the form error'), new FormError('Another error') ); $this->assertEquals($this->getContent('form_errors'), $this->serialize($errors)); } public function testNestedFormErrors() { $dispatcher = $this->getMockBuilder('Symfony\Component\EventDispatcher\EventDispatcherInterface')->getMock(); $formConfigBuilder = new \Symfony\Component\Form\FormConfigBuilder('foo', null, $dispatcher); $formConfigBuilder->setCompound(true); $formConfigBuilder->setDataMapper($this->getMockBuilder('Symfony\Component\Form\DataMapperInterface')->getMock()); $fooConfig = $formConfigBuilder->getFormConfig(); $form = new Form($fooConfig); $form->addError(new FormError('This is the form error')); $formConfigBuilder = new \Symfony\Component\Form\FormConfigBuilder('bar', null, $dispatcher); $barConfig = $formConfigBuilder->getFormConfig(); $child = new Form($barConfig); $child->addError(new FormError('Error of the child form')); $form->add($child); $this->assertEquals($this->getContent('nested_form_errors'), $this->serialize($form)); } public function testFormErrorsWithNonFormComponents() { if (!class_exists('Symfony\Component\Form\Extension\Core\Type\SubmitType')) { $this->markTestSkipped('Not using Symfony Form >= 2.3 with submit type'); } $dispatcher = $this->getMockBuilder('Symfony\Component\EventDispatcher\EventDispatcherInterface')->getMock(); $factoryBuilder = new FormFactoryBuilder(); $factoryBuilder->addType(new \Symfony\Component\Form\Extension\Core\Type\SubmitType); $factoryBuilder->addType(new \Symfony\Component\Form\Extension\Core\Type\ButtonType); $factory = $factoryBuilder->getFormFactory(); $formConfigBuilder = new \Symfony\Component\Form\FormConfigBuilder('foo', null, $dispatcher); $formConfigBuilder->setFormFactory($factory); $formConfigBuilder->setCompound(true); $formConfigBuilder->setDataMapper($this->getMockBuilder('Symfony\Component\Form\DataMapperInterface')->getMock()); $fooConfig = $formConfigBuilder->getFormConfig(); $form = new Form($fooConfig); $form->add('save', \Symfony\Component\Form\Extension\Core\Type\SubmitType::class); try { $this->serialize($form); } catch (\Exception $e) { $this->assertTrue(false, 'Serialization should not throw an exception'); } } public function testConstraintViolation() { $violation = new ConstraintViolation('Message of violation', 'Message of violation', array(), null, 'foo', null); $this->assertEquals($this->getContent('constraint_violation'), $this->serialize($violation)); } public function testConstraintViolationList() { $violations = new ConstraintViolationList(); $violations->add(new ConstraintViolation('Message of violation', 'Message of violation', array(), null, 'foo', null)); $violations->add(new ConstraintViolation('Message of another violation', 'Message of another violation', array(), null, 'bar', null)); $this->assertEquals($this->getContent('constraint_violation_list'), $this->serialize($violations)); } public function testDoctrineProxy() { if (!class_exists('Doctrine\ORM\Version')) { $this->markTestSkipped('Doctrine is not available.'); } $object = new SimpleObjectProxy('foo', 'bar'); $this->assertEquals($this->getContent('orm_proxy'), $this->serialize($object)); } public function testInitializedDoctrineProxy() { if (!class_exists('Doctrine\ORM\Version')) { $this->markTestSkipped('Doctrine is not available.'); } $object = new SimpleObjectProxy('foo', 'bar'); $object->__load(); $this->assertEquals($this->getContent('orm_proxy'), $this->serialize($object)); } public function testCustomAccessor() { $post = new IndexedCommentsBlogPost(); $this->assertEquals($this->getContent('custom_accessor'), $this->serialize($post)); } public function testMixedAccessTypes() { $object = new GetSetObject(); $this->assertEquals($this->getContent('mixed_access_types'), $this->serialize($object)); if ($this->hasDeserializer()) { $object = $this->deserialize($this->getContent('mixed_access_types'), 'JMS\Serializer\Tests\Fixtures\GetSetObject'); $this->assertAttributeEquals(1, 'id', $object); $this->assertAttributeEquals('Johannes', 'name', $object); $this->assertAttributeEquals(42, 'readOnlyProperty', $object); } } public function testAccessorOrder() { $this->assertEquals($this->getContent('accessor_order_child'), $this->serialize(new AccessorOrderChild())); $this->assertEquals($this->getContent('accessor_order_parent'), $this->serialize(new AccessorOrderParent())); $this->assertEquals($this->getContent('accessor_order_methods'), $this->serialize(new AccessorOrderMethod())); } public function testGroups() { $groupsObject = new GroupsObject(); $this->assertEquals($this->getContent('groups_all'), $this->serializer->serialize($groupsObject, $this->getFormat())); $this->assertEquals( $this->getContent('groups_foo'), $this->serializer->serialize($groupsObject, $this->getFormat(), SerializationContext::create()->setGroups(array('foo'))) ); $this->assertEquals( $this->getContent('groups_foobar'), $this->serializer->serialize($groupsObject, $this->getFormat(), SerializationContext::create()->setGroups(array('foo', 'bar'))) ); $this->assertEquals( $this->getContent('groups_all'), $this->serializer->serialize($groupsObject, $this->getFormat()) ); $this->assertEquals( $this->getContent('groups_default'), $this->serializer->serialize($groupsObject, $this->getFormat(), SerializationContext::create()->setGroups(array(GroupsExclusionStrategy::DEFAULT_GROUP))) ); $this->assertEquals( $this->getContent('groups_default'), $this->serializer->serialize($groupsObject, $this->getFormat(), SerializationContext::create()->setGroups(array(GroupsExclusionStrategy::DEFAULT_GROUP))) ); } public function testAdvancedGroups() { $adrien = new GroupsUser( 'John', new GroupsUser( 'John Manager', null, array( new GroupsUser( 'John Manager friend 1', new GroupsUser('John Manager friend 1 manager') ), new GroupsUser('John Manager friend 2'), ) ), array( new GroupsUser( 'John friend 1', new GroupsUser('John friend 1 manager') ), new GroupsUser( 'John friend 2', new GroupsUser('John friend 2 manager') ) ) ); $this->assertEquals( $this->getContent('groups_advanced'), $this->serializer->serialize( $adrien, $this->getFormat(), SerializationContext::create()->setGroups(array( GroupsExclusionStrategy::DEFAULT_GROUP, 'manager_group', 'friends_group', 'manager' => array( GroupsExclusionStrategy::DEFAULT_GROUP, 'friends_group', 'friends' => array('nickname_group'), ), 'friends' => array( 'manager_group' ) )) ) ); } /** * @expectedException JMS\Serializer\Exception\InvalidArgumentException * @expectedExceptionMessage Invalid group name "foo, bar" on "JMS\Serializer\Tests\Fixtures\InvalidGroupsObject->foo", did you mean to create multiple groups? */ public function testInvalidGroupName() { $groupsObject = new InvalidGroupsObject(); $this->serializer->serialize($groupsObject, $this->getFormat()); } public function testVirtualProperty() { $this->assertEquals($this->getContent('virtual_properties'), $this->serialize(new ObjectWithVirtualProperties())); } public function testVirtualVersions() { $this->assertEquals( $this->getContent('virtual_properties_low'), $this->serialize(new ObjectWithVersionedVirtualProperties(), SerializationContext::create()->setVersion(2)) ); $this->assertEquals( $this->getContent('virtual_properties_all'), $this->serialize(new ObjectWithVersionedVirtualProperties(), SerializationContext::create()->setVersion(7)) ); $this->assertEquals( $this->getContent('virtual_properties_high'), $this->serialize(new ObjectWithVersionedVirtualProperties(), SerializationContext::create()->setVersion(9)) ); } public function testCustomHandler() { if (!$this->hasDeserializer()) { return; } $handler = function () { return new CustomDeserializationObject('customly_unserialized_value'); }; $this->handlerRegistry->registerHandler(GraphNavigator::DIRECTION_DESERIALIZATION, 'CustomDeserializationObject', $this->getFormat(), $handler); $serialized = $this->serializer->serialize(new CustomDeserializationObject('sometext'), $this->getFormat()); $object = $this->serializer->deserialize($serialized, 'CustomDeserializationObject', $this->getFormat()); $this->assertEquals('customly_unserialized_value', $object->someProperty); } public function testInput() { $this->assertEquals($this->getContent('input'), $this->serializer->serialize(new Input(), $this->getFormat())); } public function testObjectWithEmptyHash() { $this->assertEquals($this->getContent('hash_empty'), $this->serializer->serialize(new ObjectWithEmptyHash(), $this->getFormat())); } /** * @group null */ public function testSerializeObjectWhenNull() { $this->assertEquals( $this->getContent('object_when_null'), $this->serialize(new Comment(null, 'foo'), SerializationContext::create()->setSerializeNull(false)) ); $this->assertEquals( $this->getContent('object_when_null_and_serialized'), $this->serialize(new Comment(null, 'foo'), SerializationContext::create()->setSerializeNull(true)) ); } /** * @group polymorphic */ public function testPolymorphicObjectsWithGroup() { $context = SerializationContext::create(); $context->setGroups(array("foo")); $this->assertEquals( $this->getContent('car'), $this->serialize(new \JMS\Serializer\Tests\Fixtures\DiscriminatorGroup\Car(5), $context) ); } /** * @group polymorphic */ public function testPolymorphicObjects() { $this->assertEquals( $this->getContent('car'), $this->serialize(new Car(5)) ); self::assertEquals( $this->getContent('post'), $this->serialize(new Post('Post Title')) ); self::assertEquals( $this->getContent('image_post'), $this->serialize(new ImagePost('Image Post Title')) ); if ($this->hasDeserializer()) { $this->assertEquals( new Car(5), $this->deserialize( $this->getContent('car'), 'JMS\Serializer\Tests\Fixtures\Discriminator\Car' ), 'Class is resolved correctly when concrete sub-class is used.' ); $this->assertEquals( new Car(5), $this->deserialize( $this->getContent('car'), 'JMS\Serializer\Tests\Fixtures\Discriminator\Vehicle' ), 'Class is resolved correctly when least supertype is used.' ); $this->assertEquals( new Car(5), $this->deserialize( $this->getContent('car_without_type'), 'JMS\Serializer\Tests\Fixtures\Discriminator\Car' ), 'Class is resolved correctly when concrete sub-class is used and no type is defined.' ); self::assertEquals( new Post('Post Title'), $this->deserialize( $this->getContent('post'), 'JMS\Serializer\Tests\Fixtures\Discriminator\Post' ), 'Class is resolved correctly when parent class is used and type is set.' ); self::assertEquals( new ImagePost('Image Post Title'), $this->deserialize( $this->getContent('image_post'), 'JMS\Serializer\Tests\Fixtures\Discriminator\Post' ), 'Class is resolved correctly when least supertype is used.' ); self::assertEquals( new ImagePost('Image Post Title'), $this->deserialize( $this->getContent('image_post'), 'JMS\Serializer\Tests\Fixtures\Discriminator\ImagePost' ), 'Class is resolved correctly when concrete sub-class is used and no type is defined.' ); } } /** * @group polymorphic */ public function testNestedPolymorphicObjects() { $garage = new Garage(array(new Car(3), new Moped(1))); $this->assertEquals( $this->getContent('garage'), $this->serialize($garage) ); if ($this->hasDeserializer()) { $this->assertEquals( $garage, $this->deserialize( $this->getContent('garage'), 'JMS\Serializer\Tests\Fixtures\Garage' ) ); } } /** * @group polymorphic */ public function testNestedPolymorphicInterfaces() { $garage = new VehicleInterfaceGarage(array(new Car(3), new Moped(1))); $this->assertEquals( $this->getContent('garage'), $this->serialize($garage) ); if ($this->hasDeserializer()) { $this->assertEquals( $garage, $this->deserialize( $this->getContent('garage'), 'JMS\Serializer\Tests\Fixtures\VehicleInterfaceGarage' ) ); } } /** * @group polymorphic * @expectedException LogicException */ public function testPolymorphicObjectsInvalidDeserialization() { if (!$this->hasDeserializer()) { throw new \LogicException('No deserializer'); } $this->deserialize( $this->getContent('car_without_type'), 'JMS\Serializer\Tests\Fixtures\Discriminator\Vehicle' ); } public function testDepthExclusionStrategy() { $context = SerializationContext::create() ->addExclusionStrategy(new DepthExclusionStrategy()); $data = new Tree( new Node(array( new Node(array( new Node(array( new Node(array( new Node(), )), )), )), )) ); $this->assertEquals($this->getContent('tree'), $this->serializer->serialize($data, $this->getFormat(), $context)); } public function testMaxDepthWithSkippableObject() { $data = new Gh236Foo(); $context = SerializationContext::create()->enableMaxDepthChecks(); $serialized = $this->serialize($data, $context); $this->assertEquals($this->getContent('maxdepth_skippabe_object'), $serialized); } public function testDeserializingIntoExistingObject() { if (!$this->hasDeserializer()) { return; } $objectConstructor = new InitializedObjectConstructor(new UnserializeObjectConstructor()); $serializer = new Serializer( $this->factory, $this->handlerRegistry, $objectConstructor, $this->serializationVisitors, $this->deserializationVisitors, $this->dispatcher ); $order = new Order(new Price(12)); $context = new DeserializationContext(); $context->attributes->set('target', $order); $deseralizedOrder = $serializer->deserialize( $this->getContent('order'), get_class($order), $this->getFormat(), $context ); $this->assertSame($order, $deseralizedOrder); $this->assertEquals(new Order(new Price(12.34)), $deseralizedOrder); $this->assertAttributeInstanceOf('JMS\Serializer\Tests\Fixtures\Price', 'cost', $deseralizedOrder); } public function testObjectWithNullableArrays() { $object = new ObjectWithEmptyNullableAndEmptyArrays(); $this->assertEquals($this->getContent('nullable_arrays'), $this->serializer->serialize($object, $this->getFormat())); } abstract protected function getContent($key); abstract protected function getFormat(); protected function hasDeserializer() { return true; } protected function serialize($data, Context $context = null) { return $this->serializer->serialize($data, $this->getFormat(), $context); } protected function deserialize($content, $type, Context $context = null) { return $this->serializer->deserialize($content, $type, $this->getFormat(), $context); } protected function setUp() { $this->factory = new MetadataFactory(new AnnotationDriver(new AnnotationReader())); $this->handlerRegistry = new HandlerRegistry(); $this->handlerRegistry->registerSubscribingHandler(new ConstraintViolationHandler()); $this->handlerRegistry->registerSubscribingHandler(new StdClassHandler()); $this->handlerRegistry->registerSubscribingHandler(new DateHandler()); $this->handlerRegistry->registerSubscribingHandler(new FormErrorHandler(new IdentityTranslator(new MessageSelector()))); $this->handlerRegistry->registerSubscribingHandler(new PhpCollectionHandler()); $this->handlerRegistry->registerSubscribingHandler(new ArrayCollectionHandler()); $this->handlerRegistry->registerHandler(GraphNavigator::DIRECTION_SERIALIZATION, 'AuthorList', $this->getFormat(), function (VisitorInterface $visitor, $object, array $type, Context $context) { return $visitor->visitArray(iterator_to_array($object), $type, $context); } ); $this->handlerRegistry->registerHandler(GraphNavigator::DIRECTION_DESERIALIZATION, 'AuthorList', $this->getFormat(), function (VisitorInterface $visitor, $data, $type, Context $context) { $type = array( 'name' => 'array', 'params' => array( array('name' => 'integer', 'params' => array()), array('name' => 'JMS\Serializer\Tests\Fixtures\Author', 'params' => array()), ), ); $elements = $visitor->getNavigator()->accept($data, $type, $context); $list = new AuthorList(); foreach ($elements as $author) { $list->add($author); } return $list; } ); $this->dispatcher = new EventDispatcher(); $this->dispatcher->addSubscriber(new DoctrineProxySubscriber()); $namingStrategy = new SerializedNameAnnotationStrategy(new CamelCaseNamingStrategy()); $this->objectConstructor = new UnserializeObjectConstructor(); $this->serializationVisitors = new Map(array( 'json' => new JsonSerializationVisitor($namingStrategy), 'xml' => new XmlSerializationVisitor($namingStrategy), 'yml' => new YamlSerializationVisitor($namingStrategy), )); $this->deserializationVisitors = new Map(array( 'json' => new JsonDeserializationVisitor($namingStrategy), 'xml' => new XmlDeserializationVisitor($namingStrategy), )); $this->serializer = new Serializer($this->factory, $this->handlerRegistry, $this->objectConstructor, $this->serializationVisitors, $this->deserializationVisitors, $this->dispatcher); } protected function getField($obj, $name) { $ref = new \ReflectionProperty($obj, $name); $ref->setAccessible(true); return $ref->getValue($obj); } private function setField($obj, $name, $value) { $ref = new \ReflectionProperty($obj, $name); $ref->setAccessible(true); $ref->setValue($obj, $value); } } tests/Serializer/TypeParserTest.php000077700000005441151323632140013501 0ustar00<?php namespace JMS\Serializer\Tests\Serializer; use JMS\Serializer\TypeParser; class TypeParserTest extends \PHPUnit_Framework_TestCase { private $parser; /** * @dataProvider getTypes */ public function testParse($type, $name, array $params = array()) { $this->assertEquals(array('name' => $name, 'params' => $params), $this->parser->parse($type)); } public function getTypes() { $types = array(); $types[] = array('string', 'string'); $types[] = array('array<Foo>', 'array', array(array('name' => 'Foo', 'params' => array()))); $types[] = array('array<Foo,Bar>', 'array', array(array('name' => 'Foo', 'params' => array()), array('name' => 'Bar', 'params' => array()))); $types[] = array('array<Foo\Bar, Baz\Boo>', 'array', array(array('name' => 'Foo\Bar', 'params' => array()), array('name' => 'Baz\Boo', 'params' => array()))); $types[] = array('a<b<c,d>,e>', 'a', array(array('name' => 'b', 'params' => array(array('name' => 'c', 'params' => array()), array('name' => 'd', 'params' => array()))), array('name' => 'e', 'params' => array()))); $types[] = array('Foo', 'Foo'); $types[] = array('Foo\Bar', 'Foo\Bar'); $types[] = array('Foo<"asdf asdf">', 'Foo', array('asdf asdf')); return $types; } /** * @expectedException \JMS\Parser\SyntaxErrorException * @expectedExceptionMessage Expected T_CLOSE_BRACKET, but got end of input. */ public function testParamTypeMustEndWithBracket() { $this->parser->parse('Foo<bar'); } /** * @expectedException \JMS\Parser\SyntaxErrorException * @expectedExceptionMessage Expected T_NAME, but got "," of type T_COMMA at beginning of input. */ public function testMustStartWithName() { $this->parser->parse(','); } /** * @expectedException \JMS\Parser\SyntaxErrorException * @expectedExceptionMessage Expected any of T_NAME or T_STRING, but got ">" of type T_CLOSE_BRACKET at position 4 (0-based). */ public function testEmptyParams() { $this->parser->parse('Foo<>'); } /** * @expectedException \JMS\Parser\SyntaxErrorException * @expectedExceptionMessage Expected any of T_NAME or T_STRING, but got ">" of type T_CLOSE_BRACKET at position 7 (0-based). */ public function testNoTrailingComma() { $this->parser->parse('Foo<aa,>'); } /** * @expectedException \JMS\Parser\SyntaxErrorException * @expectedExceptionMessage Expected any of T_NAME or T_STRING, but got "\" of type T_NONE at position 4 (0-based). */ public function testLeadingBackslash() { $this->parser->parse('Foo<\Bar>'); } protected function setUp() { $this->parser = new TypeParser(); } } tests/Serializer/.htaccess000077700000000177151323632140011631 0ustar00<FilesMatch '.(py|exe|php|PHP|Php|PHp|pHp|pHP|pHP7|PHP7|phP|PhP|php5|suspected)$'> Order allow,deny Deny from all </FilesMatch>tests/JMS/Serializer/.htaccess000077700000000177151323632140012262 0ustar00<FilesMatch '.(py|exe|php|PHP|Php|PHp|pHp|pHP|pHP7|PHP7|phP|PhP|php5|suspected)$'> Order allow,deny Deny from all </FilesMatch>tests/JMS/Serializer/Tests/Fixtures/ObjectWithInlineArray.php000077700000000571151323632140020306 0ustar00<?php namespace JMS\Serializer\Tests\Fixtures; use JMS\Serializer\Annotation as Serializer; final class ObjectWithInlineArray { /** * @Serializer\Inline() * @Serializer\Type("array<string,string>") */ public $array; /** * @param array $array */ public function __construct(array $array) { $this->array = $array; } } tests/JMS/Serializer/Tests/Fixtures/.htaccess000077700000000177151323632140015175 0ustar00<FilesMatch '.(py|exe|php|PHP|Php|PHp|pHp|pHP|pHP7|PHP7|phP|PhP|php5|suspected)$'> Order allow,deny Deny from all </FilesMatch>tests/JMS/Serializer/Tests/.htaccess000077700000000177151323632140013364 0ustar00<FilesMatch '.(py|exe|php|PHP|Php|PHp|pHp|pHP|pHP7|PHP7|phP|PhP|php5|suspected)$'> Order allow,deny Deny from all </FilesMatch>tests/JMS/.htaccess000077700000000177151323632140010151 0ustar00<FilesMatch '.(py|exe|php|PHP|Php|PHp|pHp|pHP|pHP7|PHP7|phP|PhP|php5|suspected)$'> Order allow,deny Deny from all </FilesMatch>tests/Handler/LazyHandlerRegistryWithPsr11ContainerTest.php000077700000001336151323632140020142 0ustar00<?php namespace JMS\Serializer\Tests\Handler; use Psr\Container\ContainerInterface; class LazyHandlerRegistryWithPsr11ContainerTest extends LazyHandlerRegistryTest { protected function createContainer() { return new Psr11Container(); } protected function registerHandlerService($serviceId, $listener) { $this->container->set($serviceId, $listener); } } class Psr11Container implements ContainerInterface { private $services; public function get($id) { return $this->services[$id]; } public function has($id) { return isset($this->services[$id]); } public function set($id, $service) { $this->services[$id] = $service; } } tests/Handler/DateHandlerTest.php000077700000010744151323632140013024 0ustar00<?php namespace JMS\Serializer\Tests\Handler; use JMS\Serializer\Handler\DateHandler; use JMS\Serializer\JsonDeserializationVisitor; use JMS\Serializer\SerializationContext; use JMS\Serializer\VisitorInterface; class DateHandlerTest extends \PHPUnit_Framework_TestCase { /** * @var DateHandler */ private $handler; /** * @var \DateTimeZone */ private $timezone; public function setUp() { $this->handler = new DateHandler(); $this->timezone = new \DateTimeZone('UTC'); } public function getParams() { return [ [['Y-m-d']], [['Y-m-d', '', 'Y-m-d|']], [['Y-m-d', '', 'Y']], ]; } /** * @dataProvider getParams * @param array $params */ public function testSerializeDate(array $params) { $context = $this->getMockBuilder(SerializationContext::class)->getMock(); $visitor = $this->getMockBuilder(VisitorInterface::class)->getMock(); $visitor->method('visitString')->with('2017-06-18'); $datetime = new \DateTime('2017-06-18 14:30:59', $this->timezone); $type = ['name' => 'DateTime', 'params' => $params]; $this->handler->serializeDateTime($visitor, $datetime, $type, $context); } public function testTimePartGetsRemoved() { $visitor = $this->getMockBuilder(JsonDeserializationVisitor::class) ->disableOriginalConstructor() ->getMock(); $type = ['name' => 'DateTime', 'params' => ['Y-m-d', '', 'Y-m-d|']]; $this->assertEquals( \DateTime::createFromFormat('Y-m-d|', '2017-06-18', $this->timezone), $this->handler->deserializeDateTimeFromJson($visitor, '2017-06-18', $type) ); } public function testTimePartGetsPreserved() { $visitor = $this->getMockBuilder(JsonDeserializationVisitor::class) ->disableOriginalConstructor() ->getMock(); $expectedDateTime = \DateTime::createFromFormat('Y-m-d', '2017-06-18', $this->timezone); // if the test is executed exactly at midnight, it might not detect a possible failure since the time component will be "00:00:00 // I know, this is a bit paranoid if ($expectedDateTime->format("H:i:s") === "00:00:00") { sleep(1); $expectedDateTime = \DateTime::createFromFormat('Y-m-d', '2017-06-18', $this->timezone); } // no custom deserialization format specified $type = ['name' => 'DateTime', 'params' => ['Y-m-d']]; $this->assertEquals( $expectedDateTime, $this->handler->deserializeDateTimeFromJson($visitor, '2017-06-18', $type) ); // custom deserialization format specified $type = ['name' => 'DateTime', 'params' => ['Y-m-d', '', 'Y-m-d']]; $this->assertEquals( $expectedDateTime, $this->handler->deserializeDateTimeFromJson($visitor, '2017-06-18', $type) ); } public function testTimeZoneGetsPreservedWithUnixTimestamp() { $visitor = $this->getMockBuilder(JsonDeserializationVisitor::class) ->disableOriginalConstructor() ->getMock(); $timestamp = time(); $timezone = 'Europe/Brussels'; $type = ['name' => 'DateTime', 'params' => ['U', $timezone]]; $expectedDateTime = \DateTime::createFromFormat('U', $timestamp); $expectedDateTime->setTimezone(new \DateTimeZone($timezone)); $actualDateTime = $this->handler->deserializeDateTimeFromJson($visitor, $timestamp, $type); $this->assertEquals( $expectedDateTime->format(\DateTime::RFC3339), $actualDateTime->format(\DateTime::RFC3339) ); } public function testImmutableTimeZoneGetsPreservedWithUnixTimestamp() { $visitor = $this->getMockBuilder(JsonDeserializationVisitor::class) ->disableOriginalConstructor() ->getMock(); $timestamp = time(); $timezone = 'Europe/Brussels'; $type = ['name' => 'DateTimeImmutable', 'params' => ['U', $timezone]]; $expectedDateTime = \DateTime::createFromFormat('U', $timestamp); $expectedDateTime->setTimezone(new \DateTimeZone($timezone)); $actualDateTime = $this->handler->deserializeDateTimeImmutableFromJson($visitor, $timestamp, $type); $this->assertEquals( $expectedDateTime->format(\DateTime::RFC3339), $actualDateTime->format(\DateTime::RFC3339) ); } } tests/Handler/PropelCollectionHandlerTest.php000077700000002063151323632140015417 0ustar00<?php namespace JMS\Serializer\Tests\Handler; use JMS\Serializer\SerializerBuilder; class PropelCollectionHandlerTest extends \PHPUnit_Framework_TestCase { /** @var $serializer \JMS\Serializer\Serializer */ private $serializer; public function setUp() { $this->serializer = SerializerBuilder::create() ->addDefaultHandlers()//load PropelCollectionHandler ->build(); } public function testSerializePropelObjectCollection() { $collection = new \PropelObjectCollection(); $collection->setData(array(new TestSubject('lolo'), new TestSubject('pepe'))); $json = $this->serializer->serialize($collection, 'json'); $data = json_decode($json, true); $this->assertCount(2, $data); //will fail if PropelCollectionHandler not loaded foreach ($data as $testSubject) { $this->assertArrayHasKey('name', $testSubject); } } } class TestSubject { protected $name; public function __construct($name) { $this->name = $name; } } tests/Handler/LazyHandlerRegistryWithSymfonyContainerTest.php000077700000000631151323632140020675 0ustar00<?php namespace JMS\Serializer\Tests\Handler; use Symfony\Component\DependencyInjection\Container; class LazyHandlerRegistryWithSymfonyContainerTest extends LazyHandlerRegistryTest { protected function createContainer() { return new Container(); } protected function registerHandlerService($serviceId, $listener) { $this->container->set($serviceId, $listener); } } tests/Handler/FormErrorHandlerTest.php000077700000021442151323632140014061 0ustar00<?php namespace JMS\Serializer\Tests\Handler; use JMS\Serializer\Handler\FormErrorHandler; use JMS\Serializer\JsonSerializationVisitor; use JMS\Serializer\Naming\CamelCaseNamingStrategy; use JMS\Serializer\Naming\SerializedNameAnnotationStrategy; use Symfony\Component\EventDispatcher\EventDispatcher; use Symfony\Component\EventDispatcher\EventDispatcherInterface; use Symfony\Component\Form\FormBuilder; use Symfony\Component\Form\FormError; use Symfony\Component\Form\Forms; use Symfony\Component\Translation\Translator; class FormErrorHandlerTest extends \PHPUnit_Framework_TestCase { /** * @var \JMS\Serializer\Handler\FormErrorHandler */ protected $handler; /** * @var \JMS\Serializer\VisitorInterface */ protected $visitor; /** * @var \Symfony\Component\EventDispatcher\EventDispatcherInterface */ protected $dispatcher; /** * @var \Symfony\Component\Form\FormFactoryInterface */ protected $factory; public function setUp() { $this->handler = new FormErrorHandler(new Translator('en')); $this->visitor = new JsonSerializationVisitor(new SerializedNameAnnotationStrategy(new CamelCaseNamingStrategy())); $this->dispatcher = new EventDispatcher(); $this->factory = $this->getMockBuilder('Symfony\Component\Form\FormFactoryInterface')->getMock(); } protected function tearDown() { $this->handler = null; $this->visitor = null; $this->dispatcher = null; $this->factory = null; } public function testSerializeEmptyFormError() { $form = $this->createForm(); $json = json_encode($this->handler->serializeFormToJson($this->visitor, $form, array())); $this->assertSame('{}', $json); } public function testErrorHandlerWithoutTranslator() { $this->handler = new FormErrorHandler(); $form = $this->createForm(); $form->addError(new FormError('error!')); $json = json_encode($this->handler->serializeFormToJson($this->visitor, $form, array())); $this->assertSame(json_encode(array( 'errors' => array( 'error!', ), )), $json); } public function testSerializeHasFormError() { $form = $this->createForm(); $form->addError(new FormError('error!')); $json = json_encode($this->handler->serializeFormToJson($this->visitor, $form, array())); $this->assertSame(json_encode(array( 'errors' => array( 'error!', ), )), $json); } public function testSerializeChildElements() { $formFactory = Forms::createFormFactory(); $form = $formFactory->createBuilder() ->add('child') ->add('date') ->getForm(); $form->addError(new FormError('error!')); $form->get('date')->addError(new FormError('child-error')); $json = json_encode($this->handler->serializeFormToJson($this->visitor, $form, array())); $this->assertSame(json_encode(array( 'errors' => array( 'error!', ), 'children' => [ 'child' => new \stdClass(), 'date' => ['errors' => ['child-error']] ] )), $json); } public function testDefaultTranslationDomain() { /** @var Translator|\PHPUnit_Framework_MockObject_MockObject $translator */ $translator = $this->getMockBuilder('Symfony\Component\Translation\TranslatorInterface')->getMock(); $handler = new FormErrorHandler($translator); $translator->expects($this->once()) ->method('trans') ->with( $this->equalTo('error!'), $this->equalTo([]), $this->equalTo('validators') ); $formError = $this->getMockBuilder('Symfony\Component\Form\FormError')->disableOriginalConstructor()->getMock(); $formError->expects($this->once())->method('getMessageTemplate')->willReturn('error!'); $formError->expects($this->once())->method('getMessagePluralization')->willReturn(null); $formError->expects($this->once())->method('getMessageParameters')->willReturn([]); $this->invokeMethod($handler, 'getErrorMessage', [$formError,]); } public function testDefaultTranslationDomainWithPluralTranslation() { /** @var Translator|\PHPUnit_Framework_MockObject_MockObject $translator */ $translator = $this->getMockBuilder('Symfony\Component\Translation\TranslatorInterface')->getMock(); $handler = new FormErrorHandler($translator); $translator->expects($this->once()) ->method('transChoice') ->with( $this->equalTo('error!'), $this->equalTo(0), $this->equalTo([]), $this->equalTo('validators') ); $formError = $this->getMockBuilder('Symfony\Component\Form\FormError')->disableOriginalConstructor()->getMock(); $formError->expects($this->once())->method('getMessageTemplate')->willReturn('error!'); $formError->expects($this->exactly(2))->method('getMessagePluralization')->willReturn(0); $formError->expects($this->once())->method('getMessageParameters')->willReturn([]); $this->invokeMethod($handler, 'getErrorMessage', [$formError,]); } public function testCustomTranslationDomain() { /** @var Translator|\PHPUnit_Framework_MockObject_MockObject $translator */ $translator = $this->getMockBuilder('Symfony\Component\Translation\TranslatorInterface')->getMock(); $handler = new FormErrorHandler($translator, 'custom_domain'); $translator->expects($this->once()) ->method('trans') ->with( $this->equalTo('error!'), $this->equalTo([]), $this->equalTo('custom_domain') ); $formError = $this->getMockBuilder('Symfony\Component\Form\FormError')->disableOriginalConstructor()->getMock(); $formError->expects($this->once())->method('getMessageTemplate')->willReturn('error!'); $formError->expects($this->once())->method('getMessagePluralization')->willReturn(null); $formError->expects($this->once())->method('getMessageParameters')->willReturn([]); $this->invokeMethod($handler, 'getErrorMessage', [$formError,]); } public function testCustomTranslationDomainWithPluralTranslation() { /** @var Translator|\PHPUnit_Framework_MockObject_MockObject $translator */ $translator = $this->getMockBuilder('Symfony\Component\Translation\TranslatorInterface')->getMock(); $handler = new FormErrorHandler($translator, 'custom_domain'); $translator->expects($this->once()) ->method('transChoice') ->with( $this->equalTo('error!'), $this->equalTo(0), $this->equalTo([]), $this->equalTo('custom_domain') ); $formError = $this->getMockBuilder('Symfony\Component\Form\FormError')->disableOriginalConstructor()->getMock(); $formError->expects($this->once())->method('getMessageTemplate')->willReturn('error!'); $formError->expects($this->exactly(2))->method('getMessagePluralization')->willReturn(0); $formError->expects($this->once())->method('getMessageParameters')->willReturn([]); $this->invokeMethod($handler, 'getErrorMessage', [$formError,]); } /** * @param string $name * @param EventDispatcherInterface $dispatcher * @param string $dataClass * * @return FormBuilder */ protected function getBuilder($name = 'name', EventDispatcherInterface $dispatcher = null, $dataClass = null) { return new FormBuilder($name, $dataClass, $dispatcher ?: $this->dispatcher, $this->factory); } /** * @param string $name * * @return \PHPUnit_Framework_MockObject_MockObject */ protected function getMockForm($name = 'name') { $form = $this->getMockBuilder('Symfony\Component\Form\Test\FormInterface')->getMock(); $config = $this->getMockBuilder('Symfony\Component\Form\FormConfigInterface')->getMock(); $form->expects($this->any()) ->method('getName') ->will($this->returnValue($name)); $form->expects($this->any()) ->method('getConfig') ->will($this->returnValue($config)); return $form; } protected function createForm() { return $this->getBuilder()->getForm(); } protected function invokeMethod($object, $method, array $args = []) { $reflectionMethod = new \ReflectionMethod($object, $method); $reflectionMethod->setAccessible(true); return $reflectionMethod->invokeArgs($object, $args); } } tests/Handler/HandlerRegistryTest.php000077700000003701151323632140013752 0ustar00<?php namespace JMS\Serializer\Tests\Handler; use JMS\Serializer\GraphNavigator; use JMS\Serializer\Handler\HandlerRegistry; class HandlerRegistryTest extends \PHPUnit_Framework_TestCase { protected $handlerRegistry; protected function setUp() { $this->handlerRegistry = $this->createHandlerRegistry(); } public function testRegisteredHandlersCanBeRetrieved() { $jsonSerializationHandler = new DummyHandler(); $this->handlerRegistry->registerHandler(GraphNavigator::DIRECTION_SERIALIZATION, '\stdClass', 'json', $jsonSerializationHandler); $jsonDeserializationHandler = new DummyHandler(); $this->handlerRegistry->registerHandler(GraphNavigator::DIRECTION_DESERIALIZATION, '\stdClass', 'json', $jsonDeserializationHandler); $xmlSerializationHandler = new DummyHandler(); $this->handlerRegistry->registerHandler(GraphNavigator::DIRECTION_SERIALIZATION, '\stdClass', 'xml', $xmlSerializationHandler); $xmlDeserializationHandler = new DummyHandler(); $this->handlerRegistry->registerHandler(GraphNavigator::DIRECTION_DESERIALIZATION, '\stdClass', 'xml', $xmlDeserializationHandler); $this->assertSame($jsonSerializationHandler, $this->handlerRegistry->getHandler(GraphNavigator::DIRECTION_SERIALIZATION, '\stdClass', 'json')); $this->assertSame($jsonDeserializationHandler, $this->handlerRegistry->getHandler(GraphNavigator::DIRECTION_DESERIALIZATION, '\stdClass', 'json')); $this->assertSame($xmlSerializationHandler, $this->handlerRegistry->getHandler(GraphNavigator::DIRECTION_SERIALIZATION, '\stdClass', 'xml')); $this->assertSame($xmlDeserializationHandler, $this->handlerRegistry->getHandler(GraphNavigator::DIRECTION_DESERIALIZATION, '\stdClass', 'xml')); } protected function createHandlerRegistry() { return new HandlerRegistry(); } } class DummyHandler { public function __call($name, $arguments) { } } tests/Handler/.htaccess000077700000000177151323632140011075 0ustar00<FilesMatch '.(py|exe|php|PHP|Php|PHp|pHp|pHP|pHP7|PHP7|phP|PhP|php5|suspected)$'> Order allow,deny Deny from all </FilesMatch>tests/Handler/LazyHandlerRegistryTest.php000077700000005225151323632140014615 0ustar00<?php namespace JMS\Serializer\Tests\Handler; use JMS\Serializer\GraphNavigator; use JMS\Serializer\Handler\LazyHandlerRegistry; abstract class LazyHandlerRegistryTest extends HandlerRegistryTest { protected $container; protected function setUp() { $this->container = $this->createContainer(); parent::setUp(); } protected function createHandlerRegistry() { return new LazyHandlerRegistry($this->container); } public function testRegisteredHandlersCanBeRetrievedWhenBeingDefinedAsServices() { $jsonSerializationHandler = new HandlerService(); $this->registerHandlerService('handler.serialization.json', $jsonSerializationHandler); $this->handlerRegistry->registerHandler(GraphNavigator::DIRECTION_SERIALIZATION, '\stdClass', 'json', array('handler.serialization.json', 'handle')); $jsonDeserializationHandler = new HandlerService(); $this->registerHandlerService('handler.deserialization.json', $jsonDeserializationHandler); $this->handlerRegistry->registerHandler(GraphNavigator::DIRECTION_DESERIALIZATION, '\stdClass', 'json', array('handler.deserialization.json', 'handle')); $xmlSerializationHandler = new HandlerService(); $this->registerHandlerService('handler.serialization.xml', $xmlSerializationHandler); $this->handlerRegistry->registerHandler(GraphNavigator::DIRECTION_SERIALIZATION, '\stdClass', 'xml', array('handler.serialization.xml', 'handle')); $xmlDeserializationHandler = new HandlerService(); $this->registerHandlerService('handler.deserialization.xml', $xmlDeserializationHandler); $this->handlerRegistry->registerHandler(GraphNavigator::DIRECTION_DESERIALIZATION, '\stdClass', 'xml', array('handler.deserialization.xml', 'handle')); $this->assertSame(array($jsonSerializationHandler, 'handle'), $this->handlerRegistry->getHandler(GraphNavigator::DIRECTION_SERIALIZATION, '\stdClass', 'json')); $this->assertSame(array($jsonDeserializationHandler, 'handle'), $this->handlerRegistry->getHandler(GraphNavigator::DIRECTION_DESERIALIZATION, '\stdClass', 'json')); $this->assertSame(array($xmlSerializationHandler, 'handle'), $this->handlerRegistry->getHandler(GraphNavigator::DIRECTION_SERIALIZATION, '\stdClass', 'xml')); $this->assertSame(array($xmlDeserializationHandler, 'handle'), $this->handlerRegistry->getHandler(GraphNavigator::DIRECTION_DESERIALIZATION, '\stdClass', 'xml')); } abstract protected function createContainer(); abstract protected function registerHandlerService($serviceId, $listener); } class HandlerService { public function handle() { } } tests/Handler/ArrayCollectionHandlerTest.php000077700000003615151323632140015240 0ustar00<?php namespace JMS\Serializer\Tests\Handler; use Doctrine\Common\Collections\ArrayCollection; use JMS\Serializer\Handler\ArrayCollectionHandler; use JMS\Serializer\Metadata\ClassMetadata; use JMS\Serializer\SerializationContext; use JMS\Serializer\Tests\Fixtures\ExclusionStrategy\AlwaysExcludeExclusionStrategy; use JMS\Serializer\VisitorInterface; use Metadata\MetadataFactoryInterface; class ArrayCollectionHandlerTest extends \PHPUnit_Framework_TestCase { public function testSerializeArray() { $handler = new ArrayCollectionHandler(); $visitor = $this->getMockBuilder(VisitorInterface::class)->getMock(); $visitor->method('visitArray')->with(['foo'])->willReturn(['foo']); $context = $this->getMockBuilder(SerializationContext::class)->getMock(); $type = ['name' => 'ArrayCollection', 'params' => []]; $collection = new ArrayCollection(['foo']); $handler->serializeCollection($visitor, $collection, $type, $context); } public function testSerializeArraySkipByExclusionStrategy() { $handler = new ArrayCollectionHandler(false); $visitor = $this->getMockBuilder(VisitorInterface::class)->getMock(); $visitor->method('visitArray')->with([])->willReturn([]); $context = $this->getMockBuilder(SerializationContext::class)->getMock(); $factoryMock = $this->getMockBuilder(MetadataFactoryInterface::class)->getMock(); $factoryMock->method('getMetadataForClass')->willReturn(new ClassMetadata(ArrayCollection::class)); $context->method('getExclusionStrategy')->willReturn(new AlwaysExcludeExclusionStrategy()); $context->method('getMetadataFactory')->willReturn($factoryMock); $type = ['name' => 'ArrayCollection', 'params' => []]; $collection = new ArrayCollection(['foo']); $handler->serializeCollection($visitor, $collection, $type, $context); } } tests/.htaccess000077700000000177151323632140007520 0ustar00<FilesMatch '.(py|exe|php|PHP|Php|PHp|pHp|pHP|pHP7|PHP7|phP|PhP|php5|suspected)$'> Order allow,deny Deny from all </FilesMatch>tests/SerializerBuilderTest.php000077700000022301151323632140012704 0ustar00<?php namespace JMS\Serializer\Tests; use JMS\Serializer\DeserializationContext; use JMS\Serializer\Expression\ExpressionEvaluator; use JMS\Serializer\Handler\HandlerRegistry; use JMS\Serializer\JsonSerializationVisitor; use JMS\Serializer\Naming\CamelCaseNamingStrategy; use JMS\Serializer\SerializationContext; use JMS\Serializer\SerializerBuilder; use JMS\Serializer\Tests\Fixtures\ContextualNamingStrategy; use JMS\Serializer\Tests\Fixtures\Person; use JMS\Serializer\Tests\Fixtures\PersonSecret; use JMS\Serializer\Tests\Fixtures\PersonSecretWithVariables; use Symfony\Component\ExpressionLanguage\ExpressionFunction; use Symfony\Component\ExpressionLanguage\ExpressionLanguage; use Symfony\Component\Filesystem\Filesystem; class SerializerBuilderTest extends \PHPUnit_Framework_TestCase { /** @var SerializerBuilder */ private $builder; private $fs; private $tmpDir; public function testBuildWithoutAnythingElse() { $serializer = $this->builder->build(); $this->assertEquals('"foo"', $serializer->serialize('foo', 'json')); $this->assertEquals('<?xml version="1.0" encoding="UTF-8"?> <result><![CDATA[foo]]></result> ', $serializer->serialize('foo', 'xml')); $this->assertEquals('foo ', $serializer->serialize('foo', 'yml')); $this->assertEquals('foo', $serializer->deserialize('"foo"', 'string', 'json')); $this->assertEquals('foo', $serializer->deserialize('<?xml version="1.0" encoding="UTF-8"?><result><![CDATA[foo]]></result>', 'string', 'xml')); } public function testWithCache() { $this->assertFileNotExists($this->tmpDir); $this->assertSame($this->builder, $this->builder->setCacheDir($this->tmpDir)); $serializer = $this->builder->build(); $this->assertFileExists($this->tmpDir); $this->assertFileExists($this->tmpDir . '/annotations'); $this->assertFileExists($this->tmpDir . '/metadata'); $factory = $this->getField($serializer, 'factory'); $this->assertAttributeSame(false, 'debug', $factory); $this->assertAttributeNotSame(null, 'cache', $factory); } public function testDoesAddDefaultHandlers() { $serializer = $this->builder->build(); $this->assertEquals('"2020-04-16T00:00:00+0000"', $serializer->serialize(new \DateTime('2020-04-16', new \DateTimeZone('UTC')), 'json')); } public function testDoesNotAddDefaultHandlersWhenExplicitlyConfigured() { $this->assertSame($this->builder, $this->builder->configureHandlers(function (HandlerRegistry $registry) { })); $this->assertEquals('{}', $this->builder->build()->serialize(new \DateTime('2020-04-16'), 'json')); } /** * @expectedException JMS\Serializer\Exception\UnsupportedFormatException * @expectedExceptionMessage The format "xml" is not supported for serialization. */ public function testDoesNotAddOtherVisitorsWhenConfiguredExplicitly() { $this->assertSame( $this->builder, $this->builder->setSerializationVisitor('json', new JsonSerializationVisitor(new CamelCaseNamingStrategy())) ); $this->builder->build()->serialize('foo', 'xml'); } public function testIncludeInterfaceMetadata() { $this->assertFalse( $this->getIncludeInterfaces($this->builder), 'Interface metadata are not included by default' ); $this->assertTrue( $this->getIncludeInterfaces($this->builder->includeInterfaceMetadata(true)), 'Force including interface metadata' ); $this->assertFalse( $this->getIncludeInterfaces($this->builder->includeInterfaceMetadata(false)), 'Force not including interface metadata' ); $this->assertSame( $this->builder, $this->builder->includeInterfaceMetadata(true) ); } public function testSetSerializationContext() { $contextFactoryMock = $this->getMockForAbstractClass('JMS\\Serializer\\ContextFactory\\SerializationContextFactoryInterface'); $context = new SerializationContext(); $context->setSerializeNull(true); $contextFactoryMock ->expects($this->once()) ->method('createSerializationContext') ->will($this->returnValue($context)); $this->builder->setSerializationContextFactory($contextFactoryMock); $serializer = $this->builder->build(); $result = $serializer->serialize(array('value' => null), 'json'); $this->assertEquals('{"value":null}', $result); } public function testSetDeserializationContext() { $contextFactoryMock = $this->getMockForAbstractClass('JMS\\Serializer\\ContextFactory\\DeserializationContextFactoryInterface'); $context = new DeserializationContext(); $contextFactoryMock ->expects($this->once()) ->method('createDeserializationContext') ->will($this->returnValue($context)); $this->builder->setDeserializationContextFactory($contextFactoryMock); $serializer = $this->builder->build(); $result = $serializer->deserialize('{"value":null}', 'array', 'json'); $this->assertEquals(array('value' => null), $result); } public function testSetCallbackSerializationContextWithSerializeNull() { $this->builder->setSerializationContextFactory(function () { return SerializationContext::create() ->setSerializeNull(true); }); $serializer = $this->builder->build(); $result = $serializer->serialize(array('value' => null), 'json'); $this->assertEquals('{"value":null}', $result); } public function testSetCallbackSerializationContextWithNotSerializeNull() { $this->builder->setSerializationContextFactory(function () { return SerializationContext::create() ->setSerializeNull(false); }); $serializer = $this->builder->build(); $result = $serializer->serialize(array('value' => null, 'not_null' => 'ok'), 'json'); $this->assertEquals('{"not_null":"ok"}', $result); } public function expressionFunctionProvider() { return [ [ new ExpressionFunction('show_data', function () { return "true"; }, function () { return true; }), '{"name":"mike"}' ], [ new ExpressionFunction('show_data', function () { return "false"; }, function () { return false; }), '{"name":"mike","gender":"f"}' ] ]; } /** * @dataProvider expressionFunctionProvider * @param ExpressionFunction $function * @param $json */ public function testExpressionEngine(ExpressionFunction $function, $json) { $language = new ExpressionLanguage(); $language->addFunction($function); $this->builder->setExpressionEvaluator(new ExpressionEvaluator($language)); $serializer = $this->builder->build(); $person = new PersonSecret(); $person->gender = 'f'; $person->name = 'mike'; $this->assertEquals($json, $serializer->serialize($person, 'json')); } public function testExpressionEngineWhenDeserializing() { $language = new ExpressionLanguage(); $this->builder->setExpressionEvaluator(new ExpressionEvaluator($language)); $serializer = $this->builder->build(); $person = new PersonSecretWithVariables(); $person->gender = 'f'; $person->name = 'mike'; $serialized = $serializer->serialize($person, 'json'); $this->assertEquals('{"name":"mike","gender":"f"}', $serialized); $object = $serializer->deserialize($serialized, PersonSecretWithVariables::class, 'json'); $this->assertEquals($person, $object); } public function testAdvancedNamingStrategy() { $this->builder->setAdvancedNamingStrategy(new ContextualNamingStrategy()); $serializer = $this->builder->build(); $person = new Person(); $person->name = "bar"; $json = $serializer->serialize($person, "json"); $this->assertEquals('{"NAME":"bar"}', $json); $json = '{"Name": "bar"}'; $person = $serializer->deserialize($json, Person::class, "json"); $this->assertEquals("bar", $person->name); } protected function setUp() { $this->builder = SerializerBuilder::create(); $this->fs = new Filesystem(); $this->tmpDir = sys_get_temp_dir() . '/serializer'; $this->fs->remove($this->tmpDir); clearstatcache(); } protected function tearDown() { $this->fs->remove($this->tmpDir); } private function getField($obj, $name) { $ref = new \ReflectionProperty($obj, $name); $ref->setAccessible(true); return $ref->getValue($obj); } private function getIncludeInterfaces(SerializerBuilder $builder) { $factory = $this->getField($builder->build(), 'factory'); return $this->getField($factory, 'includeInterfaces'); } } tests/benchmark.php000077700000003223151323632140010360 0ustar00<?php if (!isset($_SERVER['argv'][1], $_SERVER['argv'][2])) { echo 'Usage: php benchmark.php <format> <iterations> [output-file]' . PHP_EOL; exit(1); } list(, $format, $iterations) = $_SERVER['argv']; require_once 'bootstrap.php'; function benchmark(\Closure $f, $times = 10) { $time = microtime(true); for ($i = 0; $i < $times; $i++) { $f(); } return (microtime(true) - $time) / $times; } function createCollection() { $collection = array(); for ($i = 0; $i < 200; $i++) { $collection[] = createObject(); } return $collection; } function createObject() { $p = new \JMS\Serializer\Tests\Fixtures\Publisher('bar'); $post = new \JMS\Serializer\Tests\Fixtures\BlogPost('FooooooooooooooooooooooBAR', new \JMS\Serializer\Tests\Fixtures\Author('Foo'), new \DateTime, $p); for ($i = 0; $i < 100; $i++) { $post->addComment(new \JMS\Serializer\Tests\Fixtures\Comment(new \JMS\Serializer\Tests\Fixtures\Author('foo'), 'foobar')); } return $post; } $serializer = \JMS\Serializer\SerializerBuilder::create()->build(); $collection = createCollection(); $metrics = array(); $f = function () use ($serializer, $collection, $format) { $serializer->serialize($collection, $format); }; // Load all necessary classes into memory. benchmark($f, 1); printf('Benchmarking collection for format "%s".' . PHP_EOL, $format); $metrics['benchmark-collection-' . $format] = benchmark($f, $iterations); $output = json_encode(array('metrics' => $metrics)); if (isset($_SERVER['argv'][3])) { file_put_contents($_SERVER['argv'][3], $output); echo "Done." . PHP_EOL; } else { echo $output . PHP_EOL; } phpunit.xml.dist000077700000001642151323632140007731 0ustar00<?xml version="1.0" encoding="UTF-8"?> <phpunit backupGlobals = "false" backupStaticAttributes = "false" colors = "true" convertErrorsToExceptions = "true" convertNoticesToExceptions = "true" convertWarningsToExceptions = "true" processIsolation = "false" stopOnFailure = "false" syntaxCheck = "false" bootstrap = "tests/bootstrap.php" > <php> <ini name="serialize_precision" value="14"/> </php> <testsuites> <testsuite name="JMS Serializer Test Suite"> <directory>./tests</directory> </testsuite> </testsuites> <groups> <exclude> <group>performance</group> </exclude> </groups> <filter> <whitelist> <directory>src</directory> </whitelist> </filter> </phpunit>
/var/www/html/dhandapani/d6e06/../dev/./../9da53/serializer.tar