Server IP : 213.176.29.180 / Your IP : 3.149.25.26 Web Server : Apache System : Linux 213.176.29.180.hostiran.name 4.18.0-553.22.1.el8_10.x86_64 #1 SMP Tue Sep 24 05:16:59 EDT 2024 x86_64 User : webtaragh ( 1001) PHP Version : 7.4.33 Disable Function : NONE MySQL : OFF | cURL : ON | WGET : ON | Perl : ON | Python : ON Directory (0750) : /home/webtaragh/public_html/whmcs/assets/../modules/../../ |
[ Home ] | [ C0mmand ] | [ Upload File ] |
---|
serializer/UPGRADING.md 0000644 00000001760 14736103242 0010565 0 ustar 00 From 0.13 to ??? ================ - If you have implemented your own ObjectConstructor, you need to add the DeserializationContext as an additional parameter for the ``construct`` method. From 0.11 to 0.12 ================= - GraphNavigator::detachObject has been removed, you can directly use Context::stopVisiting instead. - VisitorInterface::getNavigator was deprecated, instead use Context::accept - Serializer::setGroups, Serializer::setExclusionStrategy and Serializer::setVersion were removed, these settings must now be passed as part of a new Context object. Before: $serializer->setVersion(1); $serializer->serialize($data, 'json'); After: $serializer->serialize($data, 'json', SerializationContext::create()->setVersion(1)); - All visit??? methods of the VisitorInterface, now require a third argument, the Context; the context is for example passed as an additional argument to handlers, exclusion strategies, and also available in event listeners. serializer/src/JMS/Serializer/Naming/IdenticalPropertyNamingStrategy.php 0000644 00000000427 14736103242 0022513 0 ustar 00 <?php namespace JMS\Serializer\Naming; use JMS\Serializer\Metadata\PropertyMetadata; class IdenticalPropertyNamingStrategy implements PropertyNamingStrategyInterface { public function translateName(PropertyMetadata $property) { return $property->name; } } serializer/src/JMS/Serializer/Naming/PropertyNamingStrategyInterface.php 0000644 00000001063 14736103242 0022514 0 ustar 00 <?php namespace JMS\Serializer\Naming; use JMS\Serializer\Metadata\PropertyMetadata; /** * Interface for property naming strategies. * * Implementations translate the property name to a serialized name that is * displayed. * * @author Johannes M. Schmitt <schmittjoh@gmail.com> */ interface PropertyNamingStrategyInterface { /** * Translates the name of the property to the serialized version. * * @param PropertyMetadata $property * * @return string */ public function translateName(PropertyMetadata $property); } serializer/src/JMS/Serializer/Naming/SerializedNameAnnotationStrategy.php 0000644 00000001344 14736103242 0022646 0 ustar 00 <?php namespace JMS\Serializer\Naming; use JMS\Serializer\Metadata\PropertyMetadata; /** * Naming strategy which uses an annotation to translate the property name. * * @author Johannes M. Schmitt <schmittjoh@gmail.com> */ class SerializedNameAnnotationStrategy implements PropertyNamingStrategyInterface { private $delegate; public function __construct(PropertyNamingStrategyInterface $namingStrategy) { $this->delegate = $namingStrategy; } /** * {@inheritDoc} */ public function translateName(PropertyMetadata $property) { if (null !== $name = $property->serializedName) { return $name; } return $this->delegate->translateName($property); } } serializer/src/JMS/Serializer/Naming/CamelCaseNamingStrategy.php 0000644 00000001464 14736103242 0020671 0 ustar 00 <?php namespace JMS\Serializer\Naming; use JMS\Serializer\Metadata\PropertyMetadata; /** * Generic naming strategy which translates a camel-cased property name. * * @author Johannes M. Schmitt <schmittjoh@gmail.com> */ class CamelCaseNamingStrategy implements PropertyNamingStrategyInterface { private $separator; private $lowerCase; public function __construct($separator = '_', $lowerCase = true) { $this->separator = $separator; $this->lowerCase = $lowerCase; } /** * {@inheritDoc} */ public function translateName(PropertyMetadata $property) { $name = preg_replace('/[A-Z]/', $this->separator . '\\0', $property->name); if ($this->lowerCase) { return strtolower($name); } return ucfirst($name); } } serializer/src/JMS/Serializer/Naming/CacheNamingStrategy.php 0000644 00000001175 14736103242 0020056 0 ustar 00 <?php namespace JMS\Serializer\Naming; use JMS\Serializer\Metadata\PropertyMetadata; class CacheNamingStrategy implements PropertyNamingStrategyInterface { private $delegate; private $cache; public function __construct(PropertyNamingStrategyInterface $delegate) { $this->delegate = $delegate; $this->cache = new \SplObjectStorage(); } public function translateName(PropertyMetadata $property) { if (isset($this->cache[$property])) { return $this->cache[$property]; } return $this->cache[$property] = $this->delegate->translateName($property); } } serializer/src/JMS/Serializer/Naming/AdvancedNamingStrategyInterface.php 0000644 00000001303 14736103242 0022372 0 ustar 00 <?php namespace JMS\Serializer\Naming; use JMS\Serializer\Context; use JMS\Serializer\Metadata\PropertyMetadata; /** * Interface for advanced property naming strategies. * * Implementations translate the property name to a serialized name that is * displayed. It allows advanced strategy thanks to context parameter. * * @author Vincent Rasquier <vincent.rsbs@gmail.com> */ interface AdvancedNamingStrategyInterface { /** * Translates the name of the property to the serialized version. * * @param PropertyMetadata $property * @param Context $context * * @return string */ public function getPropertyName(PropertyMetadata $property, Context $context); } serializer/src/JMS/Serializer/Exclusion/ExpressionLanguageExclusionStrategy.php 0000644 00000002552 14736103242 0024156 0 ustar 00 <?php namespace JMS\Serializer\Exclusion; use JMS\Serializer\Context; use JMS\Serializer\Expression\ExpressionEvaluatorInterface; use JMS\Serializer\Metadata\PropertyMetadata; use JMS\Serializer\SerializationContext; /** * Exposes an exclusion strategy based on the Symfony's expression language. * This is not a standard exclusion strategy and can not be used in user applications. * * @internal * * @author Asmir Mustafic <goetas@gmail.com> */ class ExpressionLanguageExclusionStrategy { /** * @var ExpressionEvaluatorInterface */ private $expressionEvaluator; public function __construct(ExpressionEvaluatorInterface $expressionEvaluator) { $this->expressionEvaluator = $expressionEvaluator; } /** * {@inheritDoc} */ public function shouldSkipProperty(PropertyMetadata $property, Context $navigatorContext) { if (null === $property->excludeIf) { return false; } $variables = [ 'context' => $navigatorContext, 'property_metadata' => $property, ]; if ($navigatorContext instanceof SerializationContext) { $variables['object'] = $navigatorContext->getObject(); } else { $variables['object'] = null; } return $this->expressionEvaluator->evaluate($property->excludeIf, $variables); } } serializer/src/JMS/Serializer/Exclusion/ExclusionStrategyInterface.php 0000644 00000001356 14736103242 0022254 0 ustar 00 <?php namespace JMS\Serializer\Exclusion; use JMS\Serializer\Context; use JMS\Serializer\Metadata\ClassMetadata; use JMS\Serializer\Metadata\PropertyMetadata; /** * Interface for exclusion strategies. * * @author Johannes M. Schmitt <schmittjoh@gmail.com> */ interface ExclusionStrategyInterface { /** * Whether the class should be skipped. * * @param ClassMetadata $metadata * * @return boolean */ public function shouldSkipClass(ClassMetadata $metadata, Context $context); /** * Whether the property should be skipped. * * @param PropertyMetadata $property * * @return boolean */ public function shouldSkipProperty(PropertyMetadata $property, Context $context); } serializer/src/JMS/Serializer/Exclusion/DepthExclusionStrategy.php 0000644 00000002456 14736103242 0021422 0 ustar 00 <?php namespace JMS\Serializer\Exclusion; use JMS\Serializer\Context; use JMS\Serializer\Metadata\ClassMetadata; use JMS\Serializer\Metadata\PropertyMetadata; /** * @author Adrien Brault <adrien.brault@gmail.com> */ class DepthExclusionStrategy implements ExclusionStrategyInterface { /** * {@inheritDoc} */ public function shouldSkipClass(ClassMetadata $metadata, Context $context) { return $this->isTooDeep($context); } /** * {@inheritDoc} */ public function shouldSkipProperty(PropertyMetadata $property, Context $context) { return $this->isTooDeep($context); } private function isTooDeep(Context $context) { $depth = $context->getDepth(); $metadataStack = $context->getMetadataStack(); $nthProperty = 0; // iterate from the first added items to the lasts for ($i = $metadataStack->count() - 1; $i > 0; $i--) { $metadata = $metadataStack[$i]; if ($metadata instanceof PropertyMetadata) { $nthProperty++; $relativeDepth = $depth - $nthProperty; if (null !== $metadata->maxDepth && $relativeDepth > $metadata->maxDepth) { return true; } } } return false; } } serializer/src/JMS/Serializer/Exclusion/GroupsExclusionStrategy.php 0000644 00000005412 14736103242 0021630 0 ustar 00 <?php namespace JMS\Serializer\Exclusion; use JMS\Serializer\Context; use JMS\Serializer\Metadata\ClassMetadata; use JMS\Serializer\Metadata\PropertyMetadata; class GroupsExclusionStrategy implements ExclusionStrategyInterface { const DEFAULT_GROUP = 'Default'; private $groups = array(); private $nestedGroups = false; public function __construct(array $groups) { if (empty($groups)) { $groups = array(self::DEFAULT_GROUP); } foreach ($groups as $group) { if (is_array($group)) { $this->nestedGroups = true; break; } } if ($this->nestedGroups) { $this->groups = $groups; } else { foreach ($groups as $group) { $this->groups[$group] = true; } } } /** * {@inheritDoc} */ public function shouldSkipClass(ClassMetadata $metadata, Context $navigatorContext) { return false; } /** * {@inheritDoc} */ public function shouldSkipProperty(PropertyMetadata $property, Context $navigatorContext) { if ($this->nestedGroups) { $groups = $this->getGroupsFor($navigatorContext); if (!$property->groups) { return !in_array(self::DEFAULT_GROUP, $groups); } return $this->shouldSkipUsingGroups($property, $groups); } else { if (!$property->groups) { return !isset($this->groups[self::DEFAULT_GROUP]); } foreach ($property->groups as $group) { if (isset($this->groups[$group])) { return false; } } return true; } } private function shouldSkipUsingGroups(PropertyMetadata $property, $groups) { foreach ($property->groups as $group) { if (in_array($group, $groups)) { return false; } } return true; } /** * @param Context $navigatorContext * @return array */ public function getGroupsFor(Context $navigatorContext) { if (!$this->nestedGroups) { return array_keys($this->groups); } $paths = $navigatorContext->getCurrentPath(); $groups = $this->groups; foreach ($paths as $index => $path) { if (!array_key_exists($path, $groups)) { if ($index > 0) { $groups = array(self::DEFAULT_GROUP); } break; } $groups = $groups[$path]; if (!array_filter($groups, 'is_string')) { $groups += array(self::DEFAULT_GROUP); } } return $groups; } } serializer/src/JMS/Serializer/Exclusion/VersionExclusionStrategy.php 0000644 00000001707 14736103242 0022001 0 ustar 00 <?php namespace JMS\Serializer\Exclusion; use JMS\Serializer\Context; use JMS\Serializer\Metadata\ClassMetadata; use JMS\Serializer\Metadata\PropertyMetadata; class VersionExclusionStrategy implements ExclusionStrategyInterface { private $version; public function __construct($version) { $this->version = $version; } /** * {@inheritDoc} */ public function shouldSkipClass(ClassMetadata $metadata, Context $navigatorContext) { return false; } /** * {@inheritDoc} */ public function shouldSkipProperty(PropertyMetadata $property, Context $navigatorContext) { if ((null !== $version = $property->sinceVersion) && version_compare($this->version, $version, '<')) { return true; } if ((null !== $version = $property->untilVersion) && version_compare($this->version, $version, '>')) { return true; } return false; } } serializer/src/JMS/Serializer/Exclusion/DisjunctExclusionStrategy.php 0000644 00000003710 14736103242 0022133 0 ustar 00 <?php namespace JMS\Serializer\Exclusion; use JMS\Serializer\Context; use JMS\Serializer\Metadata\ClassMetadata; use JMS\Serializer\Metadata\PropertyMetadata; use PhpCollection\Sequence; use PhpCollection\SequenceInterface; /** * Disjunct Exclusion Strategy. * * This strategy is short-circuiting and will skip a class, or property as soon as one of the delegates skips it. * * @author Johannes M. Schmitt <schmittjoh@gmail.com> */ class DisjunctExclusionStrategy implements ExclusionStrategyInterface { /** @var \PhpCollection\SequenceInterface */ private $delegates; /** * @param ExclusionStrategyInterface[]|SequenceInterface $delegates */ public function __construct($delegates) { if (!$delegates instanceof SequenceInterface) { $delegates = new Sequence($delegates); } $this->delegates = $delegates; } public function addStrategy(ExclusionStrategyInterface $strategy) { $this->delegates->add($strategy); } /** * Whether the class should be skipped. * * @param ClassMetadata $metadata * * @return boolean */ public function shouldSkipClass(ClassMetadata $metadata, Context $context) { foreach ($this->delegates as $delegate) { /** @var $delegate ExclusionStrategyInterface */ if ($delegate->shouldSkipClass($metadata, $context)) { return true; } } return false; } /** * Whether the property should be skipped. * * @param PropertyMetadata $property * * @return boolean */ public function shouldSkipProperty(PropertyMetadata $property, Context $context) { foreach ($this->delegates as $delegate) { /** @var $delegate ExclusionStrategyInterface */ if ($delegate->shouldSkipProperty($property, $context)) { return true; } } return false; } } serializer/src/JMS/Serializer/AbstractVisitor.php 0000644 00000002257 14736103242 0016112 0 ustar 00 <?php namespace JMS\Serializer; use JMS\Serializer\Accessor\AccessorStrategyInterface; use JMS\Serializer\Accessor\DefaultAccessorStrategy; abstract class AbstractVisitor implements VisitorInterface { protected $namingStrategy; /** * @var AccessorStrategyInterface */ protected $accessor; public function __construct($namingStrategy, AccessorStrategyInterface $accessorStrategy = null) { $this->namingStrategy = $namingStrategy; $this->accessor = $accessorStrategy ?: new DefaultAccessorStrategy(); } /** * @deprecated Will be removed in 2.0 * @return mixed */ public function getNamingStrategy() { return $this->namingStrategy; } public function prepare($data) { return $data; } /** * @param array $typeArray */ protected function getElementType($typeArray) { if (false === isset($typeArray['params'][0])) { return null; } if (isset($typeArray['params'][1]) && \is_array($typeArray['params'][1])) { return $typeArray['params'][1]; } else { return $typeArray['params'][0]; } } } serializer/src/JMS/Serializer/GraphNavigator.php 0000644 00000036512 14736103242 0015704 0 ustar 00 <?php namespace JMS\Serializer; use JMS\Serializer\Construction\ObjectConstructorInterface; use JMS\Serializer\EventDispatcher\EventDispatcherInterface; use JMS\Serializer\EventDispatcher\ObjectEvent; use JMS\Serializer\EventDispatcher\PreDeserializeEvent; use JMS\Serializer\EventDispatcher\PreSerializeEvent; use JMS\Serializer\Exception\ExpressionLanguageRequiredException; use JMS\Serializer\Exception\InvalidArgumentException; use JMS\Serializer\Exception\RuntimeException; use JMS\Serializer\Exclusion\ExpressionLanguageExclusionStrategy; use JMS\Serializer\Expression\ExpressionEvaluatorInterface; use JMS\Serializer\Handler\HandlerRegistryInterface; use JMS\Serializer\Metadata\ClassMetadata; use Metadata\MetadataFactoryInterface; /** * Handles traversal along the object graph. * * This class handles traversal along the graph, and calls different methods * on visitors, or custom handlers to process its nodes. * * @author Johannes M. Schmitt <schmittjoh@gmail.com> */ final class GraphNavigator implements GraphNavigatorInterface { /** * @var ExpressionLanguageExclusionStrategy */ private $expressionExclusionStrategy; private $dispatcher; private $metadataFactory; private $handlerRegistry; private $objectConstructor; /** * Parses a direction string to one of the direction constants. * * @param string $dirStr * * @return integer */ public static function parseDirection($dirStr) { switch (strtolower($dirStr)) { case 'serialization': return self::DIRECTION_SERIALIZATION; case 'deserialization': return self::DIRECTION_DESERIALIZATION; default: throw new InvalidArgumentException(sprintf('The direction "%s" does not exist.', $dirStr)); } } public function __construct( MetadataFactoryInterface $metadataFactory, HandlerRegistryInterface $handlerRegistry, ObjectConstructorInterface $objectConstructor, EventDispatcherInterface $dispatcher = null, ExpressionEvaluatorInterface $expressionEvaluator = null ) { $this->dispatcher = $dispatcher; $this->metadataFactory = $metadataFactory; $this->handlerRegistry = $handlerRegistry; $this->objectConstructor = $objectConstructor; if ($expressionEvaluator) { $this->expressionExclusionStrategy = new ExpressionLanguageExclusionStrategy($expressionEvaluator); } } /** * Called for each node of the graph that is being traversed. * * @param mixed $data the data depends on the direction, and type of visitor * @param null|array $type array has the format ["name" => string, "params" => array] * @param Context $context * @return mixed the return value depends on the direction, and type of visitor */ public function accept($data, array $type = null, Context $context) { $visitor = $context->getVisitor(); // If the type was not given, we infer the most specific type from the // input data in serialization mode. if (null === $type) { if ($context instanceof DeserializationContext) { throw new RuntimeException('The type must be given for all properties when deserializing.'); } $typeName = \gettype($data); if ('object' === $typeName) { $typeName = \get_class($data); } $type = array('name' => $typeName, 'params' => array()); } // If the data is null, we have to force the type to null regardless of the input in order to // guarantee correct handling of null values, and not have any internal auto-casting behavior. else if ($context instanceof SerializationContext && null === $data) { $type = array('name' => 'NULL', 'params' => array()); } // Sometimes data can convey null but is not of a null type. // Visitors can have the power to add this custom null evaluation if ($visitor instanceof NullAwareVisitorInterface && $visitor->isNull($data) === true) { $type = array('name' => 'NULL', 'params' => array()); } switch ($type['name']) { case 'NULL': return $visitor->visitNull($data, $type, $context); case 'string': return $visitor->visitString($data, $type, $context); case 'int': case 'integer': return $visitor->visitInteger($data, $type, $context); case 'bool': case 'boolean': return $visitor->visitBoolean($data, $type, $context); case 'double': case 'float': return $visitor->visitDouble($data, $type, $context); case 'array': return $visitor->visitArray($data, $type, $context); case 'resource': $msg = 'Resources are not supported in serialized data.'; if ($context instanceof SerializationContext && null !== $path = $context->getPath()) { $msg .= ' Path: ' . $path; } throw new RuntimeException($msg); default: // TODO: The rest of this method needs some refactoring. if ($context instanceof SerializationContext) { if (null !== $data) { if ($context->isVisiting($data)) { return null; } $context->startVisiting($data); } // If we're serializing a polymorphic type, then we'll be interested in the // metadata for the actual type of the object, not the base class. if (class_exists($type['name'], false) || interface_exists($type['name'], false)) { if (is_subclass_of($data, $type['name'], false)) { $type = array('name' => \get_class($data), 'params' => array()); } } } elseif ($context instanceof DeserializationContext) { $context->increaseDepth(); } // Trigger pre-serialization callbacks, and listeners if they exist. // Dispatch pre-serialization event before handling data to have ability change type in listener if ($context instanceof SerializationContext) { if (null !== $this->dispatcher && $this->dispatcher->hasListeners('serializer.pre_serialize', $type['name'], $context->getFormat())) { $this->dispatcher->dispatch('serializer.pre_serialize', $type['name'], $context->getFormat(), $event = new PreSerializeEvent($context, $data, $type)); $type = $event->getType(); } } elseif ($context instanceof DeserializationContext) { if (null !== $this->dispatcher && $this->dispatcher->hasListeners('serializer.pre_deserialize', $type['name'], $context->getFormat())) { $this->dispatcher->dispatch('serializer.pre_deserialize', $type['name'], $context->getFormat(), $event = new PreDeserializeEvent($context, $data, $type)); $type = $event->getType(); $data = $event->getData(); } } // First, try whether a custom handler exists for the given type. This is done // before loading metadata because the type name might not be a class, but // could also simply be an artifical type. if (null !== $handler = $this->handlerRegistry->getHandler($context->getDirection(), $type['name'], $context->getFormat())) { $rs = \call_user_func($handler, $visitor, $data, $type, $context); $this->leaveScope($context, $data); return $rs; } $exclusionStrategy = $context->getExclusionStrategy(); /** @var $metadata ClassMetadata */ $metadata = $this->metadataFactory->getMetadataForClass($type['name']); if ($metadata->usingExpression && !$this->expressionExclusionStrategy) { throw new ExpressionLanguageRequiredException("To use conditional exclude/expose in {$metadata->name} you must configure the expression language."); } if ($context instanceof DeserializationContext && !empty($metadata->discriminatorMap) && $type['name'] === $metadata->discriminatorBaseClass) { $metadata = $this->resolveMetadata($data, $metadata); } if (null !== $exclusionStrategy && $exclusionStrategy->shouldSkipClass($metadata, $context)) { $this->leaveScope($context, $data); return null; } $context->pushClassMetadata($metadata); if ($context instanceof SerializationContext) { foreach ($metadata->preSerializeMethods as $method) { $method->invoke($data); } } $object = $data; if ($context instanceof DeserializationContext) { $object = $this->objectConstructor->construct($visitor, $metadata, $data, $type, $context); } if (isset($metadata->handlerCallbacks[$context->getDirection()][$context->getFormat()])) { $rs = $object->{$metadata->handlerCallbacks[$context->getDirection()][$context->getFormat()]}( $visitor, $context instanceof SerializationContext ? null : $data, $context ); $this->afterVisitingObject($metadata, $object, $type, $context); return $context instanceof SerializationContext ? $rs : $object; } $visitor->startVisitingObject($metadata, $object, $type, $context); foreach ($metadata->propertyMetadata as $propertyMetadata) { if (null !== $exclusionStrategy && $exclusionStrategy->shouldSkipProperty($propertyMetadata, $context)) { continue; } if (null !== $this->expressionExclusionStrategy && $this->expressionExclusionStrategy->shouldSkipProperty($propertyMetadata, $context)) { continue; } if ($context instanceof DeserializationContext && $propertyMetadata->readOnly) { continue; } $context->pushPropertyMetadata($propertyMetadata); $visitor->visitProperty($propertyMetadata, $data, $context); $context->popPropertyMetadata(); } if ($context instanceof SerializationContext) { $this->afterVisitingObject($metadata, $data, $type, $context); return $visitor->endVisitingObject($metadata, $data, $type, $context); } $rs = $visitor->endVisitingObject($metadata, $data, $type, $context); $this->afterVisitingObject($metadata, $rs, $type, $context); return $rs; } } private function resolveMetadata($data, ClassMetadata $metadata) { switch (true) { case \is_array($data) && isset($data[$metadata->discriminatorFieldName]): $typeValue = (string)$data[$metadata->discriminatorFieldName]; break; // Check XML attribute without namespace for discriminatorFieldName case \is_object($data) && $metadata->xmlDiscriminatorAttribute && null === $metadata->xmlDiscriminatorNamespace && isset($data->attributes()->{$metadata->discriminatorFieldName}): $typeValue = (string)$data->attributes()->{$metadata->discriminatorFieldName}; break; // Check XML attribute with namespace for discriminatorFieldName case \is_object($data) && $metadata->xmlDiscriminatorAttribute && null !== $metadata->xmlDiscriminatorNamespace && isset($data->attributes($metadata->xmlDiscriminatorNamespace)->{$metadata->discriminatorFieldName}): $typeValue = (string)$data->attributes($metadata->xmlDiscriminatorNamespace)->{$metadata->discriminatorFieldName}; break; // Check XML element with namespace for discriminatorFieldName case \is_object($data) && !$metadata->xmlDiscriminatorAttribute && null !== $metadata->xmlDiscriminatorNamespace && isset($data->children($metadata->xmlDiscriminatorNamespace)->{$metadata->discriminatorFieldName}): $typeValue = (string)$data->children($metadata->xmlDiscriminatorNamespace)->{$metadata->discriminatorFieldName}; break; // Check XML element for discriminatorFieldName case \is_object($data) && isset($data->{$metadata->discriminatorFieldName}): $typeValue = (string)$data->{$metadata->discriminatorFieldName}; break; default: throw new \LogicException(sprintf( 'The discriminator field name "%s" for base-class "%s" was not found in input data.', $metadata->discriminatorFieldName, $metadata->name )); } if (!isset($metadata->discriminatorMap[$typeValue])) { throw new \LogicException(sprintf( 'The type value "%s" does not exist in the discriminator map of class "%s". Available types: %s', $typeValue, $metadata->name, implode(', ', array_keys($metadata->discriminatorMap)) )); } return $this->metadataFactory->getMetadataForClass($metadata->discriminatorMap[$typeValue]); } private function leaveScope(Context $context, $data) { if ($context instanceof SerializationContext) { $context->stopVisiting($data); } elseif ($context instanceof DeserializationContext) { $context->decreaseDepth(); } } private function afterVisitingObject(ClassMetadata $metadata, $object, array $type, Context $context) { $this->leaveScope($context, $object); $context->popClassMetadata(); if ($context instanceof SerializationContext) { foreach ($metadata->postSerializeMethods as $method) { $method->invoke($object); } if (null !== $this->dispatcher && $this->dispatcher->hasListeners('serializer.post_serialize', $metadata->name, $context->getFormat())) { $this->dispatcher->dispatch('serializer.post_serialize', $metadata->name, $context->getFormat(), new ObjectEvent($context, $object, $type)); } return; } foreach ($metadata->postDeserializeMethods as $method) { $method->invoke($object); } if (null !== $this->dispatcher && $this->dispatcher->hasListeners('serializer.post_deserialize', $metadata->name, $context->getFormat())) { $this->dispatcher->dispatch('serializer.post_deserialize', $metadata->name, $context->getFormat(), new ObjectEvent($context, $object, $type)); } } } serializer/src/JMS/Serializer/Metadata/Driver/DoctrinePHPCRTypeDriver.php 0000644 00000003745 14736103242 0022327 0 ustar 00 <?php namespace JMS\Serializer\Metadata\Driver; use Doctrine\Common\Persistence\Mapping\ClassMetadata as DoctrineClassMetadata; use JMS\Serializer\Metadata\PropertyMetadata; /** * This class decorates any other driver. If the inner driver does not provide a * a property type, the decorator will guess based on Doctrine 2 metadata. */ class DoctrinePHPCRTypeDriver extends AbstractDoctrineTypeDriver { /** * @param DoctrineClassMetadata $doctrineMetadata * @param PropertyMetadata $propertyMetadata */ protected function hideProperty(DoctrineClassMetadata $doctrineMetadata, PropertyMetadata $propertyMetadata) { return 'lazyPropertiesDefaults' === $propertyMetadata->name || $doctrineMetadata->parentMapping === $propertyMetadata->name || $doctrineMetadata->node === $propertyMetadata->name; } protected function setPropertyType(DoctrineClassMetadata $doctrineMetadata, PropertyMetadata $propertyMetadata) { $propertyName = $propertyMetadata->name; if ($doctrineMetadata->hasField($propertyName) && $fieldType = $this->normalizeFieldType($doctrineMetadata->getTypeOfField($propertyName))) { $field = $doctrineMetadata->getFieldMapping($propertyName); if (!empty($field['multivalue'])) { $fieldType = 'array'; } $propertyMetadata->setType($fieldType); } elseif ($doctrineMetadata->hasAssociation($propertyName)) { try { $targetEntity = $doctrineMetadata->getAssociationTargetClass($propertyName); } catch (\Exception $e) { return; } if (null === $this->tryLoadingDoctrineMetadata($targetEntity)) { return; } if (!$doctrineMetadata->isSingleValuedAssociation($propertyName)) { $targetEntity = "ArrayCollection<{$targetEntity}>"; } $propertyMetadata->setType($targetEntity); } } } serializer/src/JMS/Serializer/Metadata/Driver/AnnotationDriver.php 0000644 00000027075 14736103242 0021235 0 ustar 00 <?php namespace JMS\Serializer\Metadata\Driver; use Doctrine\Common\Annotations\Reader; use JMS\Serializer\Annotation\Accessor; use JMS\Serializer\Annotation\AccessorOrder; use JMS\Serializer\Annotation\AccessType; use JMS\Serializer\Annotation\Discriminator; use JMS\Serializer\Annotation\Exclude; use JMS\Serializer\Annotation\ExcludeIf; use JMS\Serializer\Annotation\ExclusionPolicy; use JMS\Serializer\Annotation\Expose; use JMS\Serializer\Annotation\Groups; use JMS\Serializer\Annotation\HandlerCallback; use JMS\Serializer\Annotation\Inline; use JMS\Serializer\Annotation\MaxDepth; use JMS\Serializer\Annotation\PostDeserialize; use JMS\Serializer\Annotation\PostSerialize; use JMS\Serializer\Annotation\PreSerialize; use JMS\Serializer\Annotation\ReadOnlyProperty; use JMS\Serializer\Annotation\SerializedName; use JMS\Serializer\Annotation\Since; use JMS\Serializer\Annotation\SkipWhenEmpty; use JMS\Serializer\Annotation\Type; use JMS\Serializer\Annotation\Until; use JMS\Serializer\Annotation\VirtualProperty; use JMS\Serializer\Annotation\XmlAttribute; use JMS\Serializer\Annotation\XmlAttributeMap; use JMS\Serializer\Annotation\XmlDiscriminator; use JMS\Serializer\Annotation\XmlElement; use JMS\Serializer\Annotation\XmlKeyValuePairs; use JMS\Serializer\Annotation\XmlList; use JMS\Serializer\Annotation\XmlMap; use JMS\Serializer\Annotation\XmlNamespace; use JMS\Serializer\Annotation\XmlRoot; use JMS\Serializer\Annotation\XmlValue; use JMS\Serializer\Exception\InvalidArgumentException; use JMS\Serializer\GraphNavigator; use JMS\Serializer\Metadata\ClassMetadata; use JMS\Serializer\Metadata\ExpressionPropertyMetadata; use JMS\Serializer\Metadata\PropertyMetadata; use JMS\Serializer\Metadata\VirtualPropertyMetadata; use Metadata\Driver\DriverInterface; use Metadata\MethodMetadata; class AnnotationDriver implements DriverInterface { private $reader; public function __construct(Reader $reader) { $this->reader = $reader; } public function loadMetadataForClass(\ReflectionClass $class) { $classMetadata = new ClassMetadata($name = $class->name); $classMetadata->fileResources[] = $class->getFilename(); $propertiesMetadata = array(); $propertiesAnnotations = array(); $exclusionPolicy = 'NONE'; $excludeAll = false; $classAccessType = PropertyMetadata::ACCESS_TYPE_PROPERTY; $readOnlyClass = false; foreach ($this->reader->getClassAnnotations($class) as $annot) { if ($annot instanceof ExclusionPolicy) { $exclusionPolicy = $annot->policy; } elseif ($annot instanceof XmlRoot) { $classMetadata->xmlRootName = $annot->name; $classMetadata->xmlRootNamespace = $annot->namespace; } elseif ($annot instanceof XmlNamespace) { $classMetadata->registerNamespace($annot->uri, $annot->prefix); } elseif ($annot instanceof Exclude) { $excludeAll = true; } elseif ($annot instanceof AccessType) { $classAccessType = $annot->type; } elseif ($annot instanceof ReadOnlyProperty) { $readOnlyClass = true; } elseif ($annot instanceof AccessorOrder) { $classMetadata->setAccessorOrder($annot->order, $annot->custom); } elseif ($annot instanceof Discriminator) { if ($annot->disabled) { $classMetadata->discriminatorDisabled = true; } else { $classMetadata->setDiscriminator($annot->field, $annot->map, $annot->groups); } } elseif ($annot instanceof XmlDiscriminator) { $classMetadata->xmlDiscriminatorAttribute = (bool)$annot->attribute; $classMetadata->xmlDiscriminatorCData = (bool)$annot->cdata; $classMetadata->xmlDiscriminatorNamespace = $annot->namespace ? (string)$annot->namespace : null; } elseif ($annot instanceof VirtualProperty) { $virtualPropertyMetadata = new ExpressionPropertyMetadata($name, $annot->name, $annot->exp); $propertiesMetadata[] = $virtualPropertyMetadata; $propertiesAnnotations[] = $annot->options; } } foreach ($class->getMethods() as $method) { if ($method->class !== $name) { continue; } $methodAnnotations = $this->reader->getMethodAnnotations($method); foreach ($methodAnnotations as $annot) { if ($annot instanceof PreSerialize) { $classMetadata->addPreSerializeMethod(new MethodMetadata($name, $method->name)); continue 2; } elseif ($annot instanceof PostDeserialize) { $classMetadata->addPostDeserializeMethod(new MethodMetadata($name, $method->name)); continue 2; } elseif ($annot instanceof PostSerialize) { $classMetadata->addPostSerializeMethod(new MethodMetadata($name, $method->name)); continue 2; } elseif ($annot instanceof VirtualProperty) { $virtualPropertyMetadata = new VirtualPropertyMetadata($name, $method->name); $propertiesMetadata[] = $virtualPropertyMetadata; $propertiesAnnotations[] = $methodAnnotations; continue 2; } elseif ($annot instanceof HandlerCallback) { $classMetadata->addHandlerCallback(GraphNavigator::parseDirection($annot->direction), $annot->format, $method->name); continue 2; } } } if (!$excludeAll) { foreach ($class->getProperties() as $property) { if ($property->class !== $name || (isset($property->info) && $property->info['class'] !== $name)) { continue; } $propertiesMetadata[] = new PropertyMetadata($name, $property->getName()); $propertiesAnnotations[] = $this->reader->getPropertyAnnotations($property); } foreach ($propertiesMetadata as $propertyKey => $propertyMetadata) { $isExclude = false; $isExpose = $propertyMetadata instanceof VirtualPropertyMetadata || $propertyMetadata instanceof ExpressionPropertyMetadata; $propertyMetadata->readOnly = $propertyMetadata->readOnly || $readOnlyClass; $accessType = $classAccessType; $accessor = array(null, null); $propertyAnnotations = $propertiesAnnotations[$propertyKey]; foreach ($propertyAnnotations as $annot) { if ($annot instanceof Since) { $propertyMetadata->sinceVersion = $annot->version; } elseif ($annot instanceof Until) { $propertyMetadata->untilVersion = $annot->version; } elseif ($annot instanceof SerializedName) { $propertyMetadata->serializedName = $annot->name; } elseif ($annot instanceof SkipWhenEmpty) { $propertyMetadata->skipWhenEmpty = true; } elseif ($annot instanceof Expose) { $isExpose = true; if (null !== $annot->if) { $propertyMetadata->excludeIf = "!(" . $annot->if . ")"; } } elseif ($annot instanceof Exclude) { if (null !== $annot->if) { $propertyMetadata->excludeIf = $annot->if; } else { $isExclude = true; } } elseif ($annot instanceof Type) { $propertyMetadata->setType($annot->name); } elseif ($annot instanceof XmlElement) { $propertyMetadata->xmlAttribute = false; $propertyMetadata->xmlElementCData = $annot->cdata; $propertyMetadata->xmlNamespace = $annot->namespace; } elseif ($annot instanceof XmlList) { $propertyMetadata->xmlCollection = true; $propertyMetadata->xmlCollectionInline = $annot->inline; $propertyMetadata->xmlEntryName = $annot->entry; $propertyMetadata->xmlEntryNamespace = $annot->namespace; $propertyMetadata->xmlCollectionSkipWhenEmpty = $annot->skipWhenEmpty; } elseif ($annot instanceof XmlMap) { $propertyMetadata->xmlCollection = true; $propertyMetadata->xmlCollectionInline = $annot->inline; $propertyMetadata->xmlEntryName = $annot->entry; $propertyMetadata->xmlEntryNamespace = $annot->namespace; $propertyMetadata->xmlKeyAttribute = $annot->keyAttribute; } elseif ($annot instanceof XmlKeyValuePairs) { $propertyMetadata->xmlKeyValuePairs = true; } elseif ($annot instanceof XmlAttribute) { $propertyMetadata->xmlAttribute = true; $propertyMetadata->xmlNamespace = $annot->namespace; } elseif ($annot instanceof XmlValue) { $propertyMetadata->xmlValue = true; $propertyMetadata->xmlElementCData = $annot->cdata; } elseif ($annot instanceof XmlElement) { $propertyMetadata->xmlElementCData = $annot->cdata; } elseif ($annot instanceof AccessType) { $accessType = $annot->type; } elseif ($annot instanceof ReadOnlyProperty) { $propertyMetadata->readOnly = $annot->readOnly; } elseif ($annot instanceof Accessor) { $accessor = array($annot->getter, $annot->setter); } elseif ($annot instanceof Groups) { $propertyMetadata->groups = $annot->groups; foreach ((array)$propertyMetadata->groups as $groupName) { if (false !== strpos($groupName, ',')) { throw new InvalidArgumentException(sprintf( 'Invalid group name "%s" on "%s", did you mean to create multiple groups?', implode(', ', $propertyMetadata->groups), $propertyMetadata->class . '->' . $propertyMetadata->name )); } } } elseif ($annot instanceof Inline) { $propertyMetadata->inline = true; } elseif ($annot instanceof XmlAttributeMap) { $propertyMetadata->xmlAttributeMap = true; } elseif ($annot instanceof MaxDepth) { $propertyMetadata->maxDepth = $annot->depth; } } if ((ExclusionPolicy::NONE === $exclusionPolicy && !$isExclude) || (ExclusionPolicy::ALL === $exclusionPolicy && $isExpose) ) { $propertyMetadata->setAccessor($accessType, $accessor[0], $accessor[1]); $classMetadata->addPropertyMetadata($propertyMetadata); } } } return $classMetadata; } } serializer/src/JMS/Serializer/Metadata/Driver/NullDriver.php 0000644 00000000644 14736103242 0020026 0 ustar 00 <?php namespace JMS\Serializer\Metadata\Driver; use JMS\Serializer\Metadata\ClassMetadata; use Metadata\Driver\DriverInterface; class NullDriver implements DriverInterface { public function loadMetadataForClass(\ReflectionClass $class) { $classMetadata = new ClassMetadata($name = $class->name); $classMetadata->fileResources[] = $class->getFilename(); return $classMetadata; } } serializer/src/JMS/Serializer/Metadata/Driver/AbstractDoctrineTypeDriver.php 0000644 00000011052 14736103242 0023204 0 ustar 00 <?php namespace JMS\Serializer\Metadata\Driver; use Doctrine\Common\Persistence\ManagerRegistry; use Doctrine\Common\Persistence\Mapping\ClassMetadata as DoctrineClassMetadata; use JMS\Serializer\Metadata\ClassMetadata; use JMS\Serializer\Metadata\ExpressionPropertyMetadata; use JMS\Serializer\Metadata\PropertyMetadata; use JMS\Serializer\Metadata\StaticPropertyMetadata; use JMS\Serializer\Metadata\VirtualPropertyMetadata; use Metadata\Driver\DriverInterface; /** * This class decorates any other driver. If the inner driver does not provide a * a property type, the decorator will guess based on Doctrine 2 metadata. */ abstract class AbstractDoctrineTypeDriver implements DriverInterface { /** * Map of doctrine 2 field types to JMS\Serializer types * @var array */ protected $fieldMapping = array( 'string' => 'string', 'text' => 'string', 'blob' => 'string', 'guid' => 'string', 'integer' => 'integer', 'smallint' => 'integer', 'bigint' => 'integer', 'datetime' => 'DateTime', 'datetimetz' => 'DateTime', 'time' => 'DateTime', 'date' => 'DateTime', 'float' => 'float', 'decimal' => 'float', 'boolean' => 'boolean', 'array' => 'array', 'json_array' => 'array', 'simple_array' => 'array<string>', ); /** * @var DriverInterface */ protected $delegate; /** * @var ManagerRegistry */ protected $registry; public function __construct(DriverInterface $delegate, ManagerRegistry $registry) { $this->delegate = $delegate; $this->registry = $registry; } public function loadMetadataForClass(\ReflectionClass $class) { /** @var $classMetadata ClassMetadata */ $classMetadata = $this->delegate->loadMetadataForClass($class); // Abort if the given class is not a mapped entity if (!$doctrineMetadata = $this->tryLoadingDoctrineMetadata($class->name)) { return $classMetadata; } $this->setDiscriminator($doctrineMetadata, $classMetadata); // We base our scan on the internal driver's property list so that we // respect any internal white/blacklisting like in the AnnotationDriver foreach ($classMetadata->propertyMetadata as $key => $propertyMetadata) { /** @var $propertyMetadata PropertyMetadata */ // If the inner driver provides a type, don't guess anymore. if ($propertyMetadata->type || $this->isVirtualProperty($propertyMetadata)) { continue; } if ($this->hideProperty($doctrineMetadata, $propertyMetadata)) { unset($classMetadata->propertyMetadata[$key]); } $this->setPropertyType($doctrineMetadata, $propertyMetadata); } return $classMetadata; } private function isVirtualProperty(PropertyMetadata $propertyMetadata) { return $propertyMetadata instanceof VirtualPropertyMetadata || $propertyMetadata instanceof StaticPropertyMetadata || $propertyMetadata instanceof ExpressionPropertyMetadata; } /** * @param DoctrineClassMetadata $doctrineMetadata * @param ClassMetadata $classMetadata */ protected function setDiscriminator(DoctrineClassMetadata $doctrineMetadata, ClassMetadata $classMetadata) { } /** * @param DoctrineClassMetadata $doctrineMetadata * @param PropertyMetadata $propertyMetadata */ protected function hideProperty(DoctrineClassMetadata $doctrineMetadata, PropertyMetadata $propertyMetadata) { return false; } /** * @param DoctrineClassMetadata $doctrineMetadata * @param PropertyMetadata $propertyMetadata */ protected function setPropertyType(DoctrineClassMetadata $doctrineMetadata, PropertyMetadata $propertyMetadata) { } /** * @param string $className * * @return null|DoctrineClassMetadata */ protected function tryLoadingDoctrineMetadata($className) { if (!$manager = $this->registry->getManagerForClass($className)) { return null; } if ($manager->getMetadataFactory()->isTransient($className)) { return null; } return $manager->getClassMetadata($className); } /** * @param string $type */ protected function normalizeFieldType($type) { if (!isset($this->fieldMapping[$type])) { return; } return $this->fieldMapping[$type]; } } serializer/src/JMS/Serializer/Metadata/Driver/PhpDriver.php 0000644 00000001631 14736103242 0017640 0 ustar 00 <?php namespace JMS\Serializer\Metadata\Driver; use JMS\Serializer\Exception\RuntimeException; use JMS\Serializer\Metadata\ClassMetadata; use Metadata\Driver\AbstractFileDriver; class PhpDriver extends AbstractFileDriver { protected function loadMetadataFromFile(\ReflectionClass $class, $file) { $metadata = require $file; if (!$metadata instanceof ClassMetadata) { throw new RuntimeException(sprintf('The file %s was expected to return an instance of ClassMetadata, but returned %s.', $file, json_encode($metadata))); } if ($metadata->name !== $class->name) { throw new RuntimeException(sprintf('The file %s was expected to return metadata for class %s, but instead returned metadata for class %s.', $class->name, $metadata->name)); } return $metadata; } protected function getExtension() { return 'php'; } } serializer/src/JMS/Serializer/Metadata/Driver/XmlDriver.php 0000644 00000036402 14736103242 0017655 0 ustar 00 <?php namespace JMS\Serializer\Metadata\Driver; use JMS\Serializer\Annotation\ExclusionPolicy; use JMS\Serializer\Exception\RuntimeException; use JMS\Serializer\Exception\XmlErrorException; use JMS\Serializer\GraphNavigator; use JMS\Serializer\Metadata\ClassMetadata; use JMS\Serializer\Metadata\ExpressionPropertyMetadata; use JMS\Serializer\Metadata\PropertyMetadata; use JMS\Serializer\Metadata\VirtualPropertyMetadata; use Metadata\Driver\AbstractFileDriver; use Metadata\MethodMetadata; class XmlDriver extends AbstractFileDriver { protected function loadMetadataFromFile(\ReflectionClass $class, $path) { $previous = libxml_use_internal_errors(true); libxml_clear_errors(); $elem = simplexml_load_file($path); libxml_use_internal_errors($previous); if (false === $elem) { throw new XmlErrorException(libxml_get_last_error()); } $metadata = new ClassMetadata($name = $class->name); if (!$elems = $elem->xpath("./class[@name = '" . $name . "']")) { throw new RuntimeException(sprintf('Could not find class %s inside XML element.', $name)); } $elem = reset($elems); $metadata->fileResources[] = $path; $metadata->fileResources[] = $class->getFileName(); $exclusionPolicy = strtoupper($elem->attributes()->{'exclusion-policy'}) ?: 'NONE'; $excludeAll = null !== ($exclude = $elem->attributes()->exclude) ? 'true' === strtolower($exclude) : false; $classAccessType = (string)($elem->attributes()->{'access-type'} ?: PropertyMetadata::ACCESS_TYPE_PROPERTY); $propertiesMetadata = array(); $propertiesNodes = array(); if (null !== $accessorOrder = $elem->attributes()->{'accessor-order'}) { $metadata->setAccessorOrder((string)$accessorOrder, preg_split('/\s*,\s*/', (string)$elem->attributes()->{'custom-accessor-order'})); } if (null !== $xmlRootName = $elem->attributes()->{'xml-root-name'}) { $metadata->xmlRootName = (string)$xmlRootName; } if (null !== $xmlRootNamespace = $elem->attributes()->{'xml-root-namespace'}) { $metadata->xmlRootNamespace = (string)$xmlRootNamespace; } $readOnlyClass = 'true' === strtolower($elem->attributes()->{'read-only'}); $discriminatorFieldName = (string)$elem->attributes()->{'discriminator-field-name'}; $discriminatorMap = array(); foreach ($elem->xpath('./discriminator-class') as $entry) { if (!isset($entry->attributes()->value)) { throw new RuntimeException('Each discriminator-class element must have a "value" attribute.'); } $discriminatorMap[(string)$entry->attributes()->value] = (string)$entry; } if ('true' === (string)$elem->attributes()->{'discriminator-disabled'}) { $metadata->discriminatorDisabled = true; } elseif (!empty($discriminatorFieldName) || !empty($discriminatorMap)) { $discriminatorGroups = array(); foreach ($elem->xpath('./discriminator-groups/group') as $entry) { $discriminatorGroups[] = (string)$entry; } $metadata->setDiscriminator($discriminatorFieldName, $discriminatorMap, $discriminatorGroups); } foreach ($elem->xpath('./xml-namespace') as $xmlNamespace) { if (!isset($xmlNamespace->attributes()->uri)) { throw new RuntimeException('The prefix attribute must be set for all xml-namespace elements.'); } if (isset($xmlNamespace->attributes()->prefix)) { $prefix = (string)$xmlNamespace->attributes()->prefix; } else { $prefix = null; } $metadata->registerNamespace((string)$xmlNamespace->attributes()->uri, $prefix); } foreach ($elem->xpath('./xml-discriminator') as $xmlDiscriminator) { if (isset($xmlDiscriminator->attributes()->attribute)) { $metadata->xmlDiscriminatorAttribute = (string)$xmlDiscriminator->attributes()->attribute === 'true'; } if (isset($xmlDiscriminator->attributes()->cdata)) { $metadata->xmlDiscriminatorCData = (string)$xmlDiscriminator->attributes()->cdata === 'true'; } if (isset($xmlDiscriminator->attributes()->namespace)) { $metadata->xmlDiscriminatorNamespace = (string)$xmlDiscriminator->attributes()->namespace; } } foreach ($elem->xpath('./virtual-property') as $method) { if (isset($method->attributes()->expression)) { $virtualPropertyMetadata = new ExpressionPropertyMetadata($name, (string)$method->attributes()->name, (string)$method->attributes()->expression); } else { if (!isset($method->attributes()->method)) { throw new RuntimeException('The method attribute must be set for all virtual-property elements.'); } $virtualPropertyMetadata = new VirtualPropertyMetadata($name, (string)$method->attributes()->method); } $propertiesMetadata[] = $virtualPropertyMetadata; $propertiesNodes[] = $method; } if (!$excludeAll) { foreach ($class->getProperties() as $property) { if ($property->class !== $name || (isset($property->info) && $property->info['class'] !== $name)) { continue; } $propertiesMetadata[] = new PropertyMetadata($name, $pName = $property->getName()); $pElems = $elem->xpath("./property[@name = '" . $pName . "']"); $propertiesNodes[] = $pElems ? reset($pElems) : null; } foreach ($propertiesMetadata as $propertyKey => $pMetadata) { $isExclude = false; $isExpose = $pMetadata instanceof VirtualPropertyMetadata || $pMetadata instanceof ExpressionPropertyMetadata; $pElem = $propertiesNodes[$propertyKey]; if (!empty($pElem)) { if (null !== $exclude = $pElem->attributes()->exclude) { $isExclude = 'true' === strtolower($exclude); } if ($isExclude) { continue; } if (null !== $expose = $pElem->attributes()->expose) { $isExpose = 'true' === strtolower($expose); } if (null !== $excludeIf = $pElem->attributes()->{'exclude-if'}) { $pMetadata->excludeIf = (string)$excludeIf; } if (null !== $skip = $pElem->attributes()->{'skip-when-empty'}) { $pMetadata->skipWhenEmpty = 'true' === strtolower($skip); } if (null !== $excludeIf = $pElem->attributes()->{'expose-if'}) { $pMetadata->excludeIf = "!(" . $excludeIf . ")"; $isExpose = true; } if (null !== $version = $pElem->attributes()->{'since-version'}) { $pMetadata->sinceVersion = (string)$version; } if (null !== $version = $pElem->attributes()->{'until-version'}) { $pMetadata->untilVersion = (string)$version; } if (null !== $serializedName = $pElem->attributes()->{'serialized-name'}) { $pMetadata->serializedName = (string)$serializedName; } if (null !== $type = $pElem->attributes()->type) { $pMetadata->setType((string)$type); } elseif (isset($pElem->type)) { $pMetadata->setType((string)$pElem->type); } if (null !== $groups = $pElem->attributes()->groups) { $pMetadata->groups = preg_split('/\s*,\s*/', (string) trim($groups)); } elseif (isset($pElem->groups)) { $pMetadata->groups = (array) $pElem->groups->value; } if (isset($pElem->{'xml-list'})) { $pMetadata->xmlCollection = true; $colConfig = $pElem->{'xml-list'}; if (isset($colConfig->attributes()->inline)) { $pMetadata->xmlCollectionInline = 'true' === (string)$colConfig->attributes()->inline; } if (isset($colConfig->attributes()->{'entry-name'})) { $pMetadata->xmlEntryName = (string)$colConfig->attributes()->{'entry-name'}; } if (isset($colConfig->attributes()->{'skip-when-empty'})) { $pMetadata->xmlCollectionSkipWhenEmpty = 'true' === (string)$colConfig->attributes()->{'skip-when-empty'}; } else { $pMetadata->xmlCollectionSkipWhenEmpty = true; } if (isset($colConfig->attributes()->namespace)) { $pMetadata->xmlEntryNamespace = (string)$colConfig->attributes()->namespace; } } if (isset($pElem->{'xml-map'})) { $pMetadata->xmlCollection = true; $colConfig = $pElem->{'xml-map'}; if (isset($colConfig->attributes()->inline)) { $pMetadata->xmlCollectionInline = 'true' === (string)$colConfig->attributes()->inline; } if (isset($colConfig->attributes()->{'entry-name'})) { $pMetadata->xmlEntryName = (string)$colConfig->attributes()->{'entry-name'}; } if (isset($colConfig->attributes()->namespace)) { $pMetadata->xmlEntryNamespace = (string)$colConfig->attributes()->namespace; } if (isset($colConfig->attributes()->{'key-attribute-name'})) { $pMetadata->xmlKeyAttribute = (string)$colConfig->attributes()->{'key-attribute-name'}; } } if (isset($pElem->{'xml-element'})) { $colConfig = $pElem->{'xml-element'}; if (isset($colConfig->attributes()->cdata)) { $pMetadata->xmlElementCData = 'true' === (string)$colConfig->attributes()->cdata; } if (isset($colConfig->attributes()->namespace)) { $pMetadata->xmlNamespace = (string)$colConfig->attributes()->namespace; } } if (isset($pElem->attributes()->{'xml-attribute'})) { $pMetadata->xmlAttribute = 'true' === (string)$pElem->attributes()->{'xml-attribute'}; } if (isset($pElem->attributes()->{'xml-attribute-map'})) { $pMetadata->xmlAttributeMap = 'true' === (string)$pElem->attributes()->{'xml-attribute-map'}; } if (isset($pElem->attributes()->{'xml-value'})) { $pMetadata->xmlValue = 'true' === (string)$pElem->attributes()->{'xml-value'}; } if (isset($pElem->attributes()->{'xml-key-value-pairs'})) { $pMetadata->xmlKeyValuePairs = 'true' === (string)$pElem->attributes()->{'xml-key-value-pairs'}; } if (isset($pElem->attributes()->{'max-depth'})) { $pMetadata->maxDepth = (int)$pElem->attributes()->{'max-depth'}; } //we need read-only before setter and getter set, because that method depends on flag being set if (null !== $readOnly = $pElem->attributes()->{'read-only'}) { $pMetadata->readOnly = 'true' === strtolower($readOnly); } else { $pMetadata->readOnly = $pMetadata->readOnly || $readOnlyClass; } $getter = $pElem->attributes()->{'accessor-getter'}; $setter = $pElem->attributes()->{'accessor-setter'}; $pMetadata->setAccessor( (string)($pElem->attributes()->{'access-type'} ?: $classAccessType), $getter ? (string)$getter : null, $setter ? (string)$setter : null ); if (null !== $inline = $pElem->attributes()->inline) { $pMetadata->inline = 'true' === strtolower($inline); } } if ((ExclusionPolicy::NONE === (string)$exclusionPolicy && !$isExclude) || (ExclusionPolicy::ALL === (string)$exclusionPolicy && $isExpose) ) { $metadata->addPropertyMetadata($pMetadata); } } } foreach ($elem->xpath('./callback-method') as $method) { if (!isset($method->attributes()->type)) { throw new RuntimeException('The type attribute must be set for all callback-method elements.'); } if (!isset($method->attributes()->name)) { throw new RuntimeException('The name attribute must be set for all callback-method elements.'); } switch ((string)$method->attributes()->type) { case 'pre-serialize': $metadata->addPreSerializeMethod(new MethodMetadata($name, (string)$method->attributes()->name)); break; case 'post-serialize': $metadata->addPostSerializeMethod(new MethodMetadata($name, (string)$method->attributes()->name)); break; case 'post-deserialize': $metadata->addPostDeserializeMethod(new MethodMetadata($name, (string)$method->attributes()->name)); break; case 'handler': if (!isset($method->attributes()->format)) { throw new RuntimeException('The format attribute must be set for "handler" callback methods.'); } if (!isset($method->attributes()->direction)) { throw new RuntimeException('The direction attribute must be set for "handler" callback methods.'); } $direction = GraphNavigator::parseDirection((string)$method->attributes()->direction); $format = (string)$method->attributes()->format; $metadata->addHandlerCallback($direction, $format, (string)$method->attributes()->name); break; default: throw new RuntimeException(sprintf('The type "%s" is not supported.', $method->attributes()->name)); } } return $metadata; } protected function getExtension() { return 'xml'; } } serializer/src/JMS/Serializer/Metadata/Driver/DoctrineTypeDriver.php 0000644 00000004345 14736103242 0021527 0 ustar 00 <?php namespace JMS\Serializer\Metadata\Driver; use Doctrine\Common\Persistence\Mapping\ClassMetadata as DoctrineClassMetadata; use JMS\Serializer\Metadata\ClassMetadata; use JMS\Serializer\Metadata\PropertyMetadata; /** * This class decorates any other driver. If the inner driver does not provide a * a property type, the decorator will guess based on Doctrine 2 metadata. */ class DoctrineTypeDriver extends AbstractDoctrineTypeDriver { protected function setDiscriminator(DoctrineClassMetadata $doctrineMetadata, ClassMetadata $classMetadata) { if (empty($classMetadata->discriminatorMap) && !$classMetadata->discriminatorDisabled && !empty($doctrineMetadata->discriminatorMap) && $doctrineMetadata->isRootEntity() ) { $classMetadata->setDiscriminator( $doctrineMetadata->discriminatorColumn['name'], $doctrineMetadata->discriminatorMap ); } } protected function setPropertyType(DoctrineClassMetadata $doctrineMetadata, PropertyMetadata $propertyMetadata) { $propertyName = $propertyMetadata->name; if ($doctrineMetadata->hasField($propertyName) && $fieldType = $this->normalizeFieldType($doctrineMetadata->getTypeOfField($propertyName))) { $propertyMetadata->setType($fieldType); } elseif ($doctrineMetadata->hasAssociation($propertyName)) { $targetEntity = $doctrineMetadata->getAssociationTargetClass($propertyName); if (null === $targetMetadata = $this->tryLoadingDoctrineMetadata($targetEntity)) { return; } // For inheritance schemes, we cannot add any type as we would only add the super-type of the hierarchy. // On serialization, this would lead to only the supertype being serialized, and properties of subtypes // being ignored. if ($targetMetadata instanceof DoctrineClassMetadata && !$targetMetadata->isInheritanceTypeNone()) { return; } if (!$doctrineMetadata->isSingleValuedAssociation($propertyName)) { $targetEntity = "ArrayCollection<{$targetEntity}>"; } $propertyMetadata->setType($targetEntity); } } } serializer/src/JMS/Serializer/Metadata/Driver/YamlDriver.php 0000644 00000033426 14736103242 0020022 0 ustar 00 <?php namespace JMS\Serializer\Metadata\Driver; use JMS\Serializer\Annotation\ExclusionPolicy; use JMS\Serializer\Exception\RuntimeException; use JMS\Serializer\GraphNavigator; use JMS\Serializer\Metadata\ClassMetadata; use JMS\Serializer\Metadata\ExpressionPropertyMetadata; use JMS\Serializer\Metadata\PropertyMetadata; use JMS\Serializer\Metadata\VirtualPropertyMetadata; use Metadata\Driver\AbstractFileDriver; use Metadata\MethodMetadata; use Symfony\Component\Yaml\Yaml; class YamlDriver extends AbstractFileDriver { protected function loadMetadataFromFile(\ReflectionClass $class, $file) { $config = Yaml::parse(file_get_contents($file)); if (!isset($config[$name = $class->name])) { throw new RuntimeException(sprintf('Expected metadata for class %s to be defined in %s.', $class->name, $file)); } $config = $config[$name]; $metadata = new ClassMetadata($name); $metadata->fileResources[] = $file; $metadata->fileResources[] = $class->getFileName(); $exclusionPolicy = isset($config['exclusion_policy']) ? strtoupper($config['exclusion_policy']) : 'NONE'; $excludeAll = isset($config['exclude']) ? (Boolean)$config['exclude'] : false; $classAccessType = isset($config['access_type']) ? $config['access_type'] : PropertyMetadata::ACCESS_TYPE_PROPERTY; $readOnlyClass = isset($config['read_only']) ? (Boolean)$config['read_only'] : false; $this->addClassProperties($metadata, $config); $propertiesMetadata = array(); if (array_key_exists('virtual_properties', $config)) { foreach ($config['virtual_properties'] as $methodName => $propertySettings) { if (isset($propertySettings['exp'])) { $virtualPropertyMetadata = new ExpressionPropertyMetadata($name, $methodName, $propertySettings['exp']); unset($propertySettings['exp']); } else { if (!$class->hasMethod($methodName)) { throw new RuntimeException('The method ' . $methodName . ' not found in class ' . $class->name); } $virtualPropertyMetadata = new VirtualPropertyMetadata($name, $methodName); } $propertiesMetadata[$methodName] = $virtualPropertyMetadata; $config['properties'][$methodName] = $propertySettings; } } if (!$excludeAll) { foreach ($class->getProperties() as $property) { if ($property->class !== $name || (isset($property->info) && $property->info['class'] !== $name)) { continue; } $pName = $property->getName(); $propertiesMetadata[$pName] = new PropertyMetadata($name, $pName); } foreach ($propertiesMetadata as $pName => $pMetadata) { $isExclude = false; $isExpose = $pMetadata instanceof VirtualPropertyMetadata || $pMetadata instanceof ExpressionPropertyMetadata || (isset($config['properties']) && array_key_exists($pName, $config['properties'])); if (isset($config['properties'][$pName])) { $pConfig = $config['properties'][$pName]; if (isset($pConfig['exclude'])) { $isExclude = (Boolean)$pConfig['exclude']; } if ($isExclude) { continue; } if (isset($pConfig['expose'])) { $isExpose = (Boolean)$pConfig['expose']; } if (isset($pConfig['skip_when_empty'])) { $pMetadata->skipWhenEmpty = (Boolean)$pConfig['skip_when_empty']; } if (isset($pConfig['since_version'])) { $pMetadata->sinceVersion = (string)$pConfig['since_version']; } if (isset($pConfig['until_version'])) { $pMetadata->untilVersion = (string)$pConfig['until_version']; } if (isset($pConfig['exclude_if'])) { $pMetadata->excludeIf = (string)$pConfig['exclude_if']; } if (isset($pConfig['expose_if'])) { $pMetadata->excludeIf = "!(" . $pConfig['expose_if'] . ")"; } if (isset($pConfig['serialized_name'])) { $pMetadata->serializedName = (string)$pConfig['serialized_name']; } if (isset($pConfig['type'])) { $pMetadata->setType((string)$pConfig['type']); } if (isset($pConfig['groups'])) { $pMetadata->groups = $pConfig['groups']; } if (isset($pConfig['xml_list'])) { $pMetadata->xmlCollection = true; $colConfig = $pConfig['xml_list']; if (isset($colConfig['inline'])) { $pMetadata->xmlCollectionInline = (Boolean)$colConfig['inline']; } if (isset($colConfig['entry_name'])) { $pMetadata->xmlEntryName = (string)$colConfig['entry_name']; } if (isset($colConfig['skip_when_empty'])) { $pMetadata->xmlCollectionSkipWhenEmpty = (Boolean)$colConfig['skip_when_empty']; } else { $pMetadata->xmlCollectionSkipWhenEmpty = true; } if (isset($colConfig['namespace'])) { $pMetadata->xmlEntryNamespace = (string)$colConfig['namespace']; } } if (isset($pConfig['xml_map'])) { $pMetadata->xmlCollection = true; $colConfig = $pConfig['xml_map']; if (isset($colConfig['inline'])) { $pMetadata->xmlCollectionInline = (Boolean)$colConfig['inline']; } if (isset($colConfig['entry_name'])) { $pMetadata->xmlEntryName = (string)$colConfig['entry_name']; } if (isset($colConfig['namespace'])) { $pMetadata->xmlEntryNamespace = (string)$colConfig['namespace']; } if (isset($colConfig['key_attribute_name'])) { $pMetadata->xmlKeyAttribute = $colConfig['key_attribute_name']; } } if (isset($pConfig['xml_element'])) { $colConfig = $pConfig['xml_element']; if (isset($colConfig['cdata'])) { $pMetadata->xmlElementCData = (Boolean)$colConfig['cdata']; } if (isset($colConfig['namespace'])) { $pMetadata->xmlNamespace = (string)$colConfig['namespace']; } } if (isset($pConfig['xml_attribute'])) { $pMetadata->xmlAttribute = (Boolean)$pConfig['xml_attribute']; } if (isset($pConfig['xml_attribute_map'])) { $pMetadata->xmlAttributeMap = (Boolean)$pConfig['xml_attribute_map']; } if (isset($pConfig['xml_value'])) { $pMetadata->xmlValue = (Boolean)$pConfig['xml_value']; } if (isset($pConfig['xml_key_value_pairs'])) { $pMetadata->xmlKeyValuePairs = (Boolean)$pConfig['xml_key_value_pairs']; } //we need read_only before setter and getter set, because that method depends on flag being set if (isset($pConfig['read_only'])) { $pMetadata->readOnly = (Boolean)$pConfig['read_only']; } else { $pMetadata->readOnly = $pMetadata->readOnly || $readOnlyClass; } $pMetadata->setAccessor( isset($pConfig['access_type']) ? $pConfig['access_type'] : $classAccessType, isset($pConfig['accessor']['getter']) ? $pConfig['accessor']['getter'] : null, isset($pConfig['accessor']['setter']) ? $pConfig['accessor']['setter'] : null ); if (isset($pConfig['inline'])) { $pMetadata->inline = (Boolean)$pConfig['inline']; } if (isset($pConfig['max_depth'])) { $pMetadata->maxDepth = (int)$pConfig['max_depth']; } } if ((ExclusionPolicy::NONE === $exclusionPolicy && !$isExclude) || (ExclusionPolicy::ALL === $exclusionPolicy && $isExpose) ) { $metadata->addPropertyMetadata($pMetadata); } } } if (isset($config['handler_callbacks'])) { foreach ($config['handler_callbacks'] as $directionName => $formats) { $direction = GraphNavigator::parseDirection($directionName); foreach ($formats as $format => $methodName) { $metadata->addHandlerCallback($direction, $format, $methodName); } } } if (isset($config['callback_methods'])) { $cConfig = $config['callback_methods']; if (isset($cConfig['pre_serialize'])) { $metadata->preSerializeMethods = $this->getCallbackMetadata($class, $cConfig['pre_serialize']); } if (isset($cConfig['post_serialize'])) { $metadata->postSerializeMethods = $this->getCallbackMetadata($class, $cConfig['post_serialize']); } if (isset($cConfig['post_deserialize'])) { $metadata->postDeserializeMethods = $this->getCallbackMetadata($class, $cConfig['post_deserialize']); } } return $metadata; } protected function getExtension() { return 'yml'; } private function addClassProperties(ClassMetadata $metadata, array $config) { if (isset($config['custom_accessor_order']) && !isset($config['accessor_order'])) { $config['accessor_order'] = 'custom'; } if (isset($config['accessor_order'])) { $metadata->setAccessorOrder($config['accessor_order'], isset($config['custom_accessor_order']) ? $config['custom_accessor_order'] : array()); } if (isset($config['xml_root_name'])) { $metadata->xmlRootName = (string)$config['xml_root_name']; } if (isset($config['xml_root_namespace'])) { $metadata->xmlRootNamespace = (string)$config['xml_root_namespace']; } if (array_key_exists('xml_namespaces', $config)) { foreach ($config['xml_namespaces'] as $prefix => $uri) { $metadata->registerNamespace($uri, $prefix); } } if (isset($config['discriminator'])) { if (isset($config['discriminator']['disabled']) && true === $config['discriminator']['disabled']) { $metadata->discriminatorDisabled = true; } else { if (!isset($config['discriminator']['field_name'])) { throw new RuntimeException('The "field_name" attribute must be set for discriminators.'); } if (!isset($config['discriminator']['map']) || !\is_array($config['discriminator']['map'])) { throw new RuntimeException('The "map" attribute must be set, and be an array for discriminators.'); } $groups = isset($config['discriminator']['groups']) ? $config['discriminator']['groups'] : array(); $metadata->setDiscriminator($config['discriminator']['field_name'], $config['discriminator']['map'], $groups); if (isset($config['discriminator']['xml_attribute'])) { $metadata->xmlDiscriminatorAttribute = (bool)$config['discriminator']['xml_attribute']; } if (isset($config['discriminator']['xml_element'])) { if (isset($config['discriminator']['xml_element']['cdata'])) { $metadata->xmlDiscriminatorCData = (bool)$config['discriminator']['xml_element']['cdata']; } if (isset($config['discriminator']['xml_element']['namespace'])) { $metadata->xmlDiscriminatorNamespace = (string)$config['discriminator']['xml_element']['namespace']; } } } } } private function getCallbackMetadata(\ReflectionClass $class, $config) { if (\is_string($config)) { $config = array($config); } elseif (!\is_array($config)) { throw new RuntimeException(sprintf('callback methods expects a string, or an array of strings that represent method names, but got %s.', json_encode($config['pre_serialize']))); } $methods = array(); foreach ($config as $name) { if (!$class->hasMethod($name)) { throw new RuntimeException(sprintf('The method %s does not exist in class %s.', $name, $class->name)); } $methods[] = new MethodMetadata($class->name, $name); } return $methods; } } serializer/src/JMS/Serializer/Metadata/ExpressionPropertyMetadata.php 0000644 00000003100 14736103242 0022040 0 ustar 00 <?php namespace JMS\Serializer\Metadata; use JMS\Serializer\Exception\ExpressionLanguageRequiredException; /** * @Annotation * @Target("METHOD") * * @author Asmir Mustafic <goetas@gmail.com> */ class ExpressionPropertyMetadata extends PropertyMetadata { /** * @var string */ public $expression; public function __construct($class, $fieldName, $expression) { $this->class = $class; $this->name = $fieldName; $this->expression = $expression; $this->readOnly = true; } public function setAccessor($type, $getter = null, $setter = null) { } /** * @param object $object * @return mixed */ public function getValue($object) { throw new ExpressionLanguageRequiredException(sprintf('The property %s on %s requires the expression accessor strategy to be enabled.', $this->name, $this->class)); } public function setValue($obj, $value) { throw new \LogicException('ExpressionPropertyMetadata is immutable.'); } public function serialize() { return serialize(array( $this->expression, parent::serialize() )); } public function unserialize($str) { $parentStr = $this->unserializeProperties($str); list($this->class, $this->name) = unserialize($parentStr); } protected function unserializeProperties($str) { list( $this->expression, $parentStr ) = unserialize($str); return parent::unserializeProperties($parentStr); } } serializer/src/JMS/Serializer/Metadata/PropertyMetadata.php 0000644 00000015346 14736103242 0017777 0 ustar 00 <?php namespace JMS\Serializer\Metadata; use JMS\Serializer\Exception\RuntimeException; use JMS\Serializer\TypeParser; use Metadata\PropertyMetadata as BasePropertyMetadata; class PropertyMetadata extends BasePropertyMetadata { const ACCESS_TYPE_PROPERTY = 'property'; const ACCESS_TYPE_PUBLIC_METHOD = 'public_method'; public $sinceVersion; public $untilVersion; public $groups; public $serializedName; public $type; public $xmlCollection = false; public $xmlCollectionInline = false; public $xmlCollectionSkipWhenEmpty = true; public $xmlEntryName; public $xmlEntryNamespace; public $xmlKeyAttribute; public $xmlAttribute = false; public $xmlValue = false; public $xmlNamespace; public $xmlKeyValuePairs = false; public $xmlElementCData = true; public $getter; public $setter; public $inline = false; public $skipWhenEmpty = false; public $readOnly = false; public $xmlAttributeMap = false; public $maxDepth = null; public $excludeIf = null; private $closureAccessor; private static $typeParser; public function __construct($class, $name) { parent::__construct($class, $name); $this->initAccessor(); } private function initAccessor() { $classRef = $this->reflection->getDeclaringClass(); if ($classRef->isInternal() || $classRef->getProperty($this->name)->isStatic()) { $this->closureAccessor = function ($o) { return $this->reflection->getValue($o); }; } else { $this->closureAccessor = \Closure::bind(function ($o, $name) { return $o->$name; }, null, $this->reflection->class); } } public function setAccessor($type, $getter = null, $setter = null) { if (self::ACCESS_TYPE_PUBLIC_METHOD === $type) { $class = $this->reflection->getDeclaringClass(); if (empty($getter)) { if ($class->hasMethod('get' . $this->name) && $class->getMethod('get' . $this->name)->isPublic()) { $getter = 'get' . $this->name; } elseif ($class->hasMethod('is' . $this->name) && $class->getMethod('is' . $this->name)->isPublic()) { $getter = 'is' . $this->name; } elseif ($class->hasMethod('has' . $this->name) && $class->getMethod('has' . $this->name)->isPublic()) { $getter = 'has' . $this->name; } else { throw new RuntimeException(sprintf('There is neither a public %s method, nor a public %s method, nor a public %s method in class %s. Please specify which public method should be used for retrieving the value of the property %s.', 'get' . ucfirst($this->name), 'is' . ucfirst($this->name), 'has' . ucfirst($this->name), $this->class, $this->name)); } } if (empty($setter) && !$this->readOnly) { if ($class->hasMethod('set' . $this->name) && $class->getMethod('set' . $this->name)->isPublic()) { $setter = 'set' . $this->name; } else { throw new RuntimeException(sprintf('There is no public %s method in class %s. Please specify which public method should be used for setting the value of the property %s.', 'set' . ucfirst($this->name), $this->class, $this->name)); } } } $this->getter = $getter; $this->setter = $setter; } public function getValue($obj) { if (null === $this->getter) { if (null !== $this->closureAccessor) { $accessor = $this->closureAccessor; return $accessor($obj, $this->name); } return parent::getValue($obj); } return $obj->{$this->getter}(); } public function setValue($obj, $value) { if (null === $this->setter) { parent::setValue($obj, $value); return; } $obj->{$this->setter}($value); } public function setType($type) { if (null === self::$typeParser) { self::$typeParser = new TypeParser(); } $this->type = self::$typeParser->parse($type); } public function serialize() { return serialize(array( $this->sinceVersion, $this->untilVersion, $this->groups, $this->serializedName, $this->type, $this->xmlCollection, $this->xmlCollectionInline, $this->xmlEntryName, $this->xmlKeyAttribute, $this->xmlAttribute, $this->xmlValue, $this->xmlNamespace, $this->xmlKeyValuePairs, $this->xmlElementCData, $this->getter, $this->setter, $this->inline, $this->readOnly, $this->xmlAttributeMap, $this->maxDepth, parent::serialize(), 'xmlEntryNamespace' => $this->xmlEntryNamespace, 'xmlCollectionSkipWhenEmpty' => $this->xmlCollectionSkipWhenEmpty, 'excludeIf' => $this->excludeIf, 'skipWhenEmpty' => $this->skipWhenEmpty, )); } public function unserialize($str) { $parentStr = $this->unserializeProperties($str); parent::unserialize($parentStr); $this->initAccessor(); } protected function unserializeProperties($str) { $unserialized = unserialize($str); list( $this->sinceVersion, $this->untilVersion, $this->groups, $this->serializedName, $this->type, $this->xmlCollection, $this->xmlCollectionInline, $this->xmlEntryName, $this->xmlKeyAttribute, $this->xmlAttribute, $this->xmlValue, $this->xmlNamespace, $this->xmlKeyValuePairs, $this->xmlElementCData, $this->getter, $this->setter, $this->inline, $this->readOnly, $this->xmlAttributeMap, $this->maxDepth, $parentStr ) = $unserialized; if (isset($unserialized['xmlEntryNamespace'])) { $this->xmlEntryNamespace = $unserialized['xmlEntryNamespace']; } if (isset($unserialized['xmlCollectionSkipWhenEmpty'])) { $this->xmlCollectionSkipWhenEmpty = $unserialized['xmlCollectionSkipWhenEmpty']; } if (isset($unserialized['excludeIf'])) { $this->excludeIf = $unserialized['excludeIf']; } if (isset($unserialized['skipWhenEmpty'])) { $this->skipWhenEmpty = $unserialized['skipWhenEmpty']; } return $parentStr; } } serializer/src/JMS/Serializer/Metadata/VirtualPropertyMetadata.php 0000644 00000001540 14736103242 0021335 0 ustar 00 <?php namespace JMS\Serializer\Metadata; class VirtualPropertyMetadata extends PropertyMetadata { public function __construct($class, $methodName) { if (0 === strpos($methodName, 'get')) { $fieldName = lcfirst(substr($methodName, 3)); } else { $fieldName = $methodName; } $this->class = $class; $this->name = $fieldName; $this->getter = $methodName; $this->readOnly = true; } public function setValue($obj, $value) { throw new \LogicException('VirtualPropertyMetadata is immutable.'); } public function setAccessor($type, $getter = null, $setter = null) { } public function unserialize($str) { $parentStr = $this->unserializeProperties($str); list($this->class, $this->name) = unserialize($parentStr); } } serializer/src/JMS/Serializer/Metadata/ClassMetadata.php 0000644 00000031246 14736103242 0017215 0 ustar 00 <?php namespace JMS\Serializer\Metadata; use JMS\Serializer\Exception\InvalidArgumentException; use Metadata\MergeableClassMetadata; use Metadata\MergeableInterface; use Metadata\MethodMetadata; use Metadata\PropertyMetadata as BasePropertyMetadata; /** * Class Metadata used to customize the serialization process. * * @author Johannes M. Schmitt <schmittjoh@gmail.com> */ class ClassMetadata extends MergeableClassMetadata { const ACCESSOR_ORDER_UNDEFINED = 'undefined'; const ACCESSOR_ORDER_ALPHABETICAL = 'alphabetical'; const ACCESSOR_ORDER_CUSTOM = 'custom'; /** @var \ReflectionMethod[] */ public $preSerializeMethods = array(); /** @var \ReflectionMethod[] */ public $postSerializeMethods = array(); /** @var \ReflectionMethod[] */ public $postDeserializeMethods = array(); public $xmlRootName; public $xmlRootNamespace; public $xmlNamespaces = array(); public $accessorOrder; public $customOrder; public $usingExpression = false; public $handlerCallbacks = array(); public $discriminatorDisabled = false; public $discriminatorBaseClass; public $discriminatorFieldName; public $discriminatorValue; public $discriminatorMap = array(); public $discriminatorGroups = array(); public $xmlDiscriminatorAttribute = false; public $xmlDiscriminatorCData = true; public $xmlDiscriminatorNamespace; public function setDiscriminator($fieldName, array $map, array $groups = array()) { if (empty($fieldName)) { throw new \InvalidArgumentException('The $fieldName cannot be empty.'); } if (empty($map)) { throw new \InvalidArgumentException('The discriminator map cannot be empty.'); } $this->discriminatorBaseClass = $this->name; $this->discriminatorFieldName = $fieldName; $this->discriminatorMap = $map; $this->discriminatorGroups = $groups; $this->handleDiscriminatorProperty(); } /** * Sets the order of properties in the class. * * @param string $order * @param array $customOrder * * @throws InvalidArgumentException When the accessor order is not valid * @throws InvalidArgumentException When the custom order is not valid */ public function setAccessorOrder($order, array $customOrder = array()) { if (!in_array($order, array(self::ACCESSOR_ORDER_UNDEFINED, self::ACCESSOR_ORDER_ALPHABETICAL, self::ACCESSOR_ORDER_CUSTOM), true)) { throw new InvalidArgumentException(sprintf('The accessor order "%s" is invalid.', $order)); } foreach ($customOrder as $name) { if (!\is_string($name)) { throw new InvalidArgumentException(sprintf('$customOrder is expected to be a list of strings, but got element of value %s.', json_encode($name))); } } $this->accessorOrder = $order; $this->customOrder = array_flip($customOrder); $this->sortProperties(); } public function addPropertyMetadata(BasePropertyMetadata $metadata) { parent::addPropertyMetadata($metadata); $this->sortProperties(); if ($metadata instanceof PropertyMetadata && $metadata->excludeIf) { $this->usingExpression = true; } } public function addPreSerializeMethod(MethodMetadata $method) { $this->preSerializeMethods[] = $method; } public function addPostSerializeMethod(MethodMetadata $method) { $this->postSerializeMethods[] = $method; } public function addPostDeserializeMethod(MethodMetadata $method) { $this->postDeserializeMethods[] = $method; } /** * @param integer $direction * @param string|integer $format * @param string $methodName */ public function addHandlerCallback($direction, $format, $methodName) { $this->handlerCallbacks[$direction][$format] = $methodName; } public function merge(MergeableInterface $object) { if (!$object instanceof ClassMetadata) { throw new InvalidArgumentException('$object must be an instance of ClassMetadata.'); } parent::merge($object); $this->preSerializeMethods = array_merge($this->preSerializeMethods, $object->preSerializeMethods); $this->postSerializeMethods = array_merge($this->postSerializeMethods, $object->postSerializeMethods); $this->postDeserializeMethods = array_merge($this->postDeserializeMethods, $object->postDeserializeMethods); $this->xmlRootName = $object->xmlRootName; $this->xmlRootNamespace = $object->xmlRootNamespace; $this->xmlNamespaces = array_merge($this->xmlNamespaces, $object->xmlNamespaces); // Handler methods are taken from the outer class completely. $this->handlerCallbacks = $object->handlerCallbacks; if ($object->accessorOrder) { $this->accessorOrder = $object->accessorOrder; $this->customOrder = $object->customOrder; } if ($object->discriminatorFieldName && $this->discriminatorFieldName) { throw new \LogicException(sprintf( 'The discriminator of class "%s" would overwrite the discriminator of the parent class "%s". Please define all possible sub-classes in the discriminator of %s.', $object->name, $this->discriminatorBaseClass, $this->discriminatorBaseClass )); } elseif (!$this->discriminatorFieldName && $object->discriminatorFieldName) { $this->discriminatorFieldName = $object->discriminatorFieldName; $this->discriminatorMap = $object->discriminatorMap; } if ($object->discriminatorDisabled !== null) { $this->discriminatorDisabled = $object->discriminatorDisabled; } if ($object->discriminatorMap) { $this->discriminatorFieldName = $object->discriminatorFieldName; $this->discriminatorMap = $object->discriminatorMap; $this->discriminatorBaseClass = $object->discriminatorBaseClass; } $this->handleDiscriminatorProperty(); $this->sortProperties(); } public function registerNamespace($uri, $prefix = null) { if (!\is_string($uri)) { throw new InvalidArgumentException(sprintf('$uri is expected to be a strings, but got value %s.', json_encode($uri))); } if ($prefix !== null) { if (!\is_string($prefix)) { throw new InvalidArgumentException(sprintf('$prefix is expected to be a strings, but got value %s.', json_encode($prefix))); } } else { $prefix = ""; } $this->xmlNamespaces[$prefix] = $uri; } public function serialize() { $this->sortProperties(); return serialize(array( $this->preSerializeMethods, $this->postSerializeMethods, $this->postDeserializeMethods, $this->xmlRootName, $this->xmlRootNamespace, $this->xmlNamespaces, $this->accessorOrder, $this->customOrder, $this->handlerCallbacks, $this->discriminatorDisabled, $this->discriminatorBaseClass, $this->discriminatorFieldName, $this->discriminatorValue, $this->discriminatorMap, $this->discriminatorGroups, parent::serialize(), 'discriminatorGroups' => $this->discriminatorGroups, 'xmlDiscriminatorAttribute' => $this->xmlDiscriminatorAttribute, 'xmlDiscriminatorCData' => $this->xmlDiscriminatorCData, 'usingExpression' => $this->usingExpression, 'xmlDiscriminatorNamespace' => $this->xmlDiscriminatorNamespace, )); } public function unserialize($str) { $unserialized = unserialize($str); list( $this->preSerializeMethods, $this->postSerializeMethods, $this->postDeserializeMethods, $this->xmlRootName, $this->xmlRootNamespace, $this->xmlNamespaces, $this->accessorOrder, $this->customOrder, $this->handlerCallbacks, $this->discriminatorDisabled, $this->discriminatorBaseClass, $this->discriminatorFieldName, $this->discriminatorValue, $this->discriminatorMap, $this->discriminatorGroups, $parentStr ) = $unserialized; if (isset($unserialized['discriminatorGroups'])) { $this->discriminatorGroups = $unserialized['discriminatorGroups']; } if (isset($unserialized['usingExpression'])) { $this->usingExpression = $unserialized['usingExpression']; } if (isset($unserialized['xmlDiscriminatorAttribute'])) { $this->xmlDiscriminatorAttribute = $unserialized['xmlDiscriminatorAttribute']; } if (isset($unserialized['xmlDiscriminatorNamespace'])) { $this->xmlDiscriminatorNamespace = $unserialized['xmlDiscriminatorNamespace']; } if (isset($unserialized['xmlDiscriminatorCData'])) { $this->xmlDiscriminatorCData = $unserialized['xmlDiscriminatorCData']; } parent::unserialize($parentStr); } private function handleDiscriminatorProperty() { if ($this->discriminatorMap && !$this->reflection->isAbstract() && !$this->reflection->isInterface()) { if (false === $typeValue = array_search($this->name, $this->discriminatorMap, true)) { if ($this->discriminatorBaseClass === $this->name) { @trigger_error( 'Discriminator map was configured on non-abstract parent class but parent class' .' was not included into discriminator map. It will throw exception in next major version.' .' Either declare parent as abstract class or add it into discriminator map.', E_USER_DEPRECATED ); } else { throw new \LogicException(sprintf( 'The sub-class "%s" is not listed in the discriminator of the base class "%s".', $this->name, $this->discriminatorBaseClass )); } } $this->discriminatorValue = $typeValue; if (isset($this->propertyMetadata[$this->discriminatorFieldName]) && !$this->propertyMetadata[$this->discriminatorFieldName] instanceof StaticPropertyMetadata ) { throw new \LogicException(sprintf( 'The discriminator field name "%s" of the base-class "%s" conflicts with a regular property of the sub-class "%s".', $this->discriminatorFieldName, $this->discriminatorBaseClass, $this->name )); } $discriminatorProperty = new StaticPropertyMetadata( $this->name, $this->discriminatorFieldName, $typeValue, $this->discriminatorGroups ); $discriminatorProperty->serializedName = $this->discriminatorFieldName; $discriminatorProperty->xmlAttribute = $this->xmlDiscriminatorAttribute; $discriminatorProperty->xmlElementCData = $this->xmlDiscriminatorCData; $discriminatorProperty->xmlNamespace = $this->xmlDiscriminatorNamespace; $this->propertyMetadata[$this->discriminatorFieldName] = $discriminatorProperty; } } private function sortProperties() { switch ($this->accessorOrder) { case self::ACCESSOR_ORDER_ALPHABETICAL: ksort($this->propertyMetadata); break; case self::ACCESSOR_ORDER_CUSTOM: $order = $this->customOrder; $currentSorting = $this->propertyMetadata ? array_combine(array_keys($this->propertyMetadata), range(1, \count($this->propertyMetadata))) : []; uksort($this->propertyMetadata, function ($a, $b) use ($order, $currentSorting) { $existsA = isset($order[$a]); $existsB = isset($order[$b]); if (!$existsA && !$existsB) { return $currentSorting[$a] - $currentSorting[$b]; } if (!$existsA) { return 1; } if (!$existsB) { return -1; } return $order[$a] < $order[$b] ? -1 : 1; }); break; } } } serializer/src/JMS/Serializer/Metadata/StaticPropertyMetadata.php 0000644 00000002320 14736103242 0021133 0 ustar 00 <?php namespace JMS\Serializer\Metadata; class StaticPropertyMetadata extends PropertyMetadata { private $value; public function __construct($className, $fieldName, $fieldValue, array $groups = array()) { $this->class = $className; $this->name = $fieldName; $this->value = $fieldValue; $this->readOnly = true; $this->groups = $groups; } public function getValue($obj) { return $this->value; } public function setValue($obj, $value) { throw new \LogicException('StaticPropertyMetadata is immutable.'); } public function setAccessor($type, $getter = null, $setter = null) { } public function serialize() { return serialize(array( $this->value, parent::serialize() )); } public function unserialize($str) { $parentStr = $this->unserializeProperties($str); list($this->class, $this->name) = unserialize($parentStr); } protected function unserializeProperties($str) { list( $this->value, $parentStr ) = unserialize($str); return parent::unserializeProperties($parentStr); } } serializer/src/JMS/Serializer/JsonSerializationVisitor.php 0000644 00000014752 14736103242 0020021 0 ustar 00 <?php namespace JMS\Serializer; use JMS\Serializer\Exception\InvalidArgumentException; use JMS\Serializer\Metadata\ClassMetadata; use JMS\Serializer\Metadata\PropertyMetadata; use JMS\Serializer\Naming\AdvancedNamingStrategyInterface; class JsonSerializationVisitor extends GenericSerializationVisitor { private $options = 0; private $navigator; private $root; private $dataStack; private $data; public function setNavigator(GraphNavigator $navigator) { $this->navigator = $navigator; $this->root = null; $this->dataStack = new \SplStack; } /** * @return GraphNavigator */ public function getNavigator() { return $this->navigator; } public function visitNull($data, array $type, Context $context) { return null; } public function visitString($data, array $type, Context $context) { if (null === $this->root) { $this->root = $data; } return (string)$data; } public function visitBoolean($data, array $type, Context $context) { if (null === $this->root) { $this->root = $data; } return (boolean)$data; } public function visitInteger($data, array $type, Context $context) { if (null === $this->root) { $this->root = $data; } return (int)$data; } public function visitDouble($data, array $type, Context $context) { if (null === $this->root) { $this->root = $data; } return (float)$data; } /** * @param array $data * @param array $type * @param Context $context * @return mixed */ public function visitArray($data, array $type, Context $context) { $this->dataStack->push($data); $isHash = isset($type['params'][1]); if (null === $this->root) { $this->root = $isHash ? new \ArrayObject() : array(); $rs = &$this->root; } else { $rs = $isHash ? new \ArrayObject() : array(); } $isList = isset($type['params'][0]) && !isset($type['params'][1]); foreach ($data as $k => $v) { $v = $this->navigator->accept($v, $this->getElementType($type), $context); if (null === $v && $context->shouldSerializeNull() !== true) { continue; } if ($isList) { $rs[] = $v; } else { $rs[$k] = $v; } } $this->dataStack->pop(); return $rs; } public function startVisitingObject(ClassMetadata $metadata, $data, array $type, Context $context) { if (null === $this->root) { $this->root = new \stdClass; } $this->dataStack->push($this->data); $this->data = array(); } public function endVisitingObject(ClassMetadata $metadata, $data, array $type, Context $context) { $rs = $this->data; $this->data = $this->dataStack->pop(); // Force JSON output to "{}" instead of "[]" if it contains either no properties or all properties are null. if (empty($rs)) { $rs = new \ArrayObject(); } if ($this->root instanceof \stdClass && 0 === $this->dataStack->count()) { $this->root = $rs; } return $rs; } public function visitProperty(PropertyMetadata $metadata, $data, Context $context) { $v = $this->accessor->getValue($data, $metadata); $v = $this->navigator->accept($v, $metadata->type, $context); if ((null === $v && $context->shouldSerializeNull() !== true) || (true === $metadata->skipWhenEmpty && ($v instanceof \ArrayObject || \is_array($v)) && 0 === count($v)) ) { return; } if ($this->namingStrategy instanceof AdvancedNamingStrategyInterface) { $k = $this->namingStrategy->getPropertyName($metadata, $context); } else { $k = $this->namingStrategy->translateName($metadata); } if ($metadata->inline) { if (\is_array($v) || ($v instanceof \ArrayObject)) { $this->data = array_merge($this->data, (array) $v); } } else { $this->data[$k] = $v; } } /** * Allows you to add additional data to the current object/root element. * @deprecated use setData instead * @param string $key * @param integer|float|boolean|string|array|null $value This value must either be a regular scalar, or an array. * It must not contain any objects anymore. */ public function addData($key, $value) { if (isset($this->data[$key])) { throw new InvalidArgumentException(sprintf('There is already data for "%s".', $key)); } $this->data[$key] = $value; } /** * Checks if some data key exists. * * @param string $key * @return boolean */ public function hasData($key) { return isset($this->data[$key]); } /** * Allows you to replace existing data on the current object/root element. * * @param string $key * @param integer|float|boolean|string|array|null $value This value must either be a regular scalar, or an array. * It must not contain any objects anymore. */ public function setData($key, $value) { $this->data[$key] = $value; } public function getRoot() { return $this->root; } /** * @param array|\ArrayObject $data the passed data must be understood by whatever encoding function is applied later. */ public function setRoot($data) { $this->root = $data; } public function getResult() { $result = @json_encode($this->getRoot(), $this->options); switch (json_last_error()) { case JSON_ERROR_NONE: return $result; case JSON_ERROR_UTF8: throw new \RuntimeException('Your data could not be encoded because it contains invalid UTF8 characters.'); default: throw new \RuntimeException(sprintf('An error occurred while encoding your data (error code %d).', json_last_error())); } } public function getOptions() { return $this->options; } public function setOptions($options) { $this->options = (integer)$options; } } serializer/src/JMS/Serializer/Serializer.php 0000644 00000020604 14736103242 0015074 0 ustar 00 <?php namespace JMS\Serializer; use JMS\Serializer\Construction\ObjectConstructorInterface; use JMS\Serializer\ContextFactory\DefaultDeserializationContextFactory; use JMS\Serializer\ContextFactory\DefaultSerializationContextFactory; use JMS\Serializer\ContextFactory\DeserializationContextFactoryInterface; use JMS\Serializer\ContextFactory\SerializationContextFactoryInterface; use JMS\Serializer\EventDispatcher\EventDispatcherInterface; use JMS\Serializer\Exception\RuntimeException; use JMS\Serializer\Exception\UnsupportedFormatException; use JMS\Serializer\Expression\ExpressionEvaluatorInterface; use JMS\Serializer\Handler\HandlerRegistryInterface; use Metadata\MetadataFactoryInterface; use PhpCollection\MapInterface; /** * Serializer Implementation. * * @author Johannes M. Schmitt <schmittjoh@gmail.com> */ class Serializer implements SerializerInterface, ArrayTransformerInterface { private $factory; private $handlerRegistry; private $objectConstructor; private $dispatcher; private $typeParser; /** @var \PhpCollection\MapInterface */ private $serializationVisitors; /** @var \PhpCollection\MapInterface */ private $deserializationVisitors; private $navigator; /** * @var SerializationContextFactoryInterface */ private $serializationContextFactory; /** * @var DeserializationContextFactoryInterface */ private $deserializationContextFactory; /** * Constructor. * * @param \Metadata\MetadataFactoryInterface $factory * @param Handler\HandlerRegistryInterface $handlerRegistry * @param Construction\ObjectConstructorInterface $objectConstructor * @param \PhpCollection\MapInterface $serializationVisitors of VisitorInterface * @param \PhpCollection\MapInterface $deserializationVisitors of VisitorInterface * @param EventDispatcher\EventDispatcherInterface $dispatcher * @param TypeParser $typeParser * @param ExpressionEvaluatorInterface|null $expressionEvaluator */ public function __construct( MetadataFactoryInterface $factory, HandlerRegistryInterface $handlerRegistry, ObjectConstructorInterface $objectConstructor, MapInterface $serializationVisitors, MapInterface $deserializationVisitors, EventDispatcherInterface $dispatcher = null, TypeParser $typeParser = null, ExpressionEvaluatorInterface $expressionEvaluator = null ) { $this->factory = $factory; $this->handlerRegistry = $handlerRegistry; $this->objectConstructor = $objectConstructor; $this->dispatcher = $dispatcher; $this->typeParser = $typeParser ?: new TypeParser(); $this->serializationVisitors = $serializationVisitors; $this->deserializationVisitors = $deserializationVisitors; $this->navigator = new GraphNavigator($this->factory, $this->handlerRegistry, $this->objectConstructor, $this->dispatcher, $expressionEvaluator); $this->serializationContextFactory = new DefaultSerializationContextFactory(); $this->deserializationContextFactory = new DefaultDeserializationContextFactory(); } public function serialize($data, $format, SerializationContext $context = null) { if (null === $context) { $context = $this->serializationContextFactory->createSerializationContext(); } return $this->serializationVisitors->get($format) ->map(function (VisitorInterface $visitor) use ($context, $data, $format) { $type = $context->getInitialType() !== null ? $this->typeParser->parse($context->getInitialType()) : null; $this->visit($visitor, $context, $visitor->prepare($data), $format, $type); return $visitor->getResult(); }) ->getOrThrow(new UnsupportedFormatException(sprintf('The format "%s" is not supported for serialization.', $format))); } public function deserialize($data, $type, $format, DeserializationContext $context = null) { if (null === $context) { $context = $this->deserializationContextFactory->createDeserializationContext(); } return $this->deserializationVisitors->get($format) ->map(function (VisitorInterface $visitor) use ($context, $data, $format, $type) { $preparedData = $visitor->prepare($data); $navigatorResult = $this->visit($visitor, $context, $preparedData, $format, $this->typeParser->parse($type)); return $this->handleDeserializeResult($visitor->getResult(), $navigatorResult); }) ->getOrThrow(new UnsupportedFormatException(sprintf('The format "%s" is not supported for deserialization.', $format))); } /** * {@InheritDoc} */ public function toArray($data, SerializationContext $context = null) { if (null === $context) { $context = $this->serializationContextFactory->createSerializationContext(); } return $this->serializationVisitors->get('json') ->map(function (JsonSerializationVisitor $visitor) use ($context, $data) { $type = $context->getInitialType() !== null ? $this->typeParser->parse($context->getInitialType()) : null; $this->visit($visitor, $context, $data, 'json', $type); $result = $this->convertArrayObjects($visitor->getRoot()); if (!\is_array($result)) { throw new RuntimeException(sprintf( 'The input data of type "%s" did not convert to an array, but got a result of type "%s".', \is_object($data) ? \get_class($data) : \gettype($data), \is_object($result) ? \get_class($result) : \gettype($result) )); } return $result; }) ->get(); } /** * {@InheritDoc} */ public function fromArray(array $data, $type, DeserializationContext $context = null) { if (null === $context) { $context = $this->deserializationContextFactory->createDeserializationContext(); } return $this->deserializationVisitors->get('json') ->map(function (JsonDeserializationVisitor $visitor) use ($data, $type, $context) { $navigatorResult = $this->visit($visitor, $context, $data, 'json', $this->typeParser->parse($type)); return $this->handleDeserializeResult($visitor->getResult(), $navigatorResult); }) ->get(); } private function visit(VisitorInterface $visitor, Context $context, $data, $format, array $type = null) { $context->initialize( $format, $visitor, $this->navigator, $this->factory ); $visitor->setNavigator($this->navigator); return $this->navigator->accept($data, $type, $context); } private function handleDeserializeResult($visitorResult, $navigatorResult) { // This is a special case if the root is handled by a callback on the object itself. if (null === $visitorResult && null !== $navigatorResult) { return $navigatorResult; } return $visitorResult; } private function convertArrayObjects($data) { if ($data instanceof \ArrayObject || $data instanceof \stdClass) { $data = (array)$data; } if (\is_array($data)) { foreach ($data as $k => $v) { $data[$k] = $this->convertArrayObjects($v); } } return $data; } /** * @return MetadataFactoryInterface */ public function getMetadataFactory() { return $this->factory; } /** * @param SerializationContextFactoryInterface $serializationContextFactory * * @return self */ public function setSerializationContextFactory(SerializationContextFactoryInterface $serializationContextFactory) { $this->serializationContextFactory = $serializationContextFactory; return $this; } /** * @param DeserializationContextFactoryInterface $deserializationContextFactory * * @return self */ public function setDeserializationContextFactory(DeserializationContextFactoryInterface $deserializationContextFactory) { $this->deserializationContextFactory = $deserializationContextFactory; return $this; } } serializer/src/JMS/Serializer/Builder/CallbackDriverFactory.php 0000644 00000001267 14736103242 0020555 0 ustar 00 <?php namespace JMS\Serializer\Builder; use Doctrine\Common\Annotations\Reader; use Metadata\Driver\DriverInterface; class CallbackDriverFactory implements DriverFactoryInterface { private $callback; /** * @param callable $callable */ public function __construct($callable) { $this->callback = $callable; } public function createDriver(array $metadataDirs, Reader $reader) { $driver = \call_user_func($this->callback, $metadataDirs, $reader); if (!$driver instanceof DriverInterface) { throw new \LogicException('The callback must return an instance of DriverInterface.'); } return $driver; } } serializer/src/JMS/Serializer/Builder/DefaultDriverFactory.php 0000644 00000001466 14736103242 0020446 0 ustar 00 <?php namespace JMS\Serializer\Builder; use Doctrine\Common\Annotations\Reader; use JMS\Serializer\Metadata\Driver\AnnotationDriver; use JMS\Serializer\Metadata\Driver\XmlDriver; use JMS\Serializer\Metadata\Driver\YamlDriver; use Metadata\Driver\DriverChain; use Metadata\Driver\FileLocator; class DefaultDriverFactory implements DriverFactoryInterface { public function createDriver(array $metadataDirs, Reader $annotationReader) { if (!empty($metadataDirs)) { $fileLocator = new FileLocator($metadataDirs); return new DriverChain(array( new YamlDriver($fileLocator), new XmlDriver($fileLocator), new AnnotationDriver($annotationReader), )); } return new AnnotationDriver($annotationReader); } } serializer/src/JMS/Serializer/Builder/DriverFactoryInterface.php 0000644 00000000554 14736103242 0020757 0 ustar 00 <?php namespace JMS\Serializer\Builder; use Doctrine\Common\Annotations\Reader; use Metadata\Driver\DriverInterface; interface DriverFactoryInterface { /** * @param array $metadataDirs * @param Reader $annotationReader * * @return DriverInterface */ public function createDriver(array $metadataDirs, Reader $annotationReader); } serializer/src/JMS/Serializer/XmlSerializationVisitor.php 0000644 00000042363 14736103242 0017647 0 ustar 00 <?php namespace JMS\Serializer; use JMS\Serializer\Accessor\AccessorStrategyInterface; use JMS\Serializer\Exception\RuntimeException; use JMS\Serializer\Metadata\ClassMetadata; use JMS\Serializer\Metadata\PropertyMetadata; use JMS\Serializer\Naming\AdvancedNamingStrategyInterface; use JMS\Serializer\Naming\PropertyNamingStrategyInterface; /** * XmlSerializationVisitor. * * @author Johannes M. Schmitt <schmittjoh@gmail.com> */ class XmlSerializationVisitor extends AbstractVisitor { public $document; private $navigator; private $defaultRootName = 'result'; private $defaultRootNamespace; private $defaultVersion = '1.0'; private $defaultEncoding = 'UTF-8'; private $stack; private $metadataStack; private $currentNode; private $currentMetadata; private $hasValue; private $nullWasVisited; private $objectMetadataStack; /** @var boolean */ private $formatOutput; public function __construct($namingStrategy, AccessorStrategyInterface $accessorStrategy = null) { parent::__construct($namingStrategy, $accessorStrategy); $this->objectMetadataStack = new \SplStack; $this->formatOutput = true; } public function setDefaultRootName($name, $namespace = null) { $this->defaultRootName = $name; $this->defaultRootNamespace = $namespace; } /** * @return boolean */ public function hasDefaultRootName() { return 'result' === $this->defaultRootName; } public function setDefaultVersion($version) { $this->defaultVersion = $version; } public function setDefaultEncoding($encoding) { $this->defaultEncoding = $encoding; } public function setNavigator(GraphNavigator $navigator) { $this->navigator = $navigator; $this->document = null; $this->stack = new \SplStack; $this->metadataStack = new \SplStack; } public function getNavigator() { return $this->navigator; } public function visitNull($data, array $type, Context $context) { if (null === $this->document) { $this->document = $this->createDocument(null, null, true); $node = $this->document->createAttribute('xsi:nil'); $node->value = 'true'; $this->currentNode->appendChild($node); $this->attachNullNamespace(); return; } $node = $this->document->createAttribute('xsi:nil'); $node->value = 'true'; $this->attachNullNamespace(); return $node; } public function visitString($data, array $type, Context $context) { if (null !== $this->currentMetadata) { $doCData = $this->currentMetadata->xmlElementCData; } else { $doCData = true; } if (null === $this->document) { $this->document = $this->createDocument(null, null, true); $this->currentNode->appendChild($doCData ? $this->document->createCDATASection($data) : $this->document->createTextNode((string)$data)); return; } return $doCData ? $this->document->createCDATASection($data) : $this->document->createTextNode((string)$data); } public function visitSimpleString($data, array $type, Context $context) { if (null === $this->document) { $this->document = $this->createDocument(null, null, true); $this->currentNode->appendChild($this->document->createTextNode((string)$data)); return; } return $this->document->createTextNode((string)$data); } public function visitBoolean($data, array $type, Context $context) { if (null === $this->document) { $this->document = $this->createDocument(null, null, true); $this->currentNode->appendChild($this->document->createTextNode($data ? 'true' : 'false')); return; } return $this->document->createTextNode($data ? 'true' : 'false'); } public function visitInteger($data, array $type, Context $context) { return $this->visitNumeric($data, $type); } public function visitDouble($data, array $type, Context $context) { return $this->visitNumeric($data, $type); } public function visitArray($data, array $type, Context $context) { if (null === $this->document) { $this->document = $this->createDocument(null, null, true); } $entryName = (null !== $this->currentMetadata && null !== $this->currentMetadata->xmlEntryName) ? $this->currentMetadata->xmlEntryName : 'entry'; $keyAttributeName = (null !== $this->currentMetadata && null !== $this->currentMetadata->xmlKeyAttribute) ? $this->currentMetadata->xmlKeyAttribute : null; $namespace = (null !== $this->currentMetadata && null !== $this->currentMetadata->xmlEntryNamespace) ? $this->currentMetadata->xmlEntryNamespace : null; foreach ($data as $k => $v) { if (null === $v && $context->shouldSerializeNull() !== true) { continue; } $tagName = (null !== $this->currentMetadata && $this->currentMetadata->xmlKeyValuePairs && $this->isElementNameValid($k)) ? $k : $entryName; $entryNode = $this->createElement($tagName, $namespace); $this->currentNode->appendChild($entryNode); $this->setCurrentNode($entryNode); if (null !== $keyAttributeName) { $entryNode->setAttribute($keyAttributeName, (string)$k); } if (null !== $node = $this->navigator->accept($v, $this->getElementType($type), $context)) { $this->currentNode->appendChild($node); } $this->revertCurrentNode(); } } public function startVisitingObject(ClassMetadata $metadata, $data, array $type, Context $context) { $this->objectMetadataStack->push($metadata); if (null === $this->document) { $this->document = $this->createDocument(null, null, false); if ($metadata->xmlRootName) { $rootName = $metadata->xmlRootName; $rootNamespace = $metadata->xmlRootNamespace ?: $this->getClassDefaultNamespace($metadata); } else { $rootName = $this->defaultRootName; $rootNamespace = $this->defaultRootNamespace; } if ($rootNamespace) { $this->currentNode = $this->document->createElementNS($rootNamespace, $rootName); } else { $this->currentNode = $this->document->createElement($rootName); } $this->document->appendChild($this->currentNode); } $this->addNamespaceAttributes($metadata, $this->currentNode); $this->hasValue = false; } public function visitProperty(PropertyMetadata $metadata, $object, Context $context) { $v = $this->accessor->getValue($object, $metadata); if (null === $v && $context->shouldSerializeNull() !== true) { return; } if ($metadata->xmlAttribute) { $this->setCurrentMetadata($metadata); $node = $this->navigator->accept($v, $metadata->type, $context); $this->revertCurrentMetadata(); if (!$node instanceof \DOMCharacterData) { throw new RuntimeException(sprintf('Unsupported value for XML attribute for %s. Expected character data, but got %s.', $metadata->name, json_encode($v))); } if ($this->namingStrategy instanceof AdvancedNamingStrategyInterface) { $attributeName = $this->namingStrategy->getPropertyName($metadata, $context); } else { $attributeName = $this->namingStrategy->translateName($metadata); } $this->setAttributeOnNode($this->currentNode, $attributeName, $node->nodeValue, $metadata->xmlNamespace); return; } if (($metadata->xmlValue && $this->currentNode->childNodes->length > 0) || (!$metadata->xmlValue && $this->hasValue) ) { throw new RuntimeException(sprintf('If you make use of @XmlValue, all other properties in the class must have the @XmlAttribute annotation. Invalid usage detected in class %s.', $metadata->class)); } if ($metadata->xmlValue) { $this->hasValue = true; $this->setCurrentMetadata($metadata); $node = $this->navigator->accept($v, $metadata->type, $context); $this->revertCurrentMetadata(); if (!$node instanceof \DOMCharacterData) { throw new RuntimeException(sprintf('Unsupported value for property %s::$%s. Expected character data, but got %s.', $metadata->reflection->class, $metadata->reflection->name, \is_object($node) ? \get_class($node) : \gettype($node))); } $this->currentNode->appendChild($node); return; } if ($metadata->xmlAttributeMap) { if (!\is_array($v)) { throw new RuntimeException(sprintf('Unsupported value type for XML attribute map. Expected array but got %s.', \gettype($v))); } foreach ($v as $key => $value) { $this->setCurrentMetadata($metadata); $node = $this->navigator->accept($value, null, $context); $this->revertCurrentMetadata(); if (!$node instanceof \DOMCharacterData) { throw new RuntimeException(sprintf('Unsupported value for a XML attribute map value. Expected character data, but got %s.', json_encode($v))); } $this->setAttributeOnNode($this->currentNode, $key, $node->nodeValue, $metadata->xmlNamespace); } return; } if ($addEnclosingElement = !$this->isInLineCollection($metadata) && !$metadata->inline) { if ($this->namingStrategy instanceof AdvancedNamingStrategyInterface) { $elementName = $this->namingStrategy->getPropertyName($metadata, $context); } else { $elementName = $this->namingStrategy->translateName($metadata); } $namespace = null !== $metadata->xmlNamespace ? $metadata->xmlNamespace : $this->getClassDefaultNamespace($this->objectMetadataStack->top()); $element = $this->createElement($elementName, $namespace); $this->currentNode->appendChild($element); $this->setCurrentNode($element); } $this->setCurrentMetadata($metadata); if (null !== $node = $this->navigator->accept($v, $metadata->type, $context)) { $this->currentNode->appendChild($node); } $this->revertCurrentMetadata(); if ($addEnclosingElement) { $this->revertCurrentNode(); if ($this->isElementEmpty($element) && ($v === null || $this->isSkippableCollection($metadata) || $this->isSkippableEmptyObject($node, $metadata) || $this->isCircularRef($context, $v))) { $this->currentNode->removeChild($element); } } $this->hasValue = false; } private function isInLineCollection(PropertyMetadata $metadata) { return $metadata->xmlCollection && $metadata->xmlCollectionInline; } private function isCircularRef(SerializationContext $context, $v) { return $context->isVisiting($v); } private function isSkippableEmptyObject($node, PropertyMetadata $metadata) { return $node === null && !$metadata->xmlCollection && $metadata->skipWhenEmpty; } private function isSkippableCollection(PropertyMetadata $metadata) { return $metadata->xmlCollection && $metadata->xmlCollectionSkipWhenEmpty; } private function isElementEmpty(\DOMElement $element) { return !$element->hasChildNodes() && !$element->hasAttributes(); } public function endVisitingObject(ClassMetadata $metadata, $data, array $type, Context $context) { $this->objectMetadataStack->pop(); } public function getResult() { return $this->document->saveXML(); } public function getCurrentNode() { return $this->currentNode; } public function getCurrentMetadata() { return $this->currentMetadata; } /** * @param bool $create (default = false) * @return \DOMDocument */ public function getDocument() { if (func_num_args() === 1) { if (null === $this->document && func_get_arg(0) === true) { $this->document = $this->createDocument(); } } return $this->document; } public function setCurrentMetadata(PropertyMetadata $metadata) { $this->metadataStack->push($this->currentMetadata); $this->currentMetadata = $metadata; } public function setCurrentNode(\DOMNode $node) { $this->stack->push($this->currentNode); $this->currentNode = $node; } public function revertCurrentNode() { return $this->currentNode = $this->stack->pop(); } public function revertCurrentMetadata() { return $this->currentMetadata = $this->metadataStack->pop(); } /** * @deprecated Use $this->getDocument(true) instead * @param null $version * @param null $encoding * @param bool $addRoot * @return \DOMDocument */ public function createDocument($version = null, $encoding = null, $addRoot = true) { $doc = new \DOMDocument($version ?: $this->defaultVersion, $encoding ?: $this->defaultEncoding); $doc->formatOutput = $this->isFormatOutput(); if ($addRoot) { if ($this->defaultRootNamespace) { $rootNode = $doc->createElementNS($this->defaultRootNamespace, $this->defaultRootName); } else { $rootNode = $doc->createElement($this->defaultRootName); } $this->setCurrentNode($rootNode); $doc->appendChild($rootNode); } return $doc; } public function prepare($data) { $this->nullWasVisited = false; return $data; } private function visitNumeric($data, array $type) { if (null === $this->document) { $this->document = $this->createDocument(null, null, true); $this->currentNode->appendChild($textNode = $this->document->createTextNode((string)$data)); return $textNode; } return $this->document->createTextNode((string)$data); } /** * Checks that the name is a valid XML element name. * * @param string $name * * @return boolean */ private function isElementNameValid($name) { return $name && false === strpos($name, ' ') && preg_match('#^[\pL_][\pL0-9._-]*$#ui', $name); } private function attachNullNamespace() { if (!$this->nullWasVisited) { $this->document->documentElement->setAttributeNS( 'http://www.w3.org/2000/xmlns/', 'xmlns:xsi', 'http://www.w3.org/2001/XMLSchema-instance' ); $this->nullWasVisited = true; } } /** * Adds namespace attributes to the XML root element * * @param \JMS\Serializer\Metadata\ClassMetadata $metadata * @param \DOMElement $element */ private function addNamespaceAttributes(ClassMetadata $metadata, \DOMElement $element) { foreach ($metadata->xmlNamespaces as $prefix => $uri) { $attribute = 'xmlns'; if ($prefix !== '') { $attribute .= ':' . $prefix; } elseif ($element->namespaceURI === $uri) { continue; } $element->setAttributeNS('http://www.w3.org/2000/xmlns/', $attribute, $uri); } } private function createElement($tagName, $namespace = null) { if (null === $namespace) { return $this->document->createElement($tagName); } if ($this->currentNode->isDefaultNamespace($namespace)) { return $this->document->createElementNS($namespace, $tagName); } if (!($prefix = $this->currentNode->lookupPrefix($namespace)) && !($prefix = $this->document->lookupPrefix($namespace))) { $prefix = 'ns-' . substr(sha1($namespace), 0, 8); } return $this->document->createElementNS($namespace, $prefix . ':' . $tagName); } private function setAttributeOnNode(\DOMElement $node, $name, $value, $namespace = null) { if (null !== $namespace) { if (!$prefix = $node->lookupPrefix($namespace)) { $prefix = 'ns-' . substr(sha1($namespace), 0, 8); } $node->setAttributeNS($namespace, $prefix . ':' . $name, $value); } else { $node->setAttribute($name, $value); } } private function getClassDefaultNamespace(ClassMetadata $metadata) { return (isset($metadata->xmlNamespaces['']) ? $metadata->xmlNamespaces[''] : null); } /** * @return bool */ public function isFormatOutput() { return $this->formatOutput; } /** * @param bool $formatOutput */ public function setFormatOutput($formatOutput) { $this->formatOutput = (boolean)$formatOutput; } } serializer/src/JMS/Serializer/Util/Writer.php 0000644 00000005020 14736103242 0015147 0 ustar 00 <?php namespace JMS\Serializer\Util; use JMS\Serializer\Exception\RuntimeException; /** * A writer implementation. * * This may be used to simplify writing well-formatted code. * * @author Johannes M. Schmitt <schmittjoh@gmail.com> */ class Writer { public $indentationSpaces = 4; public $indentationLevel = 0; public $content = ''; public $changeCount = 0; private $changes = array(); public function indent() { $this->indentationLevel += 1; return $this; } public function outdent() { $this->indentationLevel -= 1; if ($this->indentationLevel < 0) { throw new RuntimeException('The identation level cannot be less than zero.'); } return $this; } /** * @param string $content * * @return Writer */ public function writeln($content) { $this->write($content . "\n"); return $this; } public function revert() { $change = array_pop($this->changes); $this->changeCount -= 1; $this->content = substr($this->content, 0, -1 * \strlen($change)); } /** * @param string $content * * @return Writer */ public function write($content) { $addition = ''; $lines = explode("\n", $content); for ($i = 0, $c = \count($lines); $i < $c; $i++) { if ($this->indentationLevel > 0 && !empty($lines[$i]) && ((empty($addition) && "\n" === substr($this->content, -1)) || "\n" === substr($addition, -1)) ) { $addition .= str_repeat(' ', $this->indentationLevel * $this->indentationSpaces); } $addition .= $lines[$i]; if ($i + 1 < $c) { $addition .= "\n"; } } $this->content .= $addition; $this->changes[] = $addition; $this->changeCount += 1; return $this; } public function rtrim($preserveNewLines = true) { if (!$preserveNewLines) { $this->content = rtrim($this->content); return $this; } $addNl = "\n" === substr($this->content, -1); $this->content = rtrim($this->content); if ($addNl) { $this->content .= "\n"; } return $this; } public function reset() { $this->content = ''; $this->indentationLevel = 0; return $this; } public function getContent() { return $this->content; } } serializer/src/JMS/Serializer/DeserializationContext.php 0000644 00000001173 14736103242 0017456 0 ustar 00 <?php namespace JMS\Serializer; class DeserializationContext extends Context { private $depth = 0; public static function create() { return new self(); } public function getDirection() { return GraphNavigator::DIRECTION_DESERIALIZATION; } public function getDepth() { return $this->depth; } public function increaseDepth() { $this->depth += 1; } public function decreaseDepth() { if ($this->depth <= 0) { throw new \LogicException('Depth cannot be smaller than zero.'); } $this->depth -= 1; } } serializer/src/JMS/Serializer/Twig/SerializerExtension.php 0000644 00000002164 14736103242 0017704 0 ustar 00 <?php namespace JMS\Serializer\Twig; use JMS\Serializer\SerializationContext; use JMS\Serializer\SerializerInterface; /** * Serializer helper twig extension * * Basically provides access to JMSSerializer from Twig */ class SerializerExtension extends \Twig_Extension { protected $serializer; public function getName() { return 'jms_serializer'; } public function __construct(SerializerInterface $serializer) { $this->serializer = $serializer; } public function getFilters() { return array( new \Twig_SimpleFilter('serialize', array($this, 'serialize')), ); } public function getFunctions() { return array( new \Twig_SimpleFunction('serialization_context', '\JMS\Serializer\SerializationContext::create'), ); } /** * @param object $object * @param string $type * @param SerializationContext $context */ public function serialize($object, $type = 'json', SerializationContext $context = null) { return $this->serializer->serialize($object, $type, $context); } } serializer/src/JMS/Serializer/Twig/SerializerRuntimeHelper.php 0000644 00000001241 14736103242 0020506 0 ustar 00 <?php namespace JMS\Serializer\Twig; use JMS\Serializer\SerializationContext; use JMS\Serializer\SerializerInterface; /** * @author Asmir Mustafic <goetas@gmail.com> */ final class SerializerRuntimeHelper { protected $serializer; public function __construct(SerializerInterface $serializer) { $this->serializer = $serializer; } /** * @param $object * @param string $type * @param SerializationContext|null $context * @return string */ public function serialize($object, $type = 'json', SerializationContext $context = null) { return $this->serializer->serialize($object, $type, $context); } } serializer/src/JMS/Serializer/Twig/SerializerRuntimeExtension.php 0000644 00000001137 14736103242 0021247 0 ustar 00 <?php namespace JMS\Serializer\Twig; /** * @author Asmir Mustafic <goetas@gmail.com> */ final class SerializerRuntimeExtension extends \Twig_Extension { public function getName() { return 'jms_serializer'; } public function getFilters() { return array( new \Twig_SimpleFilter('serialize', array(SerializerRuntimeHelper::class, 'serialize')), ); } public function getFunctions() { return array( new \Twig_SimpleFunction('serialization_context', '\JMS\Serializer\SerializationContext::create'), ); } } serializer/src/JMS/Serializer/SerializationContext.php 0000644 00000005360 14736103242 0017147 0 ustar 00 <?php namespace JMS\Serializer; use JMS\Serializer\Exception\RuntimeException; use Metadata\MetadataFactoryInterface; class SerializationContext extends Context { /** @var \SplObjectStorage */ private $visitingSet; /** @var \SplStack */ private $visitingStack; /** * @var string */ private $initialType; public static function create() { return new self(); } /** * @param string $format */ public function initialize($format, VisitorInterface $visitor, GraphNavigator $navigator, MetadataFactoryInterface $factory) { parent::initialize($format, $visitor, $navigator, $factory); $this->visitingSet = new \SplObjectStorage(); $this->visitingStack = new \SplStack(); } public function startVisiting($object) { if (!\is_object($object)) { return; } $this->visitingSet->attach($object); $this->visitingStack->push($object); } public function stopVisiting($object) { if (!\is_object($object)) { return; } $this->visitingSet->detach($object); $poppedObject = $this->visitingStack->pop(); if ($object !== $poppedObject) { throw new RuntimeException('Context visitingStack not working well'); } } public function isVisiting($object) { if (!\is_object($object)) { return false; } return $this->visitingSet->contains($object); } public function getPath() { $path = array(); foreach ($this->visitingStack as $obj) { $path[] = \get_class($obj); } if (!$path) { return null; } return implode(' -> ', $path); } public function getDirection() { return GraphNavigator::DIRECTION_SERIALIZATION; } public function getDepth() { return $this->visitingStack->count(); } public function getObject() { return !$this->visitingStack->isEmpty() ? $this->visitingStack->top() : null; } public function getVisitingStack() { return $this->visitingStack; } public function getVisitingSet() { return $this->visitingSet; } /** * @param string $type * @return $this */ public function setInitialType($type) { $this->initialType = $type; $this->attributes->set('initial_type', $type); return $this; } /** * @return string|null */ public function getInitialType() { return $this->initialType ? $this->initialType : ($this->attributes->containsKey('initial_type') ? $this->attributes->get('initial_type')->get() : null); } } serializer/src/JMS/Serializer/Handler/PropelCollectionHandler.php 0000644 00000003733 14736103242 0021117 0 ustar 00 <?php namespace JMS\Serializer\Handler; use JMS\Serializer\Context; use JMS\Serializer\GraphNavigator; use JMS\Serializer\VisitorInterface; use PropelCollection; class PropelCollectionHandler implements SubscribingHandlerInterface { public static function getSubscribingMethods() { $methods = array(); $formats = array('json', 'xml', 'yml'); //Note: issue when handling inheritance $collectionTypes = array( 'PropelCollection', 'PropelObjectCollection', 'PropelArrayCollection', 'PropelOnDemandCollection' ); foreach ($collectionTypes as $type) { foreach ($formats as $format) { $methods[] = array( 'direction' => GraphNavigator::DIRECTION_SERIALIZATION, 'type' => $type, 'format' => $format, 'method' => 'serializeCollection', ); $methods[] = array( 'direction' => GraphNavigator::DIRECTION_DESERIALIZATION, 'type' => $type, 'format' => $format, 'method' => 'deserializeCollection', ); } } return $methods; } public function serializeCollection(VisitorInterface $visitor, PropelCollection $collection, array $type, Context $context) { // We change the base type, and pass through possible parameters. $type['name'] = 'array'; return $visitor->visitArray($collection->getData(), $type, $context); } public function deserializeCollection(VisitorInterface $visitor, $data, array $type, Context $context) { // See above. Set parameter type to PropelCollection<T> or PropelCollection<K,V> $type['name'] = 'array'; $collection = new PropelCollection(); $collection->setData($visitor->visitArray($data, $type, $context)); return $collection; } } serializer/src/JMS/Serializer/Handler/FormErrorHandler.php 0000644 00000011567 14736103242 0017563 0 ustar 00 <?php namespace JMS\Serializer\Handler; use JMS\Serializer\GraphNavigator; use JMS\Serializer\JsonSerializationVisitor; use JMS\Serializer\VisitorInterface; use JMS\Serializer\XmlSerializationVisitor; use JMS\Serializer\YamlSerializationVisitor; use Symfony\Component\Form\Form; use Symfony\Component\Form\FormError; use Symfony\Component\Translation\TranslatorInterface; class FormErrorHandler implements SubscribingHandlerInterface { private $translator; private $translationDomain; public static function getSubscribingMethods() { $methods = array(); foreach (array('xml', 'json', 'yml') as $format) { $methods[] = array( 'direction' => GraphNavigator::DIRECTION_SERIALIZATION, 'type' => 'Symfony\Component\Form\Form', 'format' => $format, ); $methods[] = array( 'direction' => GraphNavigator::DIRECTION_SERIALIZATION, 'type' => 'Symfony\Component\Form\FormError', 'format' => $format, ); } return $methods; } public function __construct(TranslatorInterface $translator = null, $translationDomain = 'validators') { $this->translator = $translator; $this->translationDomain = $translationDomain; } public function serializeFormToXml(XmlSerializationVisitor $visitor, Form $form, array $type) { if (null === $visitor->document) { $visitor->document = $visitor->createDocument(null, null, false); $visitor->document->appendChild($formNode = $visitor->document->createElement('form')); $visitor->setCurrentNode($formNode); } else { $visitor->getCurrentNode()->appendChild( $formNode = $visitor->document->createElement('form') ); } $formNode->setAttribute('name', $form->getName()); $formNode->appendChild($errorsNode = $visitor->document->createElement('errors')); foreach ($form->getErrors() as $error) { $errorNode = $visitor->document->createElement('entry'); $errorNode->appendChild($this->serializeFormErrorToXml($visitor, $error, array())); $errorsNode->appendChild($errorNode); } foreach ($form->all() as $child) { if ($child instanceof Form) { if (null !== $node = $this->serializeFormToXml($visitor, $child, array())) { $formNode->appendChild($node); } } } return $formNode; } public function serializeFormToJson(JsonSerializationVisitor $visitor, Form $form, array $type) { return $this->convertFormToArray($visitor, $form); } public function serializeFormToYml(YamlSerializationVisitor $visitor, Form $form, array $type) { return $this->convertFormToArray($visitor, $form); } public function serializeFormErrorToXml(XmlSerializationVisitor $visitor, FormError $formError, array $type) { if (null === $visitor->document) { $visitor->document = $visitor->createDocument(null, null, true); } return $visitor->document->createCDATASection($this->getErrorMessage($formError)); } public function serializeFormErrorToJson(JsonSerializationVisitor $visitor, FormError $formError, array $type) { return $this->getErrorMessage($formError); } public function serializeFormErrorToYml(YamlSerializationVisitor $visitor, FormError $formError, array $type) { return $this->getErrorMessage($formError); } private function getErrorMessage(FormError $error) { if ($this->translator === null){ return $error->getMessage(); } if (null !== $error->getMessagePluralization()) { return $this->translator->transChoice($error->getMessageTemplate(), $error->getMessagePluralization(), $error->getMessageParameters(), $this->translationDomain); } return $this->translator->trans($error->getMessageTemplate(), $error->getMessageParameters(), $this->translationDomain); } private function convertFormToArray(VisitorInterface $visitor, Form $data) { $isRoot = null === $visitor->getRoot(); $form = new \ArrayObject(); $errors = array(); foreach ($data->getErrors() as $error) { $errors[] = $this->getErrorMessage($error); } if ($errors) { $form['errors'] = $errors; } $children = array(); foreach ($data->all() as $child) { if ($child instanceof Form) { $children[$child->getName()] = $this->convertFormToArray($visitor, $child); } } if ($children) { $form['children'] = $children; } if ($isRoot) { $visitor->setRoot($form); } return $form; } } serializer/src/JMS/Serializer/Handler/LazyHandlerRegistry.php 0000644 00000003313 14736103242 0020304 0 ustar 00 <?php namespace JMS\Serializer\Handler; use Psr\Container\ContainerInterface as PsrContainerInterface; use Symfony\Component\DependencyInjection\ContainerInterface; class LazyHandlerRegistry extends HandlerRegistry { private $container; private $initializedHandlers = array(); public function __construct($container, array $handlers = array()) { if (!$container instanceof PsrContainerInterface && !$container instanceof ContainerInterface) { throw new \InvalidArgumentException(sprintf('The container must be an instance of %s or %s (%s given).', PsrContainerInterface::class, ContainerInterface::class, \is_object($container) ? \get_class($container) : \gettype($container))); } parent::__construct($handlers); $this->container = $container; } public function registerHandler($direction, $typeName, $format, $handler) { parent::registerHandler($direction, $typeName, $format, $handler); unset($this->initializedHandlers[$direction][$typeName][$format]); } public function getHandler($direction, $typeName, $format) { if (isset($this->initializedHandlers[$direction][$typeName][$format])) { return $this->initializedHandlers[$direction][$typeName][$format]; } if (!isset($this->handlers[$direction][$typeName][$format])) { return null; } $handler = $this->handlers[$direction][$typeName][$format]; if (\is_array($handler) && \is_string($handler[0]) && $this->container->has($handler[0])) { $handler[0] = $this->container->get($handler[0]); } return $this->initializedHandlers[$direction][$typeName][$format] = $handler; } } serializer/src/JMS/Serializer/Handler/PhpCollectionHandler.php 0000644 00000004276 14736103242 0020410 0 ustar 00 <?php namespace JMS\Serializer\Handler; use JMS\Serializer\Context; use JMS\Serializer\GraphNavigator; use JMS\Serializer\VisitorInterface; use PhpCollection\Map; use PhpCollection\Sequence; class PhpCollectionHandler implements SubscribingHandlerInterface { public static function getSubscribingMethods() { $methods = array(); $formats = array('json', 'xml', 'yml'); $collectionTypes = array( 'PhpCollection\Sequence' => 'Sequence', 'PhpCollection\Map' => 'Map', ); foreach ($collectionTypes as $type => $shortName) { foreach ($formats as $format) { $methods[] = array( 'direction' => GraphNavigator::DIRECTION_SERIALIZATION, 'type' => $type, 'format' => $format, 'method' => 'serialize' . $shortName, ); $methods[] = array( 'direction' => GraphNavigator::DIRECTION_DESERIALIZATION, 'type' => $type, 'format' => $format, 'method' => 'deserialize' . $shortName, ); } } return $methods; } public function serializeMap(VisitorInterface $visitor, Map $map, array $type, Context $context) { $type['name'] = 'array'; return $visitor->visitArray(iterator_to_array($map), $type, $context); } public function deserializeMap(VisitorInterface $visitor, $data, array $type, Context $context) { $type['name'] = 'array'; return new Map($visitor->visitArray($data, $type, $context)); } public function serializeSequence(VisitorInterface $visitor, Sequence $sequence, array $type, Context $context) { // We change the base type, and pass through possible parameters. $type['name'] = 'array'; return $visitor->visitArray($sequence->all(), $type, $context); } public function deserializeSequence(VisitorInterface $visitor, $data, array $type, Context $context) { // See above. $type['name'] = 'array'; return new Sequence($visitor->visitArray($data, $type, $context)); } } serializer/src/JMS/Serializer/Handler/ArrayCollectionHandler.php 0000644 00000005027 14736103242 0020732 0 ustar 00 <?php namespace JMS\Serializer\Handler; use Doctrine\Common\Collections\ArrayCollection; use Doctrine\Common\Collections\Collection; use JMS\Serializer\Context; use JMS\Serializer\GraphNavigator; use JMS\Serializer\VisitorInterface; class ArrayCollectionHandler implements SubscribingHandlerInterface { /** * @var bool */ private $initializeExcluded = true; public function __construct($initializeExcluded = true) { $this->initializeExcluded = $initializeExcluded; } public static function getSubscribingMethods() { $methods = array(); $formats = array('json', 'xml', 'yml'); $collectionTypes = array( 'ArrayCollection', 'Doctrine\Common\Collections\ArrayCollection', 'Doctrine\ORM\PersistentCollection', 'Doctrine\ODM\MongoDB\PersistentCollection', 'Doctrine\ODM\PHPCR\PersistentCollection', ); foreach ($collectionTypes as $type) { foreach ($formats as $format) { $methods[] = array( 'direction' => GraphNavigator::DIRECTION_SERIALIZATION, 'type' => $type, 'format' => $format, 'method' => 'serializeCollection', ); $methods[] = array( 'direction' => GraphNavigator::DIRECTION_DESERIALIZATION, 'type' => $type, 'format' => $format, 'method' => 'deserializeCollection', ); } } return $methods; } public function serializeCollection(VisitorInterface $visitor, Collection $collection, array $type, Context $context) { // We change the base type, and pass through possible parameters. $type['name'] = 'array'; if ($this->initializeExcluded === false) { $exclusionStrategy = $context->getExclusionStrategy(); if ($exclusionStrategy !== null && $exclusionStrategy->shouldSkipClass($context->getMetadataFactory()->getMetadataForClass(\get_class($collection)), $context)) { return $visitor->visitArray([], $type, $context); } } return $visitor->visitArray($collection->toArray(), $type, $context); } public function deserializeCollection(VisitorInterface $visitor, $data, array $type, Context $context) { // See above. $type['name'] = 'array'; return new ArrayCollection($visitor->visitArray($data, $type, $context)); } } serializer/src/JMS/Serializer/Handler/ConstraintViolationHandler.php 0000644 00000006742 14736103242 0021656 0 ustar 00 <?php namespace JMS\Serializer\Handler; use JMS\Serializer\Context; use JMS\Serializer\GraphNavigator; use JMS\Serializer\JsonSerializationVisitor; use JMS\Serializer\XmlSerializationVisitor; use JMS\Serializer\YamlSerializationVisitor; use Symfony\Component\Validator\ConstraintViolation; use Symfony\Component\Validator\ConstraintViolationList; class ConstraintViolationHandler implements SubscribingHandlerInterface { public static function getSubscribingMethods() { $methods = array(); $formats = array('xml', 'json', 'yml'); $types = array('Symfony\Component\Validator\ConstraintViolationList' => 'serializeList', 'Symfony\Component\Validator\ConstraintViolation' => 'serializeViolation'); foreach ($types as $type => $method) { foreach ($formats as $format) { $methods[] = array( 'direction' => GraphNavigator::DIRECTION_SERIALIZATION, 'type' => $type, 'format' => $format, 'method' => $method . 'To' . $format, ); } } return $methods; } public function serializeListToXml(XmlSerializationVisitor $visitor, ConstraintViolationList $list, array $type) { if (null === $visitor->document) { $visitor->document = $visitor->createDocument(); } foreach ($list as $violation) { $this->serializeViolationToXml($visitor, $violation); } } public function serializeListToJson(JsonSerializationVisitor $visitor, ConstraintViolationList $list, array $type, Context $context) { return $visitor->visitArray(iterator_to_array($list), $type, $context); } public function serializeListToYml(YamlSerializationVisitor $visitor, ConstraintViolationList $list, array $type, Context $context) { return $visitor->visitArray(iterator_to_array($list), $type, $context); } public function serializeViolationToXml(XmlSerializationVisitor $visitor, ConstraintViolation $violation, array $type = null) { if (null === $visitor->document) { $visitor->document = $visitor->createDocument(null, null, false); $visitor->document->appendChild($violationNode = $visitor->document->createElement('violation')); $visitor->setCurrentNode($violationNode); } else { $visitor->getCurrentNode()->appendChild( $violationNode = $visitor->document->createElement('violation') ); } $violationNode->setAttribute('property_path', $violation->getPropertyPath()); $violationNode->appendChild($messageNode = $visitor->document->createElement('message')); $messageNode->appendChild($visitor->document->createCDATASection($violation->getMessage())); } public function serializeViolationToJson(JsonSerializationVisitor $visitor, ConstraintViolation $violation, array $type = null) { $data = array( 'property_path' => $violation->getPropertyPath(), 'message' => $violation->getMessage() ); if (null === $visitor->getRoot()) { $visitor->setRoot($data); } return $data; } public function serializeViolationToYml(YamlSerializationVisitor $visitor, ConstraintViolation $violation, array $type = null) { return array( 'property_path' => $violation->getPropertyPath(), 'message' => $violation->getMessage(), ); } } serializer/src/JMS/Serializer/Handler/HandlerRegistryInterface.php 0000644 00000002004 14736103242 0021261 0 ustar 00 <?php namespace JMS\Serializer\Handler; /** * Handler Registry Interface. * * @author Johannes M. Schmitt <schmittjoh@gmail.com> */ interface HandlerRegistryInterface { /** * @param SubscribingHandlerInterface $handler * * @return void */ public function registerSubscribingHandler(SubscribingHandlerInterface $handler); /** * Registers a handler in the registry. * * @param integer $direction one of the GraphNavigator::DIRECTION_??? constants * @param string $typeName * @param string $format * @param callable $handler function(VisitorInterface, mixed $data, array $type): mixed * * @return void */ public function registerHandler($direction, $typeName, $format, $handler); /** * @param integer $direction one of the GraphNavigator::DIRECTION_??? constants * @param string $typeName * @param string $format * * @return callable|null */ public function getHandler($direction, $typeName, $format); } serializer/src/JMS/Serializer/Handler/StdClassHandler.php 0000644 00000002614 14736103242 0017357 0 ustar 00 <?php namespace JMS\Serializer\Handler; use JMS\Serializer\Context; use JMS\Serializer\GraphNavigator; use JMS\Serializer\Metadata\StaticPropertyMetadata; use JMS\Serializer\VisitorInterface; /** * @author Asmir Mustafic <goetas@gmail.com> */ class StdClassHandler implements SubscribingHandlerInterface { public static function getSubscribingMethods() { $methods = array(); $formats = array('json', 'xml', 'yml'); foreach ($formats as $format) { $methods[] = array( 'direction' => GraphNavigator::DIRECTION_SERIALIZATION, 'type' => 'stdClass', 'format' => $format, 'method' => 'serializeStdClass', ); } return $methods; } public function serializeStdClass(VisitorInterface $visitor, \stdClass $stdClass, array $type, Context $context) { $classMetadata = $context->getMetadataFactory()->getMetadataForClass('stdClass'); $visitor->startVisitingObject($classMetadata, $stdClass, array('name' => 'stdClass'), $context); foreach ((array)$stdClass as $name => $value) { $metadata = new StaticPropertyMetadata('stdClass', $name, $value); $visitor->visitProperty($metadata, $value, $context); } return $visitor->endVisitingObject($classMetadata, $stdClass, array('name' => 'stdClass'), $context); } } serializer/src/JMS/Serializer/Handler/SubscribingHandlerInterface.php 0000644 00000001061 14736103242 0021725 0 ustar 00 <?php namespace JMS\Serializer\Handler; interface SubscribingHandlerInterface { /** * Return format: * * array( * array( * 'direction' => GraphNavigator::DIRECTION_SERIALIZATION, * 'format' => 'json', * 'type' => 'DateTime', * 'method' => 'serializeDateTimeToJson', * ), * ) * * The direction and method keys can be omitted. * * @return array */ public static function getSubscribingMethods(); } serializer/src/JMS/Serializer/Handler/DateHandler.php 0000644 00000016731 14736103242 0016521 0 ustar 00 <?php namespace JMS\Serializer\Handler; use JMS\Serializer\Context; use JMS\Serializer\Exception\RuntimeException; use JMS\Serializer\GraphNavigator; use JMS\Serializer\JsonDeserializationVisitor; use JMS\Serializer\VisitorInterface; use JMS\Serializer\XmlDeserializationVisitor; use JMS\Serializer\XmlSerializationVisitor; class DateHandler implements SubscribingHandlerInterface { private $defaultFormat; private $defaultTimezone; private $xmlCData; public static function getSubscribingMethods() { $methods = array(); $deserializationTypes = array('DateTime', 'DateTimeImmutable', 'DateInterval'); $serialisationTypes = array('DateTime', 'DateTimeImmutable', 'DateInterval'); foreach (array('json', 'xml', 'yml') as $format) { foreach ($deserializationTypes as $type) { $methods[] = [ 'type' => $type, 'direction' => GraphNavigator::DIRECTION_DESERIALIZATION, 'format' => $format, ]; } foreach ($serialisationTypes as $type) { $methods[] = array( 'type' => $type, 'format' => $format, 'direction' => GraphNavigator::DIRECTION_SERIALIZATION, 'method' => 'serialize' . $type, ); } } return $methods; } public function __construct($defaultFormat = \DateTime::ISO8601, $defaultTimezone = 'UTC', $xmlCData = true) { $this->defaultFormat = $defaultFormat; $this->defaultTimezone = new \DateTimeZone($defaultTimezone); $this->xmlCData = $xmlCData; } private function serializeDateTimeInterface( VisitorInterface $visitor, \DateTimeInterface $date, array $type, Context $context ) { if ($visitor instanceof XmlSerializationVisitor && false === $this->xmlCData) { return $visitor->visitSimpleString($date->format($this->getFormat($type)), $type, $context); } $format = $this->getFormat($type); if ('U' === $format) { return $visitor->visitInteger($date->format($format), $type, $context); } return $visitor->visitString($date->format($this->getFormat($type)), $type, $context); } public function serializeDateTime(VisitorInterface $visitor, \DateTime $date, array $type, Context $context) { return $this->serializeDateTimeInterface($visitor, $date, $type, $context); } public function serializeDateTimeImmutable( VisitorInterface $visitor, \DateTimeImmutable $date, array $type, Context $context ) { return $this->serializeDateTimeInterface($visitor, $date, $type, $context); } public function serializeDateInterval(VisitorInterface $visitor, \DateInterval $date, array $type, Context $context) { $iso8601DateIntervalString = $this->format($date); if ($visitor instanceof XmlSerializationVisitor && false === $this->xmlCData) { return $visitor->visitSimpleString($iso8601DateIntervalString, $type, $context); } return $visitor->visitString($iso8601DateIntervalString, $type, $context); } private function isDataXmlNull($data) { $attributes = $data->attributes('xsi', true); return isset($attributes['nil'][0]) && (string)$attributes['nil'][0] === 'true'; } public function deserializeDateTimeFromXml(XmlDeserializationVisitor $visitor, $data, array $type) { if ($this->isDataXmlNull($data)) { return null; } return $this->parseDateTime($data, $type); } public function deserializeDateTimeImmutableFromXml(XmlDeserializationVisitor $visitor, $data, array $type) { if ($this->isDataXmlNull($data)) { return null; } return $this->parseDateTime($data, $type, true); } public function deserializeDateIntervalFromXml(XmlDeserializationVisitor $visitor, $data, array $type) { if ($this->isDataXmlNull($data)) { return null; } return $this->parseDateInterval($data); } public function deserializeDateTimeFromJson(JsonDeserializationVisitor $visitor, $data, array $type) { if (null === $data) { return null; } return $this->parseDateTime($data, $type); } public function deserializeDateTimeImmutableFromJson(JsonDeserializationVisitor $visitor, $data, array $type) { if (null === $data) { return null; } return $this->parseDateTime($data, $type, true); } public function deserializeDateIntervalFromJson(JsonDeserializationVisitor $visitor, $data, array $type) { if (null === $data) { return null; } return $this->parseDateInterval($data); } private function parseDateTime($data, array $type, $immutable = false) { $timezone = !empty($type['params'][1]) ? new \DateTimeZone($type['params'][1]) : $this->defaultTimezone; $format = $this->getDeserializationFormat($type); if ($immutable) { $datetime = \DateTimeImmutable::createFromFormat($format, (string)$data, $timezone); } else { $datetime = \DateTime::createFromFormat($format, (string)$data, $timezone); } if (false === $datetime) { throw new RuntimeException(sprintf('Invalid datetime "%s", expected format %s.', $data, $format)); } if ($format === 'U') { $datetime = $datetime->setTimezone($timezone); } return $datetime; } private function parseDateInterval($data) { $dateInterval = null; try { $dateInterval = new \DateInterval($data); } catch (\Exception $e) { throw new RuntimeException(sprintf('Invalid dateinterval "%s", expected ISO 8601 format', $data), null, $e); } return $dateInterval; } /** * @param array $type * @return string */ private function getDeserializationFormat(array $type) { if (isset($type['params'][2])) { return $type['params'][2]; } if (isset($type['params'][0])) { return $type['params'][0]; } return $this->defaultFormat; } /** * @return string * @param array $type */ private function getFormat(array $type) { return isset($type['params'][0]) ? $type['params'][0] : $this->defaultFormat; } /** * @param \DateInterval $dateInterval * @return string */ public function format(\DateInterval $dateInterval) { $format = 'P'; if (0 < $dateInterval->y) { $format .= $dateInterval->y . 'Y'; } if (0 < $dateInterval->m) { $format .= $dateInterval->m . 'M'; } if (0 < $dateInterval->d) { $format .= $dateInterval->d . 'D'; } if (0 < $dateInterval->h || 0 < $dateInterval->i || 0 < $dateInterval->s) { $format .= 'T'; } if (0 < $dateInterval->h) { $format .= $dateInterval->h . 'H'; } if (0 < $dateInterval->i) { $format .= $dateInterval->i . 'M'; } if (0 < $dateInterval->s) { $format .= $dateInterval->s . 'S'; } if ($format === 'P') { $format = 'P0DT0S'; } return $format; } } serializer/src/JMS/Serializer/Handler/HandlerRegistry.php 0000644 00000005103 14736103242 0017443 0 ustar 00 <?php namespace JMS\Serializer\Handler; use JMS\Serializer\Exception\LogicException; use JMS\Serializer\Exception\RuntimeException; use JMS\Serializer\GraphNavigator; class HandlerRegistry implements HandlerRegistryInterface { protected $handlers; public static function getDefaultMethod($direction, $type, $format) { if (false !== $pos = strrpos($type, '\\')) { $type = substr($type, $pos + 1); } switch ($direction) { case GraphNavigator::DIRECTION_DESERIALIZATION: return 'deserialize' . $type . 'From' . $format; case GraphNavigator::DIRECTION_SERIALIZATION: return 'serialize' . $type . 'To' . $format; default: throw new LogicException(sprintf('The direction %s does not exist; see GraphNavigator::DIRECTION_??? constants.', json_encode($direction))); } } public function __construct(array $handlers = array()) { $this->handlers = $handlers; } public function registerSubscribingHandler(SubscribingHandlerInterface $handler) { foreach ($handler->getSubscribingMethods() as $methodData) { if (!isset($methodData['type'], $methodData['format'])) { throw new RuntimeException(sprintf('For each subscribing method a "type" and "format" attribute must be given, but only got "%s" for %s.', implode('" and "', array_keys($methodData)), \get_class($handler))); } $directions = array(GraphNavigator::DIRECTION_DESERIALIZATION, GraphNavigator::DIRECTION_SERIALIZATION); if (isset($methodData['direction'])) { $directions = array($methodData['direction']); } foreach ($directions as $direction) { $method = isset($methodData['method']) ? $methodData['method'] : self::getDefaultMethod($direction, $methodData['type'], $methodData['format']); $this->registerHandler($direction, $methodData['type'], $methodData['format'], array($handler, $method)); } } } public function registerHandler($direction, $typeName, $format, $handler) { if (\is_string($direction)) { $direction = GraphNavigator::parseDirection($direction); } $this->handlers[$direction][$typeName][$format] = $handler; } public function getHandler($direction, $typeName, $format) { if (!isset($this->handlers[$direction][$typeName][$format])) { return null; } return $this->handlers[$direction][$typeName][$format]; } } serializer/src/JMS/Serializer/Expression/ExpressionEvaluatorInterface.php 0000644 00000000461 14736103242 0022764 0 ustar 00 <?php namespace JMS\Serializer\Expression; /** * @author Asmir Mustafic <goetas@gmail.com> */ interface ExpressionEvaluatorInterface { /** * @param string $expression * @param array $data * @return mixed */ public function evaluate($expression, array $data = array()); } serializer/src/JMS/Serializer/Expression/ExpressionEvaluator.php 0000644 00000002652 14736103242 0021147 0 ustar 00 <?php namespace JMS\Serializer\Expression; use Symfony\Component\ExpressionLanguage\ExpressionLanguage; /** * @author Asmir Mustafic <goetas@gmail.com> */ class ExpressionEvaluator implements ExpressionEvaluatorInterface { /** * @var ExpressionLanguage */ private $expressionLanguage; /** * @var array */ private $context = array(); /** * @var array */ private $cache = array(); public function __construct(ExpressionLanguage $expressionLanguage, array $context = array(), array $cache = array()) { $this->expressionLanguage = $expressionLanguage; $this->context = $context; $this->cache = $cache; } /** * @param string $name * @param mixed $value */ public function setContextVariable($name, $value) { $this->context[$name] = $value; } /** * @param string $expression * @param array $data * @return mixed */ public function evaluate($expression, array $data = array()) { if (!\is_string($expression)) { return $expression; } $context = $data + $this->context; if (!array_key_exists($expression, $this->cache)) { $this->cache[$expression] = $this->expressionLanguage->parse($expression, array_keys($context)); } return $this->expressionLanguage->evaluate($this->cache[$expression], $context); } } serializer/src/JMS/Serializer/GenericDeserializationVisitor.php 0000644 00000012631 14736103242 0020767 0 ustar 00 <?php namespace JMS\Serializer; use JMS\Serializer\Exception\RuntimeException; use JMS\Serializer\Metadata\ClassMetadata; use JMS\Serializer\Metadata\PropertyMetadata; use JMS\Serializer\Naming\AdvancedNamingStrategyInterface; use JMS\Serializer\Naming\PropertyNamingStrategyInterface; /** * Generic Deserialization Visitor. * @deprecated * @author Johannes M. Schmitt <schmittjoh@gmail.com> */ abstract class GenericDeserializationVisitor extends AbstractVisitor { private $navigator; private $result; private $objectStack; private $currentObject; public function setNavigator(GraphNavigator $navigator) { $this->navigator = $navigator; $this->result = null; $this->objectStack = new \SplStack; } public function getNavigator() { return $this->navigator; } public function prepare($data) { return $this->decode($data); } public function visitNull($data, array $type, Context $context) { return null; } public function visitString($data, array $type, Context $context) { $data = (string)$data; if (null === $this->result) { $this->result = $data; } return $data; } public function visitBoolean($data, array $type, Context $context) { $data = (Boolean)$data; if (null === $this->result) { $this->result = $data; } return $data; } public function visitInteger($data, array $type, Context $context) { $data = (integer)$data; if (null === $this->result) { $this->result = $data; } return $data; } public function visitDouble($data, array $type, Context $context) { $data = (double)$data; if (null === $this->result) { $this->result = $data; } return $data; } public function visitArray($data, array $type, Context $context) { if (!\is_array($data)) { throw new RuntimeException(sprintf('Expected array, but got %s: %s', \gettype($data), json_encode($data))); } // If no further parameters were given, keys/values are just passed as is. if (!$type['params']) { if (null === $this->result) { $this->result = $data; } return $data; } switch (\count($type['params'])) { case 1: // Array is a list. $listType = $type['params'][0]; $result = array(); if (null === $this->result) { $this->result = &$result; } foreach ($data as $v) { $result[] = $this->navigator->accept($v, $listType, $context); } return $result; case 2: // Array is a map. list($keyType, $entryType) = $type['params']; $result = array(); if (null === $this->result) { $this->result = &$result; } foreach ($data as $k => $v) { $result[$this->navigator->accept($k, $keyType, $context)] = $this->navigator->accept($v, $entryType, $context); } return $result; default: throw new RuntimeException(sprintf('Array type cannot have more than 2 parameters, but got %s.', json_encode($type['params']))); } } public function startVisitingObject(ClassMetadata $metadata, $object, array $type, Context $context) { $this->setCurrentObject($object); if (null === $this->result) { $this->result = $this->currentObject; } } public function visitProperty(PropertyMetadata $metadata, $data, Context $context) { if ($this->namingStrategy instanceof AdvancedNamingStrategyInterface) { $name = $this->namingStrategy->getPropertyName($metadata, $context); } else { $name = $this->namingStrategy->translateName($metadata); } if (null === $data) { return; } if (!\is_array($data)) { throw new RuntimeException(sprintf('Invalid data "%s"(%s), expected "%s".', $data, $metadata->type['name'], $metadata->reflection->class)); } if (!array_key_exists($name, $data)) { return; } if (!$metadata->type) { throw new RuntimeException(sprintf('You must define a type for %s::$%s.', $metadata->reflection->class, $metadata->name)); } $v = $data[$name] !== null ? $this->navigator->accept($data[$name], $metadata->type, $context) : null; $this->accessor->setValue($this->currentObject, $v, $metadata); } public function endVisitingObject(ClassMetadata $metadata, $data, array $type, Context $context) { $obj = $this->currentObject; $this->revertCurrentObject(); return $obj; } public function getResult() { return $this->result; } public function setCurrentObject($object) { $this->objectStack->push($this->currentObject); $this->currentObject = $object; } public function getCurrentObject() { return $this->currentObject; } public function revertCurrentObject() { return $this->currentObject = $this->objectStack->pop(); } abstract protected function decode($str); } serializer/src/JMS/Serializer/Accessor/ExpressionAccessorStrategy.php 0000644 00000002200 14736103242 0022062 0 ustar 00 <?php namespace JMS\Serializer\Accessor; use JMS\Serializer\Expression\ExpressionEvaluatorInterface; use JMS\Serializer\Metadata\ExpressionPropertyMetadata; use JMS\Serializer\Metadata\PropertyMetadata; /** * @author Asmir Mustafic <goetas@gmail.com> */ class ExpressionAccessorStrategy implements AccessorStrategyInterface { /** * @var AccessorStrategyInterface */ private $fallback; /** * @var ExpressionEvaluatorInterface */ private $evaluator; public function __construct(ExpressionEvaluatorInterface $evaluator, AccessorStrategyInterface $fallback) { $this->fallback = $fallback; $this->evaluator = $evaluator; } public function getValue($object, PropertyMetadata $metadata) { if ($metadata instanceof ExpressionPropertyMetadata) { return $this->evaluator->evaluate($metadata->expression, array('object' => $object)); } return $this->fallback->getValue($object, $metadata); } public function setValue($object, $value, PropertyMetadata $metadata) { $this->fallback->setValue($object, $value, $metadata); } } serializer/src/JMS/Serializer/Accessor/AccessorStrategyInterface.php 0000644 00000001066 14736103242 0021634 0 ustar 00 <?php namespace JMS\Serializer\Accessor; use JMS\Serializer\Metadata\PropertyMetadata; /** * @author Asmir Mustafic <goetas@gmail.com> */ interface AccessorStrategyInterface { /** * @param object $object * @param PropertyMetadata $metadata * @return mixed */ public function getValue($object, PropertyMetadata $metadata); /** * @param object $object * @param mixed $value * @param PropertyMetadata $metadata * @return void */ public function setValue($object, $value, PropertyMetadata $metadata); } serializer/src/JMS/Serializer/Accessor/DefaultAccessorStrategy.php 0000644 00000000727 14736103242 0021323 0 ustar 00 <?php namespace JMS\Serializer\Accessor; use JMS\Serializer\Metadata\PropertyMetadata; /** * @author Asmir Mustafic <goetas@gmail.com> */ class DefaultAccessorStrategy implements AccessorStrategyInterface { public function getValue($object, PropertyMetadata $metadata) { return $metadata->getValue($object); } public function setValue($object, $value, PropertyMetadata $metadata) { $metadata->setValue($object, $value); } } serializer/src/JMS/Serializer/Construction/ObjectConstructorInterface.php 0000644 00000001656 14736103242 0022760 0 ustar 00 <?php namespace JMS\Serializer\Construction; use JMS\Serializer\DeserializationContext; use JMS\Serializer\Metadata\ClassMetadata; use JMS\Serializer\VisitorInterface; /** * Implementations of this interface construct new objects during deserialization. * * @author Johannes M. Schmitt <schmittjoh@gmail.com> */ interface ObjectConstructorInterface { /** * Constructs a new object. * * Implementations could for example create a new object calling "new", use * "unserialize" techniques, reflection, or other means. * * @param VisitorInterface $visitor * @param ClassMetadata $metadata * @param mixed $data * @param array $type ["name" => string, "params" => array] * @param DeserializationContext $context * * @return object */ public function construct(VisitorInterface $visitor, ClassMetadata $metadata, $data, array $type, DeserializationContext $context); } serializer/src/JMS/Serializer/Construction/UnserializeObjectConstructor.php 0000644 00000001443 14736103242 0023344 0 ustar 00 <?php namespace JMS\Serializer\Construction; use Doctrine\Instantiator\Instantiator; use JMS\Serializer\DeserializationContext; use JMS\Serializer\Metadata\ClassMetadata; use JMS\Serializer\VisitorInterface; class UnserializeObjectConstructor implements ObjectConstructorInterface { /** @var Instantiator */ private $instantiator; public function construct(VisitorInterface $visitor, ClassMetadata $metadata, $data, array $type, DeserializationContext $context) { return $this->getInstantiator()->instantiate($metadata->name); } /** * @return Instantiator */ private function getInstantiator() { if (null == $this->instantiator) { $this->instantiator = new Instantiator(); } return $this->instantiator; } } serializer/src/JMS/Serializer/Construction/DoctrineObjectConstructor.php 0000644 00000010230 14736103242 0022613 0 ustar 00 <?php namespace JMS\Serializer\Construction; use Doctrine\Common\Persistence\ManagerRegistry; use JMS\Serializer\AbstractVisitor; use JMS\Serializer\DeserializationContext; use JMS\Serializer\Exception\InvalidArgumentException; use JMS\Serializer\Exception\ObjectConstructionException; use JMS\Serializer\Metadata\ClassMetadata; use JMS\Serializer\Naming\PropertyNamingStrategyInterface; use JMS\Serializer\VisitorInterface; /** * Doctrine object constructor for new (or existing) objects during deserialization. */ class DoctrineObjectConstructor implements ObjectConstructorInterface { const ON_MISSING_NULL = 'null'; const ON_MISSING_EXCEPTION = 'exception'; const ON_MISSING_FALLBACK = 'fallback'; /** * @var string */ private $fallbackStrategy; private $managerRegistry; private $fallbackConstructor; /** * Constructor. * * @param ManagerRegistry $managerRegistry Manager registry * @param ObjectConstructorInterface $fallbackConstructor Fallback object constructor * @param string $fallbackStrategy */ public function __construct(ManagerRegistry $managerRegistry, ObjectConstructorInterface $fallbackConstructor, $fallbackStrategy = self::ON_MISSING_NULL) { $this->managerRegistry = $managerRegistry; $this->fallbackConstructor = $fallbackConstructor; $this->fallbackStrategy = $fallbackStrategy; } /** * {@inheritdoc} */ public function construct(VisitorInterface $visitor, ClassMetadata $metadata, $data, array $type, DeserializationContext $context) { // Locate possible ObjectManager $objectManager = $this->managerRegistry->getManagerForClass($metadata->name); if (!$objectManager) { // No ObjectManager found, proceed with normal deserialization return $this->fallbackConstructor->construct($visitor, $metadata, $data, $type, $context); } // Locate possible ClassMetadata $classMetadataFactory = $objectManager->getMetadataFactory(); if ($classMetadataFactory->isTransient($metadata->name)) { // No ClassMetadata found, proceed with normal deserialization return $this->fallbackConstructor->construct($visitor, $metadata, $data, $type, $context); } // Managed entity, check for proxy load if (!\is_array($data)) { // Single identifier, load proxy return $objectManager->getReference($metadata->name, $data); } // Fallback to default constructor if missing identifier(s) $classMetadata = $objectManager->getClassMetadata($metadata->name); $identifierList = array(); foreach ($classMetadata->getIdentifierFieldNames() as $name) { if ($visitor instanceof AbstractVisitor) { /** @var PropertyNamingStrategyInterface $namingStrategy */ $namingStrategy = $visitor->getNamingStrategy(); $dataName = $namingStrategy->translateName($metadata->propertyMetadata[$name]); } else { $dataName = $name; } if (!array_key_exists($dataName, $data)) { return $this->fallbackConstructor->construct($visitor, $metadata, $data, $type, $context); } $identifierList[$name] = $data[$dataName]; } // Entity update, load it from database $object = $objectManager->find($metadata->name, $identifierList); if (null === $object) { switch ($this->fallbackStrategy) { case self::ON_MISSING_NULL: return null; case self::ON_MISSING_EXCEPTION: throw new ObjectConstructionException(sprintf("Entity %s can not be found", $metadata->name)); case self::ON_MISSING_FALLBACK: return $this->fallbackConstructor->construct($visitor, $metadata, $data, $type, $context); default: throw new InvalidArgumentException("The provided fallback strategy for the object constructor is not valid"); } } $objectManager->initializeObject($object); return $object; } } serializer/src/JMS/Serializer/NullAwareVisitorInterface.php 0000644 00000000556 14736103242 0020062 0 ustar 00 <?php namespace JMS\Serializer; interface NullAwareVisitorInterface extends VisitorInterface { /** * Determine if a value conveys a null value. * An example could be an xml element (Dom, SimpleXml, ...) that is tagged with a xsi:nil attribute * * @param mixed $value * * @return bool */ public function isNull($value); } serializer/src/JMS/Serializer/ArrayTransformerInterface.php 0000644 00000001724 14736103242 0020107 0 ustar 00 <?php namespace JMS\Serializer; /** * Interface for array transformation. * * @author Daniel Bojdo <daniel@bojdo.eu> */ interface ArrayTransformerInterface { /** * Converts objects to an array structure. * * This is useful when the data needs to be passed on to other methods which expect array data. * * @param mixed $data anything that converts to an array, typically an object or an array of objects * @param SerializationContext|null $context * * @return array */ public function toArray($data, SerializationContext $context = null); /** * Restores objects from an array structure. * * @param array $data * @param string $type * @param DeserializationContext|null $context * * @return mixed this returns whatever the passed type is, typically an object or an array of objects */ public function fromArray(array $data, $type, DeserializationContext $context = null); } serializer/src/JMS/Serializer/JsonDeserializationVisitor.php 0000644 00000002233 14736103242 0020321 0 ustar 00 <?php namespace JMS\Serializer; use JMS\Serializer\Exception\RuntimeException; class JsonDeserializationVisitor extends GenericDeserializationVisitor { protected function decode($str) { $decoded = json_decode($str, true); switch (json_last_error()) { case JSON_ERROR_NONE: return $decoded; case JSON_ERROR_DEPTH: throw new RuntimeException('Could not decode JSON, maximum stack depth exceeded.'); case JSON_ERROR_STATE_MISMATCH: throw new RuntimeException('Could not decode JSON, underflow or the nodes mismatch.'); case JSON_ERROR_CTRL_CHAR: throw new RuntimeException('Could not decode JSON, unexpected control character found.'); case JSON_ERROR_SYNTAX: throw new RuntimeException('Could not decode JSON, syntax error - malformed JSON.'); case JSON_ERROR_UTF8: throw new RuntimeException('Could not decode JSON, malformed UTF-8 characters (incorrectly encoded?)'); default: throw new RuntimeException('Could not decode JSON.'); } } } serializer/src/JMS/Serializer/Exception/UnsupportedFormatException.php 0000644 00000000162 14736103242 0022276 0 ustar 00 <?php namespace JMS\Serializer\Exception; class UnsupportedFormatException extends InvalidArgumentException { } serializer/src/JMS/Serializer/Exception/LogicException.php 0000644 00000000331 14736103242 0017630 0 ustar 00 <?php namespace JMS\Serializer\Exception; /** * LogicException for the Serializer. * * @author Johannes M. Schmitt <schmittjoh@gmail.com> */ class LogicException extends \LogicException implements Exception { } serializer/src/JMS/Serializer/Exception/ObjectConstructionException.php 0000644 00000000350 14736103242 0022415 0 ustar 00 <?php namespace JMS\Serializer\Exception; /** * InvalidArgumentException for the Serializer. * * @author Asmir Mustafic <goetas@gmail.com> */ class ObjectConstructionException extends RuntimeException implements Exception { } serializer/src/JMS/Serializer/Exception/Exception.php 0000644 00000000253 14736103242 0016655 0 ustar 00 <?php namespace JMS\Serializer\Exception; /** * Base exception for the Serializer. * * @author Johannes M. Schmitt <schmittjoh@gmail.com> */ interface Exception { } serializer/src/JMS/Serializer/Exception/ExpressionLanguageRequiredException.php 0000644 00000000246 14736103242 0024104 0 ustar 00 <?php namespace JMS\Serializer\Exception; /** * @author Asmir Mustafic <goetas@gmail.com> */ class ExpressionLanguageRequiredException extends LogicException { } serializer/src/JMS/Serializer/Exception/InvalidArgumentException.php 0000644 00000000367 14736103242 0021675 0 ustar 00 <?php namespace JMS\Serializer\Exception; /** * InvalidArgumentException for the Serializer. * * @author Johannes M. Schmitt <schmittjoh@gmail.com> */ class InvalidArgumentException extends \InvalidArgumentException implements Exception { } serializer/src/JMS/Serializer/Exception/ValidationFailedException.php 0000644 00000001145 14736103242 0021776 0 ustar 00 <?php namespace JMS\Serializer\Exception; use Symfony\Component\Validator\ConstraintViolationListInterface; class ValidationFailedException extends RuntimeException { /** * @var ConstraintViolationListInterface */ private $list; public function __construct(ConstraintViolationListInterface $list) { parent::__construct(sprintf('Validation failed with %d error(s).', \count($list))); $this->list = $list; } /** * @return ConstraintViolationListInterface */ public function getConstraintViolationList() { return $this->list; } } serializer/src/JMS/Serializer/Exception/XmlErrorException.php 0000644 00000001477 14736103242 0020361 0 ustar 00 <?php namespace JMS\Serializer\Exception; class XmlErrorException extends RuntimeException { private $xmlError; public function __construct(\LibXMLError $error) { switch ($error->level) { case LIBXML_ERR_WARNING: $level = 'WARNING'; break; case LIBXML_ERR_FATAL: $level = 'FATAL'; break; case LIBXML_ERR_ERROR: $level = 'ERROR'; break; default: $level = 'UNKNOWN'; } parent::__construct(sprintf('[%s] %s in %s (line: %d, column: %d)', $level, $error->message, $error->file, $error->line, $error->column)); $this->xmlError = $error; } public function getXmlError() { return $this->xmlError; } } serializer/src/JMS/Serializer/Exception/RuntimeException.php 0000644 00000000337 14736103242 0020224 0 ustar 00 <?php namespace JMS\Serializer\Exception; /** * RuntimeException for the Serializer. * * @author Johannes M. Schmitt <schmittjoh@gmail.com> */ class RuntimeException extends \RuntimeException implements Exception { } serializer/src/JMS/Serializer/GraphNavigatorInterface.php 0000644 00000001506 14736103242 0017520 0 ustar 00 <?php namespace JMS\Serializer; /** * Handles traversal along the object graph. * * This class handles traversal along the graph, and calls different methods * on visitors, or custom handlers to process its nodes. * * @author Asmir Mustafic <goetas@gmail.com> */ interface GraphNavigatorInterface { const DIRECTION_SERIALIZATION = 1; const DIRECTION_DESERIALIZATION = 2; /** * Called for each node of the graph that is being traversed. * * @param mixed $data the data depends on the direction, and type of visitor * @param null|array $type array has the format ["name" => string, "params" => array] * @param Context $context * @return mixed the return value depends on the direction, and type of visitor */ public function accept($data, array $type = null, Context $context); } serializer/src/JMS/Serializer/VisitorInterface.php 0000644 00000005505 14736103242 0016246 0 ustar 00 <?php namespace JMS\Serializer; use JMS\Serializer\Metadata\ClassMetadata; use JMS\Serializer\Metadata\PropertyMetadata; /** * Interface for visitors. * * This contains the minimal set of values that must be supported for any * output format. * * @author Johannes M. Schmitt <schmittjoh@gmail.com> */ interface VisitorInterface { /** * Allows visitors to convert the input data to a different representation * before the actual serialization/deserialization process starts. * * @param mixed $data * * @return mixed */ public function prepare($data); /** * @param mixed $data * @param array $type * * @return mixed */ public function visitNull($data, array $type, Context $context); /** * @param mixed $data * @param array $type * * @return mixed */ public function visitString($data, array $type, Context $context); /** * @param mixed $data * @param array $type * * @return mixed */ public function visitBoolean($data, array $type, Context $context); /** * @param mixed $data * @param array $type * * @return mixed */ public function visitDouble($data, array $type, Context $context); /** * @param mixed $data * @param array $type * * @return mixed */ public function visitInteger($data, array $type, Context $context); /** * @param mixed $data * @param array $type * * @return mixed */ public function visitArray($data, array $type, Context $context); /** * Called before the properties of the object are being visited. * * @param ClassMetadata $metadata * @param mixed $data * @param array $type * * @return void */ public function startVisitingObject(ClassMetadata $metadata, $data, array $type, Context $context); /** * @param PropertyMetadata $metadata * @param mixed $data * * @return void */ public function visitProperty(PropertyMetadata $metadata, $data, Context $context); /** * Called after all properties of the object have been visited. * * @param ClassMetadata $metadata * @param mixed $data * @param array $type * * @return mixed */ public function endVisitingObject(ClassMetadata $metadata, $data, array $type, Context $context); /** * Called before serialization/deserialization starts. * * @param GraphNavigator $navigator * * @return void */ public function setNavigator(GraphNavigator $navigator); /** * @deprecated use Context::getNavigator/Context::accept instead * @return GraphNavigator */ public function getNavigator(); /** * @return object|array|scalar */ public function getResult(); } serializer/src/JMS/Serializer/SerializerBuilder.php 0000644 00000040265 14736103242 0016410 0 ustar 00 <?php namespace JMS\Serializer; use Doctrine\Common\Annotations\AnnotationReader; use Doctrine\Common\Annotations\CachedReader; use Doctrine\Common\Annotations\Reader; use Doctrine\Common\Cache\FilesystemCache; use JMS\Serializer\Accessor\AccessorStrategyInterface; use JMS\Serializer\Accessor\DefaultAccessorStrategy; use JMS\Serializer\Accessor\ExpressionAccessorStrategy; use JMS\Serializer\Builder\DefaultDriverFactory; use JMS\Serializer\Builder\DriverFactoryInterface; use JMS\Serializer\Construction\ObjectConstructorInterface; use JMS\Serializer\Construction\UnserializeObjectConstructor; use JMS\Serializer\ContextFactory\CallableDeserializationContextFactory; use JMS\Serializer\ContextFactory\CallableSerializationContextFactory; use JMS\Serializer\ContextFactory\DeserializationContextFactoryInterface; use JMS\Serializer\ContextFactory\SerializationContextFactoryInterface; use JMS\Serializer\EventDispatcher\EventDispatcher; use JMS\Serializer\EventDispatcher\Subscriber\DoctrineProxySubscriber; use JMS\Serializer\Exception\InvalidArgumentException; use JMS\Serializer\Exception\RuntimeException; use JMS\Serializer\Expression\ExpressionEvaluatorInterface; use JMS\Serializer\Handler\ArrayCollectionHandler; use JMS\Serializer\Handler\DateHandler; use JMS\Serializer\Handler\HandlerRegistry; use JMS\Serializer\Handler\PhpCollectionHandler; use JMS\Serializer\Handler\PropelCollectionHandler; use JMS\Serializer\Handler\StdClassHandler; use JMS\Serializer\Naming\AdvancedNamingStrategyInterface; use JMS\Serializer\Naming\CamelCaseNamingStrategy; use JMS\Serializer\Naming\PropertyNamingStrategyInterface; use JMS\Serializer\Naming\SerializedNameAnnotationStrategy; use Metadata\Cache\CacheInterface; use Metadata\Cache\FileCache; use Metadata\MetadataFactory; use PhpCollection\Map; /** * Builder for serializer instances. * * This object makes serializer construction a breeze for projects that do not use * any special dependency injection container. * * @author Johannes M. Schmitt <schmittjoh@gmail.com> */ class SerializerBuilder { private $metadataDirs = array(); private $handlerRegistry; private $handlersConfigured = false; private $eventDispatcher; private $listenersConfigured = false; private $objectConstructor; private $serializationVisitors; private $deserializationVisitors; private $visitorsAdded = false; private $propertyNamingStrategy; private $debug = false; private $cacheDir; private $annotationReader; private $includeInterfaceMetadata = false; private $driverFactory; private $serializationContextFactory; private $deserializationContextFactory; /** * @var ExpressionEvaluatorInterface */ private $expressionEvaluator; /** * @var AccessorStrategyInterface */ private $accessorStrategy; /** * @var CacheInterface */ private $metadataCache; public static function create() { return new static(); } public function __construct() { $this->handlerRegistry = new HandlerRegistry(); $this->eventDispatcher = new EventDispatcher(); $this->driverFactory = new DefaultDriverFactory(); $this->serializationVisitors = new Map(); $this->deserializationVisitors = new Map(); } public function setAccessorStrategy(AccessorStrategyInterface $accessorStrategy) { $this->accessorStrategy = $accessorStrategy; } protected function getAccessorStrategy() { if (!$this->accessorStrategy) { $this->accessorStrategy = new DefaultAccessorStrategy(); if ($this->expressionEvaluator) { $this->accessorStrategy = new ExpressionAccessorStrategy($this->expressionEvaluator, $this->accessorStrategy); } } return $this->accessorStrategy; } public function setExpressionEvaluator(ExpressionEvaluatorInterface $expressionEvaluator) { $this->expressionEvaluator = $expressionEvaluator; return $this; } public function setAnnotationReader(Reader $reader) { $this->annotationReader = $reader; return $this; } public function setDebug($bool) { $this->debug = (boolean)$bool; return $this; } public function setCacheDir($dir) { if (!is_dir($dir)) { $this->createDir($dir); } if (!is_writable($dir)) { throw new InvalidArgumentException(sprintf('The cache directory "%s" is not writable.', $dir)); } $this->cacheDir = $dir; return $this; } public function addDefaultHandlers() { $this->handlersConfigured = true; $this->handlerRegistry->registerSubscribingHandler(new DateHandler()); $this->handlerRegistry->registerSubscribingHandler(new StdClassHandler()); $this->handlerRegistry->registerSubscribingHandler(new PhpCollectionHandler()); $this->handlerRegistry->registerSubscribingHandler(new ArrayCollectionHandler()); $this->handlerRegistry->registerSubscribingHandler(new PropelCollectionHandler()); return $this; } public function configureHandlers(\Closure $closure) { $this->handlersConfigured = true; $closure($this->handlerRegistry); return $this; } public function addDefaultListeners() { $this->listenersConfigured = true; $this->eventDispatcher->addSubscriber(new DoctrineProxySubscriber()); return $this; } public function configureListeners(\Closure $closure) { $this->listenersConfigured = true; $closure($this->eventDispatcher); return $this; } public function setObjectConstructor(ObjectConstructorInterface $constructor) { $this->objectConstructor = $constructor; return $this; } public function setPropertyNamingStrategy(PropertyNamingStrategyInterface $propertyNamingStrategy) { $this->propertyNamingStrategy = $propertyNamingStrategy; return $this; } public function setAdvancedNamingStrategy(AdvancedNamingStrategyInterface $advancedNamingStrategy) { $this->propertyNamingStrategy = $advancedNamingStrategy; return $this; } public function setSerializationVisitor($format, VisitorInterface $visitor) { $this->visitorsAdded = true; $this->serializationVisitors->set($format, $visitor); return $this; } public function setDeserializationVisitor($format, VisitorInterface $visitor) { $this->visitorsAdded = true; $this->deserializationVisitors->set($format, $visitor); return $this; } public function addDefaultSerializationVisitors() { $this->initializePropertyNamingStrategy(); $this->visitorsAdded = true; $this->serializationVisitors->setAll(array( 'xml' => new XmlSerializationVisitor($this->propertyNamingStrategy, $this->getAccessorStrategy()), 'yml' => new YamlSerializationVisitor($this->propertyNamingStrategy, $this->getAccessorStrategy()), 'json' => new JsonSerializationVisitor($this->propertyNamingStrategy, $this->getAccessorStrategy()), )); return $this; } public function addDefaultDeserializationVisitors() { $this->initializePropertyNamingStrategy(); $this->visitorsAdded = true; $this->deserializationVisitors->setAll(array( 'xml' => new XmlDeserializationVisitor($this->propertyNamingStrategy), 'json' => new JsonDeserializationVisitor($this->propertyNamingStrategy), )); return $this; } /** * @param Boolean $include Whether to include the metadata from the interfaces * * @return SerializerBuilder */ public function includeInterfaceMetadata($include) { $this->includeInterfaceMetadata = (Boolean)$include; return $this; } /** * Sets a map of namespace prefixes to directories. * * This method overrides any previously defined directories. * * @param array <string,string> $namespacePrefixToDirMap * * @return SerializerBuilder * * @throws InvalidArgumentException When a directory does not exist */ public function setMetadataDirs(array $namespacePrefixToDirMap) { foreach ($namespacePrefixToDirMap as $dir) { if (!is_dir($dir)) { throw new InvalidArgumentException(sprintf('The directory "%s" does not exist.', $dir)); } } $this->metadataDirs = $namespacePrefixToDirMap; return $this; } /** * Adds a directory where the serializer will look for class metadata. * * The namespace prefix will make the names of the actual metadata files a bit shorter. For example, let's assume * that you have a directory where you only store metadata files for the ``MyApplication\Entity`` namespace. * * If you use an empty prefix, your metadata files would need to look like: * * ``my-dir/MyApplication.Entity.SomeObject.yml`` * ``my-dir/MyApplication.Entity.OtherObject.xml`` * * If you use ``MyApplication\Entity`` as prefix, your metadata files would need to look like: * * ``my-dir/SomeObject.yml`` * ``my-dir/OtherObject.yml`` * * Please keep in mind that you currently may only have one directory per namespace prefix. * * @param string $dir The directory where metadata files are located. * @param string $namespacePrefix An optional prefix if you only store metadata for specific namespaces in this directory. * * @return SerializerBuilder * * @throws InvalidArgumentException When a directory does not exist * @throws InvalidArgumentException When a directory has already been registered */ public function addMetadataDir($dir, $namespacePrefix = '') { if (!is_dir($dir)) { throw new InvalidArgumentException(sprintf('The directory "%s" does not exist.', $dir)); } if (isset($this->metadataDirs[$namespacePrefix])) { throw new InvalidArgumentException(sprintf('There is already a directory configured for the namespace prefix "%s". Please use replaceMetadataDir() to override directories.', $namespacePrefix)); } $this->metadataDirs[$namespacePrefix] = $dir; return $this; } /** * Adds a map of namespace prefixes to directories. * * @param array <string,string> $namespacePrefixToDirMap * * @return SerializerBuilder */ public function addMetadataDirs(array $namespacePrefixToDirMap) { foreach ($namespacePrefixToDirMap as $prefix => $dir) { $this->addMetadataDir($dir, $prefix); } return $this; } /** * Similar to addMetadataDir(), but overrides an existing entry. * * @param string $dir * @param string $namespacePrefix * * @return SerializerBuilder * * @throws InvalidArgumentException When a directory does not exist * @throws InvalidArgumentException When no directory is configured for the ns prefix */ public function replaceMetadataDir($dir, $namespacePrefix = '') { if (!is_dir($dir)) { throw new InvalidArgumentException(sprintf('The directory "%s" does not exist.', $dir)); } if (!isset($this->metadataDirs[$namespacePrefix])) { throw new InvalidArgumentException(sprintf('There is no directory configured for namespace prefix "%s". Please use addMetadataDir() for adding new directories.', $namespacePrefix)); } $this->metadataDirs[$namespacePrefix] = $dir; return $this; } public function setMetadataDriverFactory(DriverFactoryInterface $driverFactory) { $this->driverFactory = $driverFactory; return $this; } /** * @param SerializationContextFactoryInterface|callable $serializationContextFactory * * @return self */ public function setSerializationContextFactory($serializationContextFactory) { if ($serializationContextFactory instanceof SerializationContextFactoryInterface) { $this->serializationContextFactory = $serializationContextFactory; } elseif (is_callable($serializationContextFactory)) { $this->serializationContextFactory = new CallableSerializationContextFactory( $serializationContextFactory ); } else { throw new InvalidArgumentException('expected SerializationContextFactoryInterface or callable.'); } return $this; } /** * @param DeserializationContextFactoryInterface|callable $deserializationContextFactory * * @return self */ public function setDeserializationContextFactory($deserializationContextFactory) { if ($deserializationContextFactory instanceof DeserializationContextFactoryInterface) { $this->deserializationContextFactory = $deserializationContextFactory; } elseif (is_callable($deserializationContextFactory)) { $this->deserializationContextFactory = new CallableDeserializationContextFactory( $deserializationContextFactory ); } else { throw new InvalidArgumentException('expected DeserializationContextFactoryInterface or callable.'); } return $this; } /** * @param CacheInterface $cache * * @return self */ public function setMetadataCache(CacheInterface $cache) { $this->metadataCache = $cache; return $this; } public function build() { $annotationReader = $this->annotationReader; if (null === $annotationReader) { $annotationReader = new AnnotationReader(); if (null !== $this->cacheDir) { $this->createDir($this->cacheDir . '/annotations'); $annotationsCache = new FilesystemCache($this->cacheDir . '/annotations'); $annotationReader = new CachedReader($annotationReader, $annotationsCache, $this->debug); } } $metadataDriver = $this->driverFactory->createDriver($this->metadataDirs, $annotationReader); $metadataFactory = new MetadataFactory($metadataDriver, null, $this->debug); $metadataFactory->setIncludeInterfaces($this->includeInterfaceMetadata); if ($this->metadataCache !== null) { $metadataFactory->setCache($this->metadataCache); } elseif (null !== $this->cacheDir) { $this->createDir($this->cacheDir . '/metadata'); $metadataFactory->setCache(new FileCache($this->cacheDir . '/metadata')); } if (!$this->handlersConfigured) { $this->addDefaultHandlers(); } if (!$this->listenersConfigured) { $this->addDefaultListeners(); } if (!$this->visitorsAdded) { $this->addDefaultSerializationVisitors(); $this->addDefaultDeserializationVisitors(); } $serializer = new Serializer( $metadataFactory, $this->handlerRegistry, $this->objectConstructor ?: new UnserializeObjectConstructor(), $this->serializationVisitors, $this->deserializationVisitors, $this->eventDispatcher, null, $this->expressionEvaluator ); if (null !== $this->serializationContextFactory) { $serializer->setSerializationContextFactory($this->serializationContextFactory); } if (null !== $this->deserializationContextFactory) { $serializer->setDeserializationContextFactory($this->deserializationContextFactory); } return $serializer; } private function initializePropertyNamingStrategy() { if (null !== $this->propertyNamingStrategy) { return; } $this->propertyNamingStrategy = new SerializedNameAnnotationStrategy(new CamelCaseNamingStrategy()); } private function createDir($dir) { if (is_dir($dir)) { return; } if (false === @mkdir($dir, 0777, true) && false === is_dir($dir)) { throw new RuntimeException(sprintf('Could not create directory "%s".', $dir)); } } } serializer/src/JMS/Serializer/GenericSerializationVisitor.php 0000644 00000012573 14736103242 0020463 0 ustar 00 <?php namespace JMS\Serializer; use JMS\Serializer\Exception\InvalidArgumentException; use JMS\Serializer\Metadata\ClassMetadata; use JMS\Serializer\Metadata\PropertyMetadata; use JMS\Serializer\Naming\AdvancedNamingStrategyInterface; /** * @deprecated */ abstract class GenericSerializationVisitor extends AbstractVisitor { private $navigator; private $root; private $dataStack; private $data; public function setNavigator(GraphNavigator $navigator) { $this->navigator = $navigator; $this->root = null; $this->dataStack = new \SplStack; } /** * @return GraphNavigator */ public function getNavigator() { return $this->navigator; } public function visitNull($data, array $type, Context $context) { return null; } public function visitString($data, array $type, Context $context) { if (null === $this->root) { $this->root = $data; } return (string)$data; } public function visitBoolean($data, array $type, Context $context) { if (null === $this->root) { $this->root = $data; } return (boolean)$data; } public function visitInteger($data, array $type, Context $context) { if (null === $this->root) { $this->root = $data; } return (int)$data; } public function visitDouble($data, array $type, Context $context) { if (null === $this->root) { $this->root = $data; } return (float)$data; } /** * @param array $data * @param array $type */ public function visitArray($data, array $type, Context $context) { $this->dataStack->push($data); $isHash = isset($type['params'][1]); if (null === $this->root) { $this->root = $isHash ? new \ArrayObject() : array(); $rs = &$this->root; } else { $rs = $isHash ? new \ArrayObject() : array(); } $isList = isset($type['params'][0]) && !isset($type['params'][1]); foreach ($data as $k => $v) { $v = $this->navigator->accept($v, $this->getElementType($type), $context); if (null === $v && $context->shouldSerializeNull() !== true) { continue; } if ($isList) { $rs[] = $v; } else { $rs[$k] = $v; } } $this->dataStack->pop(); return $rs; } public function startVisitingObject(ClassMetadata $metadata, $data, array $type, Context $context) { if (null === $this->root) { $this->root = new \stdClass; } $this->dataStack->push($this->data); $this->data = array(); } public function endVisitingObject(ClassMetadata $metadata, $data, array $type, Context $context) { $rs = $this->data; $this->data = $this->dataStack->pop(); if ($this->root instanceof \stdClass && 0 === $this->dataStack->count()) { $this->root = $rs; } return $rs; } public function visitProperty(PropertyMetadata $metadata, $data, Context $context) { $v = $this->accessor->getValue($data, $metadata); $v = $this->navigator->accept($v, $metadata->type, $context); if (null === $v && $context->shouldSerializeNull() !== true) { return; } if ($this->namingStrategy instanceof AdvancedNamingStrategyInterface) { $k = $this->namingStrategy->getPropertyName($metadata, $context); } else { $k = $this->namingStrategy->translateName($metadata); } if ($metadata->inline) { if (\is_array($v)) { $this->data = array_merge($this->data, $v); } } else { $this->data[$k] = $v; } } /** * Allows you to add additional data to the current object/root element. * @deprecated use setData instead * @param string $key * @param integer|float|boolean|string|array|null $value This value must either be a regular scalar, or an array. * It must not contain any objects anymore. */ public function addData($key, $value) { if (isset($this->data[$key])) { throw new InvalidArgumentException(sprintf('There is already data for "%s".', $key)); } $this->data[$key] = $value; } /** * Checks if some data key exists. * * @param string $key * @return boolean */ public function hasData($key) { return isset($this->data[$key]); } /** * Allows you to replace existing data on the current object/root element. * * @param string $key * @param integer|float|boolean|string|array|null $value This value must either be a regular scalar, or an array. * It must not contain any objects anymore. */ public function setData($key, $value) { $this->data[$key] = $value; } public function getRoot() { return $this->root; } /** * @param array|\ArrayObject $data the passed data must be understood by whatever encoding function is applied later. */ public function setRoot($data) { $this->root = $data; } } serializer/src/JMS/Serializer/ContextFactory/DeserializationContextFactoryInterface.php 0000644 00000000462 14736103242 0025603 0 ustar 00 <?php namespace JMS\Serializer\ContextFactory; use JMS\Serializer\DeserializationContext; /** * Deserialization Context Factory Interface. */ interface DeserializationContextFactoryInterface { /** * @return DeserializationContext */ public function createDeserializationContext(); } serializer/src/JMS/Serializer/ContextFactory/DefaultDeserializationContextFactory.php 0000644 00000000603 14736103242 0025264 0 ustar 00 <?php namespace JMS\Serializer\ContextFactory; use JMS\Serializer\DeserializationContext; /** * Default Deserialization Context Factory. */ class DefaultDeserializationContextFactory implements DeserializationContextFactoryInterface { /** * {@InheritDoc} */ public function createDeserializationContext() { return new DeserializationContext(); } } serializer/src/JMS/Serializer/ContextFactory/CallableSerializationContextFactory.php 0000644 00000000566 14736103242 0025076 0 ustar 00 <?php namespace JMS\Serializer\ContextFactory; /** * Serialization Context Factory using a callable. */ class CallableSerializationContextFactory extends CallableContextFactory implements SerializationContextFactoryInterface { /** * {@InheritDoc} */ public function createSerializationContext() { return $this->createContext(); } } serializer/src/JMS/Serializer/ContextFactory/DefaultSerializationContextFactory.php 0000644 00000000567 14736103242 0024764 0 ustar 00 <?php namespace JMS\Serializer\ContextFactory; use JMS\Serializer\SerializationContext; /** * Default Serialization Context Factory. */ class DefaultSerializationContextFactory implements SerializationContextFactoryInterface { /** * {@InheritDoc} */ public function createSerializationContext() { return new SerializationContext(); } } serializer/src/JMS/Serializer/ContextFactory/CallableContextFactory.php 0000644 00000000766 14736103242 0022342 0 ustar 00 <?php namespace JMS\Serializer\ContextFactory; /** * Context Factory using a callable. */ abstract class CallableContextFactory { /** * @var callable */ private $callable; /** * @param callable $callable */ public function __construct(callable $callable) { $this->callable = $callable; } /** * @return mixed */ protected function createContext() { $callable = $this->callable; return $callable(); } } serializer/src/JMS/Serializer/ContextFactory/CallableDeserializationContextFactory.php 0000644 00000000576 14736103242 0025410 0 ustar 00 <?php namespace JMS\Serializer\ContextFactory; /** * Deserialization Context Factory using a callable. */ class CallableDeserializationContextFactory extends CallableContextFactory implements DeserializationContextFactoryInterface { /** * {@InheritDoc} */ public function createDeserializationContext() { return $this->createContext(); } } serializer/src/JMS/Serializer/ContextFactory/SerializationContextFactoryInterface.php 0000644 00000000450 14736103242 0025267 0 ustar 00 <?php namespace JMS\Serializer\ContextFactory; use JMS\Serializer\SerializationContext; /** * Serialization Context Factory Interface. */ interface SerializationContextFactoryInterface { /** * @return SerializationContext */ public function createSerializationContext(); } serializer/src/JMS/Serializer/SerializerInterface.php 0000644 00000001432 14736103242 0016713 0 ustar 00 <?php namespace JMS\Serializer; /** * Serializer Interface. * * @author Johannes M. Schmitt <schmittjoh@gmail.com> */ interface SerializerInterface { /** * Serializes the given data to the specified output format. * * @param object|array|scalar $data * @param string $format * @param Context $context * * @return string */ public function serialize($data, $format, SerializationContext $context = null); /** * Deserializes the given data to the specified type. * * @param string $data * @param string $type * @param string $format * @param Context $context * * @return object|array|scalar */ public function deserialize($data, $type, $format, DeserializationContext $context = null); } serializer/src/JMS/Serializer/EventDispatcher/EventDispatcherInterface.php 0000644 00000002261 14736103242 0022763 0 ustar 00 <?php namespace JMS\Serializer\EventDispatcher; interface EventDispatcherInterface { /** * Returns whether there are listeners. * * @param string $eventName * @param string $class * @param string $format * * @return boolean */ public function hasListeners($eventName, $class, $format); /** * Dispatches an event. * * The listeners/subscribers are called in the same order in which they * were added to the dispatcher. * * @param string $eventName * @param string $class * @param string $format * @param Event $event * @return void */ public function dispatch($eventName, $class, $format, Event $event); /** * Adds a listener. * * @param string $eventName * @param callable $callable * @param string|null $class * @param string|null $format * @return void */ public function addListener($eventName, $callable, $class = null, $format = null); /** * Adds a subscribers. * * @param EventSubscriberInterface $subscriber * @return void */ public function addSubscriber(EventSubscriberInterface $subscriber); } serializer/src/JMS/Serializer/EventDispatcher/Subscriber/DoctrineProxySubscriber.php 0000644 00000007617 14736103242 0025024 0 ustar 00 <?php namespace JMS\Serializer\EventDispatcher\Subscriber; use Doctrine\Common\Persistence\Proxy; use Doctrine\ODM\MongoDB\PersistentCollection as MongoDBPersistentCollection; use Doctrine\ODM\PHPCR\PersistentCollection as PHPCRPersistentCollection; use Doctrine\ORM\PersistentCollection; use Doctrine\ORM\Proxy\Proxy as ORMProxy; use JMS\Serializer\EventDispatcher\EventDispatcherInterface; use JMS\Serializer\EventDispatcher\EventSubscriberInterface; use JMS\Serializer\EventDispatcher\PreSerializeEvent; class DoctrineProxySubscriber implements EventSubscriberInterface { /** * @var bool */ private $skipVirtualTypeInit = false; /** * @var bool */ private $initializeExcluded = true; public function __construct($skipVirtualTypeInit = false, $initializeExcluded = true) { $this->skipVirtualTypeInit = (bool)$skipVirtualTypeInit; $this->initializeExcluded = (bool)$initializeExcluded; } public function onPreSerialize(PreSerializeEvent $event) { $object = $event->getObject(); $type = $event->getType(); // If the set type name is not an actual class, but a faked type for which a custom handler exists, we do not // modify it with this subscriber. Also, we forgo autoloading here as an instance of this type is already created, // so it must be loaded if its a real class. $virtualType = !class_exists($type['name'], false); if ($object instanceof PersistentCollection || $object instanceof MongoDBPersistentCollection || $object instanceof PHPCRPersistentCollection ) { if (!$virtualType) { $event->setType('ArrayCollection'); } return; } if (($this->skipVirtualTypeInit && $virtualType) || (!$object instanceof Proxy && !$object instanceof ORMProxy) ) { return; } // do not initialize the proxy if is going to be excluded by-class by some exclusion strategy if ($this->initializeExcluded === false && !$virtualType) { $context = $event->getContext(); $exclusionStrategy = $context->getExclusionStrategy(); if ($exclusionStrategy !== null && $exclusionStrategy->shouldSkipClass($context->getMetadataFactory()->getMetadataForClass(get_parent_class($object)), $context)) { return; } } $object->__load(); if (!$virtualType) { $event->setType(get_parent_class($object), $type['params']); } } public function onPreSerializeTypedProxy(PreSerializeEvent $event, $eventName, $class, $format, EventDispatcherInterface $dispatcher) { $type = $event->getType(); // is a virtual type? then there is no need to change the event name if (!class_exists($type['name'], false)) { return; } $object = $event->getObject(); if ($object instanceof Proxy) { $parentClassName = get_parent_class($object); // check if this is already a re-dispatch if (strtolower($class) !== strtolower($parentClassName)) { $event->stopPropagation(); $newEvent = new PreSerializeEvent($event->getContext(), $object, array('name' => $parentClassName, 'params' => $type['params'])); $dispatcher->dispatch($eventName, $parentClassName, $format, $newEvent); // update the type in case some listener changed it $newType = $newEvent->getType(); $event->setType($newType['name'], $newType['params']); } } } public static function getSubscribedEvents() { return array( array('event' => 'serializer.pre_serialize', 'method' => 'onPreSerializeTypedProxy'), array('event' => 'serializer.pre_serialize', 'method' => 'onPreSerialize'), ); } } serializer/src/JMS/Serializer/EventDispatcher/Subscriber/SymfonyValidatorSubscriber.php 0000644 00000002332 14736103242 0025512 0 ustar 00 <?php namespace JMS\Serializer\EventDispatcher\Subscriber; use JMS\Serializer\EventDispatcher\Event; use JMS\Serializer\EventDispatcher\EventSubscriberInterface; use JMS\Serializer\Exception\ValidationFailedException; use Symfony\Component\Validator\ValidatorInterface; class SymfonyValidatorSubscriber implements EventSubscriberInterface { private $validator; public function __construct(ValidatorInterface $validator) { $this->validator = $validator; } public static function getSubscribedEvents() { return array( array('event' => 'serializer.post_deserialize', 'method' => 'onPostDeserialize'), ); } public function onPostDeserialize(Event $event) { $context = $event->getContext(); if ($context->getDepth() > 0) { return; } $validator = $this->validator; $context->attributes->get('validation_groups')->map( function (array $groups) use ($event, $validator) { $list = $validator->validate($event->getObject(), $groups); if ($list->count() > 0) { throw new ValidationFailedException($list); } } ); } } serializer/src/JMS/Serializer/EventDispatcher/Subscriber/SymfonyValidatorValidatorSubscriber.php 0000644 00000003042 14736103242 0027357 0 ustar 00 <?php namespace JMS\Serializer\EventDispatcher\Subscriber; use JMS\Serializer\EventDispatcher\Event; use JMS\Serializer\EventDispatcher\EventSubscriberInterface; use JMS\Serializer\Exception\ValidationFailedException; use PhpOption\None; use Symfony\Component\Validator\Validator\ValidatorInterface; class SymfonyValidatorValidatorSubscriber implements EventSubscriberInterface { /** * @var ValidatorInterface */ private $validator; public function __construct(ValidatorInterface $validator) { $this->validator = $validator; } public static function getSubscribedEvents() { return array( array('event' => 'serializer.post_deserialize', 'method' => 'onPostDeserialize'), ); } public function onPostDeserialize(Event $event) { $context = $event->getContext(); if ($context->getDepth() > 0) { return; } $validator = $this->validator; $groups = $context->attributes->get('validation_groups') instanceof None ? null : $context->attributes->get('validation_groups')->get(); if (!$groups) { return; } $constraints = $context->attributes->get('validation_constraints') instanceof None ? null : $context->attributes->get('validation_constraints')->get(); $list = $validator->validate($event->getObject(), $constraints, $groups); if ($list->count() > 0) { throw new ValidationFailedException($list); } } } serializer/src/JMS/Serializer/EventDispatcher/PreSerializeEvent.php 0000644 00000000500 14736103242 0021444 0 ustar 00 <?php namespace JMS\Serializer\EventDispatcher; class PreSerializeEvent extends ObjectEvent { /** * @param string $typeName * @param array $params */ public function setType($typeName, array $params = array()) { $this->type = array('name' => $typeName, 'params' => $params); } } serializer/src/JMS/Serializer/EventDispatcher/PreDeserializeEvent.php 0000644 00000001153 14736103242 0021762 0 ustar 00 <?php namespace JMS\Serializer\EventDispatcher; use JMS\Serializer\DeserializationContext; class PreDeserializeEvent extends Event { private $data; public function __construct(DeserializationContext $context, $data, array $type) { parent::__construct($context, $type); $this->data = $data; } public function setType($name, array $params = array()) { $this->type = array('name' => $name, 'params' => $params); } public function getData() { return $this->data; } public function setData($data) { $this->data = $data; } } serializer/src/JMS/Serializer/EventDispatcher/ObjectEvent.php 0000644 00000000570 14736103242 0020263 0 ustar 00 <?php namespace JMS\Serializer\EventDispatcher; use JMS\Serializer\Context; class ObjectEvent extends Event { private $object; public function __construct(Context $context, $object, array $type) { parent::__construct($context, $type); $this->object = $object; } public function getObject() { return $this->object; } } serializer/src/JMS/Serializer/EventDispatcher/Events.php 0000644 00000000546 14736103242 0017322 0 ustar 00 <?php namespace JMS\Serializer\EventDispatcher; abstract class Events { const PRE_SERIALIZE = 'serializer.pre_serialize'; const POST_SERIALIZE = 'serializer.post_serialize'; const PRE_DESERIALIZE = 'serializer.pre_deserialize'; const POST_DESERIALIZE = 'serializer.post_deserialize'; final private function __construct() { } } serializer/src/JMS/Serializer/EventDispatcher/Event.php 0000644 00000002435 14736103242 0017136 0 ustar 00 <?php namespace JMS\Serializer\EventDispatcher; use JMS\Serializer\Context; class Event { /** * @var bool Whether no further event listeners should be triggered */ private $propagationStopped = false; protected $type; private $context; public function __construct(Context $context, array $type) { $this->context = $context; $this->type = $type; } public function getVisitor() { return $this->context->getVisitor(); } public function getContext() { return $this->context; } public function getType() { return $this->type; } /** * Returns whether further event listeners should be triggered. * * @see Event::stopPropagation() * * @return bool Whether propagation was already stopped for this event */ public function isPropagationStopped() { return $this->propagationStopped; } /** * Stops the propagation of the event to further event listeners. * * If multiple event listeners are connected to the same event, no * further event listener will be triggered once any trigger calls * stopPropagation(). */ public function stopPropagation() { $this->propagationStopped = true; } } serializer/src/JMS/Serializer/EventDispatcher/EventDispatcher.php 0000644 00000007323 14736103242 0021146 0 ustar 00 <?php namespace JMS\Serializer\EventDispatcher; use JMS\Serializer\Exception\InvalidArgumentException; /** * Light-weight event dispatcher. * * This implementation focuses primarily on performance, and dispatching * events for certain classes. It is not a general purpose event dispatcher. * * @author Johannes M. Schmitt <schmittjoh@gmail.com> */ class EventDispatcher implements EventDispatcherInterface { private $listeners = array(); private $classListeners = array(); public static function getDefaultMethodName($eventName) { return 'on' . str_replace(array('_', '.'), '', $eventName); } /** * Sets the listeners. * * @param array $listeners */ public function setListeners(array $listeners) { $this->listeners = $listeners; $this->classListeners = array(); } public function addListener($eventName, $callable, $class = null, $format = null) { $this->listeners[$eventName][] = array($callable, null === $class ? null : strtolower($class), $format); unset($this->classListeners[$eventName]); } public function addSubscriber(EventSubscriberInterface $subscriber) { foreach ($subscriber->getSubscribedEvents() as $eventData) { if (!isset($eventData['event'])) { throw new InvalidArgumentException(sprintf('Each event must have a "event" key.')); } $method = isset($eventData['method']) ? $eventData['method'] : self::getDefaultMethodName($eventData['event']); $class = isset($eventData['class']) ? strtolower($eventData['class']) : null; $format = isset($eventData['format']) ? $eventData['format'] : null; $this->listeners[$eventData['event']][] = array(array($subscriber, $method), $class, $format); unset($this->classListeners[$eventData['event']]); } } public function hasListeners($eventName, $class, $format) { if (!isset($this->listeners[$eventName])) { return false; } $loweredClass = strtolower($class); if (!isset($this->classListeners[$eventName][$loweredClass][$format])) { $this->classListeners[$eventName][$loweredClass][$format] = $this->initializeListeners($eventName, $loweredClass, $format); } return !!$this->classListeners[$eventName][$loweredClass][$format]; } public function dispatch($eventName, $class, $format, Event $event) { if (!isset($this->listeners[$eventName])) { return; } $loweredClass = strtolower($class); if (!isset($this->classListeners[$eventName][$loweredClass][$format])) { $this->classListeners[$eventName][$loweredClass][$format] = $this->initializeListeners($eventName, $loweredClass, $format); } foreach ($this->classListeners[$eventName][$loweredClass][$format] as $listener) { if ($event->isPropagationStopped()) { break; } \call_user_func($listener, $event, $eventName, $loweredClass, $format, $this); } } /** * @param string $eventName * @param string $loweredClass * @param string $format * * @return array An array of listeners */ protected function initializeListeners($eventName, $loweredClass, $format) { $listeners = array(); foreach ($this->listeners[$eventName] as $listener) { if (null !== $listener[1] && $loweredClass !== $listener[1]) { continue; } if (null !== $listener[2] && $format !== $listener[2]) { continue; } $listeners[] = $listener[0]; } return $listeners; } } serializer/src/JMS/Serializer/EventDispatcher/LazyEventDispatcher.php 0000644 00000002405 14736103242 0022002 0 ustar 00 <?php namespace JMS\Serializer\EventDispatcher; use Psr\Container\ContainerInterface as PsrContainerInterface; use Symfony\Component\DependencyInjection\ContainerInterface; class LazyEventDispatcher extends EventDispatcher { private $container; public function __construct($container) { if (!$container instanceof PsrContainerInterface && !$container instanceof ContainerInterface) { throw new \InvalidArgumentException(sprintf('The container must be an instance of %s or %s (%s given).', PsrContainerInterface::class, ContainerInterface::class, \is_object($container) ? \get_class($container) : \gettype($container))); } $this->container = $container; } /** * {@inheritdoc} */ protected function initializeListeners($eventName, $loweredClass, $format) { $listeners = parent::initializeListeners($eventName, $loweredClass, $format); foreach ($listeners as &$listener) { if (!\is_array($listener) || !\is_string($listener[0])) { continue; } if (!$this->container->has($listener[0])) { continue; } $listener[0] = $this->container->get($listener[0]); } return $listeners; } } serializer/src/JMS/Serializer/EventDispatcher/EventSubscriberInterface.php 0000644 00000001115 14736103242 0022775 0 ustar 00 <?php namespace JMS\Serializer\EventDispatcher; interface EventSubscriberInterface { /** * Returns the events to which this class has subscribed. * * Return format: * array( * array('event' => 'the-event-name', 'method' => 'onEventName', 'class' => 'some-class', 'format' => 'json'), * array(...), * ) * * The class may be omitted if the class wants to subscribe to events of all classes. * Same goes for the format key. * * @return array */ public static function getSubscribedEvents(); } serializer/src/JMS/Serializer/YamlSerializationVisitor.php 0000644 00000013012 14736103242 0017776 0 ustar 00 <?php namespace JMS\Serializer; use JMS\Serializer\Accessor\AccessorStrategyInterface; use JMS\Serializer\Metadata\ClassMetadata; use JMS\Serializer\Metadata\PropertyMetadata; use JMS\Serializer\Naming\AdvancedNamingStrategyInterface; use JMS\Serializer\Naming\PropertyNamingStrategyInterface; use JMS\Serializer\Util\Writer; use Symfony\Component\Yaml\Inline; /** * Serialization Visitor for the YAML format. * * @see http://www.yaml.org/spec/ * @author Johannes M. Schmitt <schmittjoh@gmail.com> */ class YamlSerializationVisitor extends AbstractVisitor { public $writer; private $navigator; private $stack; private $metadataStack; private $currentMetadata; public function __construct($namingStrategy, AccessorStrategyInterface $accessorStrategy = null) { parent::__construct($namingStrategy, $accessorStrategy); $this->writer = new Writer(); } public function setNavigator(GraphNavigator $navigator) { $this->navigator = $navigator; $this->writer->reset(); $this->stack = new \SplStack; $this->metadataStack = new \SplStack; } public function visitNull($data, array $type, Context $context) { if ('' === $this->writer->content) { $this->writer->writeln('null'); } return 'null'; } public function visitString($data, array $type, Context $context) { $v = Inline::dump($data); if ('' === $this->writer->content) { $this->writer->writeln($v); } return $v; } /** * @param array $data * @param array $type */ public function visitArray($data, array $type, Context $context) { $isHash = isset($type['params'][1]); $count = $this->writer->changeCount; $isList = (isset($type['params'][0]) && !isset($type['params'][1])) || array_keys($data) === range(0, \count($data) - 1); foreach ($data as $k => $v) { if (null === $v && $context->shouldSerializeNull() !== true) { continue; } if ($isList && !$isHash) { $this->writer->writeln('-'); } else { $this->writer->writeln(Inline::dump($k) . ':'); } $this->writer->indent(); if (null !== $v = $this->navigator->accept($v, $this->getElementType($type), $context)) { $this->writer ->rtrim(false) ->writeln(' ' . $v); } $this->writer->outdent(); } if ($count === $this->writer->changeCount && isset($type['params'][1])) { $this->writer ->rtrim(false) ->writeln(' {}'); } elseif (empty($data)) { $this->writer ->rtrim(false) ->writeln(' []'); } } public function visitBoolean($data, array $type, Context $context) { $v = $data ? 'true' : 'false'; if ('' === $this->writer->content) { $this->writer->writeln($v); } return $v; } public function visitDouble($data, array $type, Context $context) { $v = (string)$data; if ('' === $this->writer->content) { $this->writer->writeln($v); } return $v; } public function visitInteger($data, array $type, Context $context) { $v = (string)$data; if ('' === $this->writer->content) { $this->writer->writeln($v); } return $v; } public function startVisitingObject(ClassMetadata $metadata, $data, array $type, Context $context) { } public function visitProperty(PropertyMetadata $metadata, $data, Context $context) { $v = $this->accessor->getValue($data, $metadata); if ((null === $v && $context->shouldSerializeNull() !== true) || (true === $metadata->skipWhenEmpty && ($v instanceof \ArrayObject || \is_array($v)) && 0 === count($v)) ) { return; } if ($this->namingStrategy instanceof AdvancedNamingStrategyInterface) { $name = $this->namingStrategy->getPropertyName($metadata, $context); } else { $name = $this->namingStrategy->translateName($metadata); } if (!$metadata->inline) { $this->writer ->writeln(Inline::dump($name) . ':') ->indent(); } $this->setCurrentMetadata($metadata); $count = $this->writer->changeCount; if (null !== $v = $this->navigator->accept($v, $metadata->type, $context)) { $this->writer ->rtrim(false) ->writeln(' ' . $v); } elseif ($count === $this->writer->changeCount && !$metadata->inline) { $this->writer->revert(); } if (!$metadata->inline) { $this->writer->outdent(); } $this->revertCurrentMetadata(); } public function endVisitingObject(ClassMetadata $metadata, $data, array $type, Context $context) { } public function setCurrentMetadata(PropertyMetadata $metadata) { $this->metadataStack->push($this->currentMetadata); $this->currentMetadata = $metadata; } public function revertCurrentMetadata() { return $this->currentMetadata = $this->metadataStack->pop(); } public function getNavigator() { return $this->navigator; } public function getResult() { return $this->writer->getContent(); } } serializer/src/JMS/Serializer/XmlDeserializationVisitor.php 0000644 00000033011 14736103242 0020146 0 ustar 00 <?php namespace JMS\Serializer; use JMS\Serializer\Exception\InvalidArgumentException; use JMS\Serializer\Exception\LogicException; use JMS\Serializer\Exception\RuntimeException; use JMS\Serializer\Exception\XmlErrorException; use JMS\Serializer\Metadata\ClassMetadata; use JMS\Serializer\Metadata\PropertyMetadata; use JMS\Serializer\Naming\AdvancedNamingStrategyInterface; class XmlDeserializationVisitor extends AbstractVisitor implements NullAwareVisitorInterface { private $objectStack; private $metadataStack; private $objectMetadataStack; private $currentObject; private $currentMetadata; private $result; private $navigator; private $disableExternalEntities = true; private $doctypeWhitelist = array(); public function enableExternalEntities() { $this->disableExternalEntities = false; } public function setNavigator(GraphNavigator $navigator) { $this->navigator = $navigator; $this->objectStack = new \SplStack; $this->metadataStack = new \SplStack; $this->objectMetadataStack = new \SplStack; $this->result = null; } public function getNavigator() { return $this->navigator; } public function prepare($data) { $data = $this->emptyStringToSpaceCharacter($data); $previous = libxml_use_internal_errors(true); libxml_clear_errors(); $previousEntityLoaderState = libxml_disable_entity_loader($this->disableExternalEntities); if (false !== stripos($data, '<!doctype')) { $internalSubset = $this->getDomDocumentTypeEntitySubset($data); if (!in_array($internalSubset, $this->doctypeWhitelist, true)) { throw new InvalidArgumentException(sprintf( 'The document type "%s" is not allowed. If it is safe, you may add it to the whitelist configuration.', $internalSubset )); } } $doc = simplexml_load_string($data); libxml_use_internal_errors($previous); libxml_disable_entity_loader($previousEntityLoaderState); if (false === $doc) { throw new XmlErrorException(libxml_get_last_error()); } return $doc; } private function emptyStringToSpaceCharacter($data) { return $data === '' ? ' ' : (string)$data; } public function visitNull($data, array $type, Context $context) { return null; } public function visitString($data, array $type, Context $context) { $data = (string)$data; if (null === $this->result) { $this->result = $data; } return $data; } public function visitBoolean($data, array $type, Context $context) { $data = (string)$data; if ('true' === $data || '1' === $data) { $data = true; } elseif ('false' === $data || '0' === $data) { $data = false; } else { throw new RuntimeException(sprintf('Could not convert data to boolean. Expected "true", "false", "1" or "0", but got %s.', json_encode($data))); } if (null === $this->result) { $this->result = $data; } return $data; } public function visitInteger($data, array $type, Context $context) { $data = (integer)$data; if (null === $this->result) { $this->result = $data; } return $data; } public function visitDouble($data, array $type, Context $context) { $data = (double)$data; if (null === $this->result) { $this->result = $data; } return $data; } public function visitArray($data, array $type, Context $context) { // handle key-value-pairs if (null !== $this->currentMetadata && $this->currentMetadata->xmlKeyValuePairs) { if (2 !== count($type['params'])) { throw new RuntimeException('The array type must be specified as "array<K,V>" for Key-Value-Pairs.'); } $this->revertCurrentMetadata(); list($keyType, $entryType) = $type['params']; $result = []; foreach ($data as $key => $v) { $k = $this->navigator->accept($key, $keyType, $context); $result[$k] = $this->navigator->accept($v, $entryType, $context); } return $result; } $entryName = null !== $this->currentMetadata && $this->currentMetadata->xmlEntryName ? $this->currentMetadata->xmlEntryName : 'entry'; $namespace = null !== $this->currentMetadata && $this->currentMetadata->xmlEntryNamespace ? $this->currentMetadata->xmlEntryNamespace : null; if ($namespace === null && $this->objectMetadataStack->count()) { $classMetadata = $this->objectMetadataStack->top(); $namespace = isset($classMetadata->xmlNamespaces['']) ? $classMetadata->xmlNamespaces[''] : $namespace; if ($namespace === null) { $namespaces = $data->getDocNamespaces(); if (isset($namespaces[''])) { $namespace = $namespaces['']; } } } if (null !== $namespace) { $prefix = uniqid('ns-'); $data->registerXPathNamespace($prefix, $namespace); $nodes = $data->xpath("$prefix:$entryName"); } else { $nodes = $data->xpath($entryName); } if (!is_iterable($nodes) || !\count($nodes)) { if (null === $this->result) { return $this->result = array(); } return array(); } switch (\count($type['params'])) { case 0: throw new RuntimeException(sprintf('The array type must be specified either as "array<T>", or "array<K,V>".')); case 1: $result = array(); if (null === $this->result) { $this->result = &$result; } foreach ($nodes as $v) { $result[] = $this->navigator->accept($v, $type['params'][0], $context); } return $result; case 2: if (null === $this->currentMetadata) { throw new RuntimeException('Maps are not supported on top-level without metadata.'); } list($keyType, $entryType) = $type['params']; $result = array(); if (null === $this->result) { $this->result = &$result; } $nodes = $data->children($namespace)->$entryName; foreach ($nodes as $v) { $attrs = $v->attributes(); if (!isset($attrs[$this->currentMetadata->xmlKeyAttribute])) { throw new RuntimeException(sprintf('The key attribute "%s" must be set for each entry of the map.', $this->currentMetadata->xmlKeyAttribute)); } $k = $this->navigator->accept($attrs[$this->currentMetadata->xmlKeyAttribute], $keyType, $context); $result[$k] = $this->navigator->accept($v, $entryType, $context); } return $result; default: throw new LogicException(sprintf('The array type does not support more than 2 parameters, but got %s.', json_encode($type['params']))); } } public function startVisitingObject(ClassMetadata $metadata, $object, array $type, Context $context) { $this->setCurrentObject($object); $this->objectMetadataStack->push($metadata); if (null === $this->result) { $this->result = $this->currentObject; } } public function visitProperty(PropertyMetadata $metadata, $data, Context $context) { if ($this->namingStrategy instanceof AdvancedNamingStrategyInterface) { $name = $this->namingStrategy->getPropertyName($metadata, $context); } else { $name = $this->namingStrategy->translateName($metadata); } if (!$metadata->type) { throw new RuntimeException(sprintf('You must define a type for %s::$%s.', $metadata->reflection->class, $metadata->name)); } if ($metadata->xmlAttribute) { $attributes = $data->attributes($metadata->xmlNamespace); if (isset($attributes[$name])) { $v = $this->navigator->accept($attributes[$name], $metadata->type, $context); $this->accessor->setValue($this->currentObject, $v, $metadata); } return; } if ($metadata->xmlValue) { $v = $this->navigator->accept($data, $metadata->type, $context); $this->accessor->setValue($this->currentObject, $v, $metadata); return; } if ($metadata->xmlCollection) { $enclosingElem = $data; if (!$metadata->xmlCollectionInline) { $enclosingElem = $data->children($metadata->xmlNamespace)->$name; } $this->setCurrentMetadata($metadata); $v = $this->navigator->accept($enclosingElem, $metadata->type, $context); $this->revertCurrentMetadata(); $this->accessor->setValue($this->currentObject, $v, $metadata); return; } if ($metadata->xmlNamespace) { $node = $data->children($metadata->xmlNamespace)->$name; if (!$node->count()) { return; } } else { $namespaces = $data->getDocNamespaces(); if (isset($namespaces[''])) { $prefix = uniqid('ns-'); $data->registerXPathNamespace($prefix, $namespaces['']); $nodes = $data->xpath('./' . $prefix . ':' . $name); } else { $nodes = $data->xpath('./' . $name); } if (empty($nodes)) { return; } $node = reset($nodes); } if ($metadata->xmlKeyValuePairs) { $this->setCurrentMetadata($metadata); } $v = $this->navigator->accept($node, $metadata->type, $context); $this->accessor->setValue($this->currentObject, $v, $metadata); } public function endVisitingObject(ClassMetadata $metadata, $data, array $type, Context $context) { $rs = $this->currentObject; $this->objectMetadataStack->pop(); $this->revertCurrentObject(); return $rs; } public function setCurrentObject($object) { $this->objectStack->push($this->currentObject); $this->currentObject = $object; } public function getCurrentObject() { return $this->currentObject; } public function revertCurrentObject() { return $this->currentObject = $this->objectStack->pop(); } public function setCurrentMetadata(PropertyMetadata $metadata) { $this->metadataStack->push($this->currentMetadata); $this->currentMetadata = $metadata; } public function getCurrentMetadata() { return $this->currentMetadata; } public function revertCurrentMetadata() { return $this->currentMetadata = $this->metadataStack->pop(); } public function getResult() { return $this->result; } /** * @param array <string> $doctypeWhitelist */ public function setDoctypeWhitelist(array $doctypeWhitelist) { $this->doctypeWhitelist = $doctypeWhitelist; } /** * @return array<string> */ public function getDoctypeWhitelist() { return $this->doctypeWhitelist; } /** * Retrieves internalSubset even in bugfixed php versions * * @param \DOMDocumentType $child * @param string $data * @return string */ private function getDomDocumentTypeEntitySubset($data) { $startPos = $endPos = stripos($data, '<!doctype'); $braces = 0; do { $char = $data[$endPos++]; if ($char === '<') { ++$braces; } if ($char === '>') { --$braces; } } while ($braces > 0); $internalSubset = substr($data, $startPos, $endPos - $startPos); $internalSubset = str_replace(array("\n", "\r"), '', $internalSubset); $internalSubset = preg_replace('/\s{2,}/', ' ', $internalSubset); $internalSubset = str_replace(array("[ <!", "> ]>"), array('[<!', '>]>'), $internalSubset); return $internalSubset; } /** * @param mixed $value * * @return bool */ public function isNull($value) { if ($value instanceof \SimpleXMLElement) { // Workaround for https://bugs.php.net/bug.php?id=75168 and https://github.com/schmittjoh/serializer/issues/817 // If the "name" is empty means that we are on an not-existent node and subsequent operations on the object will trigger the warning: // "Node no longer exists" if ($value->getName() === "") { // @todo should be "true", but for collections needs a default collection value. maybe something for the 2.0 return false; } $xsiAttributes = $value->attributes('http://www.w3.org/2001/XMLSchema-instance'); if (isset($xsiAttributes['nil']) && ((string) $xsiAttributes['nil'] === 'true' || (string) $xsiAttributes['nil'] === '1') ) { return true; } } return $value === null; } } serializer/src/JMS/Serializer/TypeParser.php 0000644 00000005525 14736103242 0015066 0 ustar 00 <?php namespace JMS\Serializer; /** * Parses a serializer type. * * @author Johannes M. Schmitt <schmittjoh@gmail.com> */ final class TypeParser extends \JMS\Parser\AbstractParser { const T_NAME = 1; const T_STRING = 2; const T_OPEN_BRACKET = 3; const T_CLOSE_BRACKET = 4; const T_COMMA = 5; const T_NONE = 6; public function __construct() { parent::__construct(new \JMS\Parser\SimpleLexer( '/ # PHP Class Names ((?:[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*\\\\)*[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*) # Strings |("(?:[^"]|"")*"|\'(?:[^\']|\'\')*\') # Ignore whitespace |\s* # Terminals |(.) /x', array(self::T_NAME => 'T_NAME', self::T_STRING => 'T_STRING', self::T_OPEN_BRACKET => 'T_OPEN_BRACKET', self::T_CLOSE_BRACKET => 'T_CLOSE_BRACKET', self::T_COMMA => 'T_COMMA', self::T_NONE => 'T_NONE'), function ($value) { switch ($value[0]) { case '"': case "'": return array(TypeParser::T_STRING, substr($value, 1, -1)); case '<': return array(TypeParser::T_OPEN_BRACKET, '<'); case '>': return array(TypeParser::T_CLOSE_BRACKET, '>'); case ',': return array(TypeParser::T_COMMA, ','); default: if (preg_match('/^(?:[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*\\\\)*[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*$/', $value)) { return array(TypeParser::T_NAME, $value); } return array(TypeParser::T_NONE, $value); } } )); } /** * @return array of the format ["name" => string, "params" => array] */ protected function parseInternal() { $typeName = $this->match(self::T_NAME); if (!$this->lexer->isNext(self::T_OPEN_BRACKET)) { return array('name' => $typeName, 'params' => array()); } $this->match(self::T_OPEN_BRACKET); $params = array(); do { if ($this->lexer->isNext(self::T_NAME)) { $params[] = $this->parseInternal(); } else if ($this->lexer->isNext(self::T_STRING)) { $params[] = $this->match(self::T_STRING); } else { $this->matchAny(array(self::T_NAME, self::T_STRING)); // Will throw an exception. } } while ($this->lexer->isNext(self::T_COMMA) && $this->lexer->moveNext()); $this->match(self::T_CLOSE_BRACKET); return array('name' => $typeName, 'params' => $params); } } serializer/src/JMS/Serializer/Annotation/Until.php 0000644 00000000215 14736103242 0016164 0 ustar 00 <?php namespace JMS\Serializer\Annotation; /** * @Annotation * @Target({"PROPERTY", "METHOD"}) */ final class Until extends Version { } serializer/src/JMS/Serializer/Annotation/Inline.php 0000644 00000000212 14736103242 0016304 0 ustar 00 <?php namespace JMS\Serializer\Annotation; /** * @Annotation * @Target({"PROPERTY","METHOD","ANNOTATION"}) */ final class Inline { } serializer/src/JMS/Serializer/Annotation/Since.php 0000644 00000000215 14736103242 0016132 0 ustar 00 <?php namespace JMS\Serializer\Annotation; /** * @Annotation * @Target({"PROPERTY", "METHOD"}) */ final class Since extends Version { } serializer/src/JMS/Serializer/Annotation/XmlCollection.php 0000644 00000000521 14736103242 0017645 0 ustar 00 <?php namespace JMS\Serializer\Annotation; abstract class XmlCollection { /** * @var string */ public $entry = 'entry'; /** * @var boolean */ public $inline = false; /** * @var string */ public $namespace; /** * @var boolean */ public $skipWhenEmpty = true; } serializer/src/JMS/Serializer/Annotation/XmlKeyValuePairs.php 0000644 00000000224 14736103242 0020276 0 ustar 00 <?php namespace JMS\Serializer\Annotation; /** * @Annotation * @Target({"PROPERTY","METHOD","ANNOTATION"}) */ final class XmlKeyValuePairs { } serializer/src/JMS/Serializer/Annotation/PreSerialize.php 0000644 00000000626 14736103242 0017475 0 ustar 00 <?php namespace JMS\Serializer\Annotation; /** * This annotation can be declared on methods which should be called * before the Serialization process. * * These methods do not need to be public, and should do any clean-up, or * preparation of the object that is necessary. * * @Annotation * @Target("METHOD") * @author Johannes M. Schmitt <schmittjoh@gmail.com> */ final class PreSerialize { } serializer/src/JMS/Serializer/Annotation/Version.php 0000644 00000000221 14736103242 0016513 0 ustar 00 <?php namespace JMS\Serializer\Annotation; abstract class Version { /** * @Required * @var string */ public $version; } serializer/src/JMS/Serializer/Annotation/AccessorOrder.php 0000644 00000000557 14736103242 0017640 0 ustar 00 <?php namespace JMS\Serializer\Annotation; /** * Controls the order of properties in a class. * * @Annotation * @Target("CLASS") * @author Johannes M. Schmitt <schmittjoh@gmail.com> */ final class AccessorOrder { /** * @Required * @var string */ public $order; /** * @var array<string> */ public $custom = array(); } serializer/src/JMS/Serializer/Annotation/ExclusionPolicy.php 0000644 00000001217 14736103242 0020225 0 ustar 00 <?php namespace JMS\Serializer\Annotation; use JMS\Serializer\Exception\RuntimeException; /** * @Annotation * @Target("CLASS") */ final class ExclusionPolicy { const NONE = 'NONE'; const ALL = 'ALL'; public $policy; public function __construct(array $values) { if (!\is_string($values['value'])) { throw new RuntimeException('"value" must be a string.'); } $this->policy = strtoupper($values['value']); if (self::NONE !== $this->policy && self::ALL !== $this->policy) { throw new RuntimeException('Exclusion policy must either be "ALL", or "NONE".'); } } } serializer/src/JMS/Serializer/Annotation/SkipWhenEmpty.php 0000644 00000000221 14736103242 0017635 0 ustar 00 <?php namespace JMS\Serializer\Annotation; /** * @Annotation * @Target({"PROPERTY","METHOD","ANNOTATION"}) */ final class SkipWhenEmpty { } serializer/src/JMS/Serializer/Annotation/Groups.php 0000644 00000000306 14736103242 0016351 0 ustar 00 <?php namespace JMS\Serializer\Annotation; /** * @Annotation * @Target({"PROPERTY","METHOD","ANNOTATION"}) */ final class Groups { /** @var array<string> @Required */ public $groups; } serializer/src/JMS/Serializer/Annotation/XmlRoot.php 0000644 00000000361 14736103242 0016477 0 ustar 00 <?php namespace JMS\Serializer\Annotation; /** * @Annotation * @Target("CLASS") */ final class XmlRoot { /** * @Required * @var string */ public $name; /** * @var string */ public $namespace; } serializer/src/JMS/Serializer/Annotation/SerializedName.php 0000644 00000000733 14736103242 0017772 0 ustar 00 <?php namespace JMS\Serializer\Annotation; use JMS\Serializer\Exception\RuntimeException; /** * @Annotation * @Target({"PROPERTY","METHOD", "ANNOTATION"}) */ final class SerializedName { public $name; public function __construct(array $values) { if (!isset($values['value']) || !\is_string($values['value'])) { throw new RuntimeException(sprintf('"value" must be a string.')); } $this->name = $values['value']; } } serializer/src/JMS/Serializer/Annotation/XmlDiscriminator.php 0000644 00000000461 14736103242 0020364 0 ustar 00 <?php namespace JMS\Serializer\Annotation; /** * @Annotation * @Target("CLASS") */ class XmlDiscriminator { /** * @var boolean */ public $attribute = false; /** * @var boolean */ public $cdata = true; /** * @var string */ public $namespace; } serializer/src/JMS/Serializer/Annotation/Discriminator.php 0000644 00000000502 14736103242 0017677 0 ustar 00 <?php namespace JMS\Serializer\Annotation; /** * @Annotation * @Target("CLASS") */ class Discriminator { /** @var array<string> */ public $map; /** @var string */ public $field = 'type'; /** @var boolean */ public $disabled = false; /** @var string[] */ public $groups = array(); } serializer/src/JMS/Serializer/Annotation/XmlValue.php 0000644 00000000312 14736103242 0016624 0 ustar 00 <?php namespace JMS\Serializer\Annotation; /** * @Annotation * @Target({"PROPERTY","METHOD","ANNOTATION"}) */ final class XmlValue { /** * @var boolean */ public $cdata = true; } serializer/src/JMS/Serializer/Annotation/Type.php 0000644 00000000317 14736103242 0016015 0 ustar 00 <?php namespace JMS\Serializer\Annotation; /** * @Annotation * @Target({"PROPERTY", "METHOD","ANNOTATION"}) */ final class Type { /** * @Required * @var string */ public $name; } serializer/src/JMS/Serializer/Annotation/XmlNamespace.php 0000644 00000000367 14736103242 0017456 0 ustar 00 <?php namespace JMS\Serializer\Annotation; /** * @Annotation * @Target("CLASS") */ final class XmlNamespace { /** * @Required * @var string */ public $uri; /** * @var string */ public $prefix = ''; } serializer/src/JMS/Serializer/Annotation/HandlerCallback.php 0000644 00000000522 14736103242 0020064 0 ustar 00 <?php namespace JMS\Serializer\Annotation; /** * @Annotation * @Target("METHOD") * @deprecated * @author Johannes M. Schmitt <schmittjoh@gmail.com> */ final class HandlerCallback { /** * @Required * @var string */ public $format; /** * @Required * @var string */ public $direction; } serializer/src/JMS/Serializer/Annotation/MaxDepth.php 0000644 00000000324 14736103242 0016604 0 ustar 00 <?php namespace JMS\Serializer\Annotation; /** * @Annotation * @Target({"PROPERTY","METHOD","ANNOTATION"}) */ final class MaxDepth { /** * @Required * @var integer */ public $depth; } serializer/src/JMS/Serializer/Annotation/XmlAttribute.php 0000644 00000000313 14736103242 0017514 0 ustar 00 <?php namespace JMS\Serializer\Annotation; /** * @Annotation * @Target({"PROPERTY", "METHOD","ANNOTATION"}) */ final class XmlAttribute { /** * @var string */ public $namespace; } serializer/src/JMS/Serializer/Annotation/XmlElement.php 0000644 00000000410 14736103242 0017140 0 ustar 00 <?php namespace JMS\Serializer\Annotation; /** * @Annotation * @Target({"PROPERTY", "METHOD","ANNOTATION"}) */ final class XmlElement { /** * @var boolean */ public $cdata = true; /** * @var string */ public $namespace; } serializer/src/JMS/Serializer/Annotation/Exclude.php 0000644 00000000246 14736103242 0016466 0 ustar 00 <?php namespace JMS\Serializer\Annotation; /** * @Annotation * @Target({"PROPERTY", "CLASS", "METHOD", "ANNOTATION"}) */ final class Exclude { public $if; } serializer/src/JMS/Serializer/Annotation/XmlMap.php 0000644 00000000346 14736103242 0016274 0 ustar 00 <?php namespace JMS\Serializer\Annotation; /** * @Annotation * @Target({"PROPERTY","METHOD","ANNOTATION"}) */ final class XmlMap extends XmlCollection { /** * @var string */ public $keyAttribute = '_key'; } serializer/src/JMS/Serializer/Annotation/XmlAttributeMap.php 0000644 00000000207 14736103242 0020154 0 ustar 00 <?php namespace JMS\Serializer\Annotation; /** * @Annotation * @Target({"PROPERTY", "METHOD"}) */ final class XmlAttributeMap { } serializer/src/JMS/Serializer/Annotation/Expose.php 0000644 00000000233 14736103242 0016334 0 ustar 00 <?php namespace JMS\Serializer\Annotation; /** * @Annotation * @Target({"PROPERTY", "METHOD","ANNOTATION"}) */ final class Expose { public $if; } serializer/src/JMS/Serializer/Annotation/PostSerialize.php 0000644 00000000167 14736103242 0017674 0 ustar 00 <?php namespace JMS\Serializer\Annotation; /** * @Annotation * @Target("METHOD") */ final class PostSerialize { } serializer/src/JMS/Serializer/Annotation/ReadOnlyProperty.php 0000644 00000000362 14736103242 0020356 0 ustar 00 <?php declare(strict_types=1); namespace JMS\Serializer\Annotation; /** * @Annotation * @Target({"CLASS","PROPERTY"}) * * @final */ /* final */ class ReadOnlyProperty { /** * @var bool */ public $readOnly = true; } serializer/src/JMS/Serializer/Annotation/ReadOnly.php 0000644 00000000412 14736103242 0016605 0 ustar 00 <?php namespace JMS\Serializer\Annotation; /** * @Annotation * @Target({"CLASS","PROPERTY"}) * * @deprecated use `@ReadOnlyProperty` instead */ final class ReadOnly extends ReadOnlyProperty { /** * @var boolean */ public $readOnly = true; } serializer/src/JMS/Serializer/Annotation/PostDeserialize.php 0000644 00000000542 14736103242 0020202 0 ustar 00 <?php namespace JMS\Serializer\Annotation; /** * This annotation can be defined on methods which are called after the * deserialization of the object is complete. * * These methods do not necessarily have to be public. * * @Annotation * @Target("METHOD") * @author Johannes M. Schmitt <schmittjoh@gmail.com> */ final class PostDeserialize { } serializer/src/JMS/Serializer/Annotation/Accessor.php 0000644 00000000434 14736103242 0016636 0 ustar 00 <?php namespace JMS\Serializer\Annotation; /** * @Annotation * @Target("PROPERTY") * * @author Johannes M. Schmitt <schmittjoh@gmail.com> */ final class Accessor { /** * @var string */ public $getter; /** * @var string */ public $setter; } serializer/src/JMS/Serializer/Annotation/VirtualProperty.php 0000644 00000001317 14736103242 0020270 0 ustar 00 <?php namespace JMS\Serializer\Annotation; /** * @Annotation * @Target({"METHOD", "CLASS"}) * * @author Alexander Klimenkov <alx.devel@gmail.com> */ final class VirtualProperty { public $exp; public $name; public $options = array(); public function __construct(array $data) { if (isset($data['value'])) { $data['name'] = $data['value']; unset($data['value']); } foreach ($data as $key => $value) { if (!property_exists(__CLASS__, $key)) { throw new \BadMethodCallException(sprintf('Unknown property "%s" on annotation "%s".', $key, __CLASS__)); } $this->{$key} = $value; } } } serializer/src/JMS/Serializer/Annotation/XmlList.php 0000644 00000000241 14736103242 0016464 0 ustar 00 <?php namespace JMS\Serializer\Annotation; /** * @Annotation * @Target({"PROPERTY","METHOD","ANNOTATION"}) */ final class XmlList extends XmlCollection { } serializer/src/JMS/Serializer/Annotation/AccessType.php 0000644 00000000400 14736103242 0017130 0 ustar 00 <?php namespace JMS\Serializer\Annotation; /** * @Annotation * @Target({"CLASS", "PROPERTY"}) * * @author Johannes M. Schmitt <schmittjoh@gmail.com> */ final class AccessType { /** * @Required * @var string */ public $type; } serializer/src/JMS/Serializer/Context.php 0000644 00000015037 14736103242 0014413 0 ustar 00 <?php namespace JMS\Serializer; use JMS\Serializer\Exception\RuntimeException; use JMS\Serializer\Exclusion\DepthExclusionStrategy; use JMS\Serializer\Exclusion\DisjunctExclusionStrategy; use JMS\Serializer\Exclusion\ExclusionStrategyInterface; use JMS\Serializer\Exclusion\GroupsExclusionStrategy; use JMS\Serializer\Exclusion\VersionExclusionStrategy; use JMS\Serializer\Metadata\ClassMetadata; use JMS\Serializer\Metadata\PropertyMetadata; use Metadata\MetadataFactory; use Metadata\MetadataFactoryInterface; use PhpCollection\Map; abstract class Context { /** * @deprecated use has/get/set attribute methods * @var \PhpCollection\Map */ public $attributes; private $format; /** @var VisitorInterface */ private $visitor; /** @var GraphNavigator */ private $navigator; /** @var MetadataFactory */ private $metadataFactory; /** @var ExclusionStrategyInterface */ private $exclusionStrategy; /** @var boolean|null */ private $serializeNull; private $initialized = false; /** @var \SplStack */ private $metadataStack; public function __construct() { $this->attributes = new Map(); $this->metadataStack = new \SplStack(); } /** * @param string $format */ public function initialize($format, VisitorInterface $visitor, GraphNavigator $navigator, MetadataFactoryInterface $factory) { if ($this->initialized) { throw new \LogicException('This context was already initialized, and cannot be re-used.'); } $this->initialized = true; $this->format = $format; $this->visitor = $visitor; $this->navigator = $navigator; $this->metadataFactory = $factory; $this->metadataStack = new \SplStack(); } /** * @deprecated Will be removed in 2.0, Use getNavigator()->accept() instead * @param $data * @param array|null $type * @return mixed */ public function accept($data, array $type = null) { return $this->navigator->accept($data, $type, $this); } public function getMetadataFactory() { return $this->metadataFactory; } public function getVisitor() { return $this->visitor; } public function getNavigator() { return $this->navigator; } public function getExclusionStrategy() { return $this->exclusionStrategy; } public function hasAttribute($key) { return $this->attributes->get($key)->isDefined(); } public function getAttribute($key) { return $this->attributes->get($key)->get(); } public function setAttribute($key, $value) { $this->assertMutable(); $this->attributes->set($key, $value); return $this; } private function assertMutable() { if (!$this->initialized) { return; } throw new \LogicException('This context was already initialized and is immutable; you cannot modify it anymore.'); } public function addExclusionStrategy(ExclusionStrategyInterface $strategy) { $this->assertMutable(); if (null === $this->exclusionStrategy) { $this->exclusionStrategy = $strategy; return $this; } if ($this->exclusionStrategy instanceof DisjunctExclusionStrategy) { $this->exclusionStrategy->addStrategy($strategy); return $this; } $this->exclusionStrategy = new DisjunctExclusionStrategy(array( $this->exclusionStrategy, $strategy, )); return $this; } /** * @param integer $version */ public function setVersion($version) { if (null === $version) { throw new \LogicException('The version must not be null.'); } $this->attributes->set('version', $version); $this->addExclusionStrategy(new VersionExclusionStrategy($version)); return $this; } /** * @param array|string $groups */ public function setGroups($groups) { if (empty($groups)) { throw new \LogicException('The groups must not be empty.'); } $this->attributes->set('groups', (array)$groups); $this->addExclusionStrategy(new GroupsExclusionStrategy((array)$groups)); return $this; } public function enableMaxDepthChecks() { $this->addExclusionStrategy(new DepthExclusionStrategy()); return $this; } /** * Set if NULLs should be serialized (TRUE) ot not (FALSE) * * @param bool $bool * @return $this */ public function setSerializeNull($bool) { $this->serializeNull = (boolean)$bool; return $this; } /** * Returns TRUE when NULLs should be serialized * Returns FALSE when NULLs should not be serialized * Returns NULL when NULLs should not be serialized, * but the user has not explicitly decided to use this policy * * @return bool|null */ public function shouldSerializeNull() { return $this->serializeNull; } /** * @return string */ public function getFormat() { return $this->format; } public function pushClassMetadata(ClassMetadata $metadata) { $this->metadataStack->push($metadata); } public function pushPropertyMetadata(PropertyMetadata $metadata) { $this->metadataStack->push($metadata); } public function popPropertyMetadata() { $metadata = $this->metadataStack->pop(); if (!$metadata instanceof PropertyMetadata) { throw new RuntimeException('Context metadataStack not working well'); } } public function popClassMetadata() { $metadata = $this->metadataStack->pop(); if (!$metadata instanceof ClassMetadata) { throw new RuntimeException('Context metadataStack not working well'); } } public function getMetadataStack() { return $this->metadataStack; } /** * @return array */ public function getCurrentPath() { if (!$this->metadataStack) { return array(); } $paths = array(); foreach ($this->metadataStack as $metadata) { if ($metadata instanceof PropertyMetadata) { array_unshift($paths, $metadata->name); } } return $paths; } abstract public function getDepth(); /** * @return integer */ abstract public function getDirection(); } serializer/README.md 0000644 00000000664 14736103242 0010204 0 ustar 00 Serializer [![Scrutinizer Quality Score](https://scrutinizer-ci.com/g/schmittjoh/serializer/badges/quality-score.png?s=189df68e00c75d3fe155bc0da0b53b53709a9895)](https://scrutinizer-ci.com/g/schmittjoh/serializer/) [![Build Status](https://travis-ci.org/schmittjoh/serializer.svg?branch=master)](https://travis-ci.org/schmittjoh/serializer) ========== Learn more about it in its [documentation](http://jmsyst.com/libs/serializer/1.x). serializer/CHANGELOG.md 0000644 00000215320 14736103242 0010533 0 ustar 00 # Change Log ## [1.14.1](https://github.com/schmittjoh/serializer/tree/1.14.1) (2020-02-22) **Merged pull requests:** - PHP7.4 ternary operator deprecation [\#1163](https://github.com/schmittjoh/serializer/pull/1163) ([adhocore](https://github.com/adhocore)) ## [1.14.0](https://github.com/schmittjoh/serializer/tree/1.14.0) (2019-04-17) **Implemented enhancements:** - Discriminator property serialization when parent is in discriminator map for v1 [\#982](https://github.com/schmittjoh/serializer/pull/982) ([supersmile2009](https://github.com/supersmile2009)) - Expose and test GroupsExclusionStrategy::getGroupsFor\(\) [\#1069](https://github.com/schmittjoh/serializer/pull/1069) ([goetas](https://github.com/goetas)) ## [1.13.0](https://github.com/schmittjoh/serializer/tree/1.13.0) **Implemented enhancements:** - Bugfix/metadata serialization [\#969](https://github.com/schmittjoh/serializer/pull/969) ([supersmile2009](https://github.com/supersmile2009)) **Fixed bugs:** - Exception on deserialization using XML and exclude-if [\#975](https://github.com/schmittjoh/serializer/issues/975) **Closed issues:** - Serialization fails if root element has custom handler [\#961](https://github.com/schmittjoh/serializer/issues/961) - Make inline property work with deserialization too [\#937](https://github.com/schmittjoh/serializer/issues/937) **Merged pull requests:** - Serializer 2.0 compatibility features [\#967](https://github.com/schmittjoh/serializer/pull/967) ([goetas](https://github.com/goetas)) ## [1.12.1](https://github.com/schmittjoh/serializer/tree/1.12.1) (2018-06-01) **Fixed bugs:** - Accessing static property as non static [\#960](https://github.com/schmittjoh/serializer/issues/960) - creating JMS\Serializer\Metadata-\>closureAccessor on internal class failed [\#959](https://github.com/schmittjoh/serializer/issues/959) ## [1.12.0](https://github.com/schmittjoh/serializer/tree/1.12.0) (2018-05-25) **Implemented enhancements:** - Add support for namespaced XML attribute on Discriminator + Tests [\#909](https://github.com/schmittjoh/serializer/pull/909) ([ArthurJam](https://github.com/ArthurJam)) - Introduce graph navigator interface [\#876](https://github.com/schmittjoh/serializer/pull/876) ([goetas](https://github.com/goetas)) - Use Bind closure accessor [\#875](https://github.com/schmittjoh/serializer/pull/875) ([goetas](https://github.com/goetas)) **Fixed bugs:** - DoctrineObjectConstructor and deserialize not work [\#806](https://github.com/schmittjoh/serializer/issues/806) - \[Symfony\] DoctrineObjectorConstructor always creates new entity because of camel case to snake case conversion [\#734](https://github.com/schmittjoh/serializer/issues/734) - Fix DoctrineObjectConstructor deserialization with naming strategies [\#951](https://github.com/schmittjoh/serializer/pull/951) ([re2bit](https://github.com/re2bit)) **Closed issues:** - Feature proposal: dynamic property serialized name [\#225](https://github.com/schmittjoh/serializer/issues/225) - Mapping request payload works for JSON but not for XML [\#820](https://github.com/schmittjoh/serializer/issues/820) **Merged pull requests:** - Cange the spelling of a word [\#939](https://github.com/schmittjoh/serializer/pull/939) ([greg0ire](https://github.com/greg0ire)) - Use dedicated PHPUnit assertions [\#928](https://github.com/schmittjoh/serializer/pull/928) ([carusogabriel](https://github.com/carusogabriel)) - Update arrays.rst [\#907](https://github.com/schmittjoh/serializer/pull/907) ([burki](https://github.com/burki)) - Change to MIT license [\#956](https://github.com/schmittjoh/serializer/pull/956) ([goetas](https://github.com/goetas)) - Double logic for group exclusion \(20% faster\) [\#941](https://github.com/schmittjoh/serializer/pull/941) ([goetas](https://github.com/goetas)) - Type casting tests [\#917](https://github.com/schmittjoh/serializer/pull/917) ([goetas](https://github.com/goetas)) - Explicitly set serialization precision for tests [\#899](https://github.com/schmittjoh/serializer/pull/899) ([Majkl578](https://github.com/Majkl578)) - Deprecations [\#877](https://github.com/schmittjoh/serializer/pull/877) ([goetas](https://github.com/goetas)) - Added note on SerializedName annotation valididity [\#874](https://github.com/schmittjoh/serializer/pull/874) ([bobvandevijver](https://github.com/bobvandevijver)) - Optimizations [\#861](https://github.com/schmittjoh/serializer/pull/861) ([goetas](https://github.com/goetas)) ## [1.11.0](https://github.com/schmittjoh/serializer/tree/1.11.0) (2018-02-04) **Implemented enhancements:** - Deserialize xmlKeyValuePairs [\#868](https://github.com/schmittjoh/serializer/pull/868) ([goetas](https://github.com/goetas)) - Add AdvancedNamingStrategyInterface [\#859](https://github.com/schmittjoh/serializer/pull/859) ([LeaklessGfy](https://github.com/LeaklessGfy)) - Deserialize xmlKeyValuePairs [\#840](https://github.com/schmittjoh/serializer/pull/840) ([fdyckhoff](https://github.com/fdyckhoff)) **Fixed bugs:** - Exception thrown for non-existant accessor to an excluded property [\#862](https://github.com/schmittjoh/serializer/issues/862) - Support non-namespaced lists in namespaced XML [\#851](https://github.com/schmittjoh/serializer/pull/851) ([bertterheide](https://github.com/bertterheide)) **Closed issues:** - Context Group not working [\#865](https://github.com/schmittjoh/serializer/issues/865) - Not all virtual properties are serialized [\#864](https://github.com/schmittjoh/serializer/issues/864) - DeserializedName [\#857](https://github.com/schmittjoh/serializer/issues/857) - Annotation does not exist, or could not be auto-loaded. [\#855](https://github.com/schmittjoh/serializer/issues/855) - \[Question\] Serialization of primitive types [\#853](https://github.com/schmittjoh/serializer/issues/853) - Empty list when deserializing namespaced XML with children that are not namespaced [\#850](https://github.com/schmittjoh/serializer/issues/850) - XmlList\(skipWhenEmpty=true\) or @SkipWhenEmpty\(\) does not work [\#847](https://github.com/schmittjoh/serializer/issues/847) - DateHandler Timezone ignored on deserialization [\#457](https://github.com/schmittjoh/serializer/issues/457) **Merged pull requests:** - Drop HHVM support [\#869](https://github.com/schmittjoh/serializer/pull/869) ([goetas](https://github.com/goetas)) - Allow excluded private properties to not have a getter acc… [\#863](https://github.com/schmittjoh/serializer/pull/863) ([0mars](https://github.com/0mars)) - Solve php 7.2 deprecations [\#860](https://github.com/schmittjoh/serializer/pull/860) ([goetas](https://github.com/goetas)) - Fixed issue where timezone is lost when creating DateTime from unix timestamp [\#835](https://github.com/schmittjoh/serializer/pull/835) ([goetas](https://github.com/goetas)) ## [1.10.0](https://github.com/schmittjoh/serializer/tree/1.10.0) (2017-11-30) **Implemented enhancements:** - support PSR-11 compatible DI containers [\#844](https://github.com/schmittjoh/serializer/pull/844) ([xabbuh](https://github.com/xabbuh)) **Closed issues:** - Serialize using jsonSerialize\(\) if object implements JsonSerializable [\#846](https://github.com/schmittjoh/serializer/issues/846) - ExclusionStrategy backward compatibility break [\#843](https://github.com/schmittjoh/serializer/issues/843) - @MaxDepth jms/serializer-bundle 2.2 [\#842](https://github.com/schmittjoh/serializer/issues/842) ## [1.9.2](https://github.com/schmittjoh/serializer/tree/1.9.2) (2017-11-22) **Fixed bugs:** - Missing ClassMetadata deserialization data [\#841](https://github.com/schmittjoh/serializer/pull/841) ([TristanMogwai](https://github.com/TristanMogwai)) **Closed issues:** - DateTime format documentation [\#836](https://github.com/schmittjoh/serializer/issues/836) - Deserialization not working with camelCase [\#831](https://github.com/schmittjoh/serializer/issues/831) **Merged pull requests:** - Fix documentation syntax errors on available types [\#839](https://github.com/schmittjoh/serializer/pull/839) ([andy-morgan](https://github.com/andy-morgan)) - Improve documentation about default DateTime format [\#838](https://github.com/schmittjoh/serializer/pull/838) ([enumag](https://github.com/enumag)) ## [1.9.1](https://github.com/schmittjoh/serializer/tree/1.9.1) (2017-10-27) **Fixed bugs:** - Dynamic exclusion strategy, Variable "object" is not valid [\#826](https://github.com/schmittjoh/serializer/issues/826) **Closed issues:** - Allow DateTime or Null [\#779](https://github.com/schmittjoh/serializer/issues/779) **Merged pull requests:** - Alow to use "object" var in expressions when deserializing [\#827](https://github.com/schmittjoh/serializer/pull/827) ([goetas](https://github.com/goetas)) ## [1.9.0](https://github.com/schmittjoh/serializer/tree/1.9.0) (2017-09-28) **Implemented enhancements:** - Doctrine LazyCriteriaCollection not supported [\#814](https://github.com/schmittjoh/serializer/issues/814) - Do not require the translator [\#824](https://github.com/schmittjoh/serializer/pull/824) ([goetas](https://github.com/goetas)) - Added mapping for guid type [\#802](https://github.com/schmittjoh/serializer/pull/802) ([develth](https://github.com/develth)) - Added translation domain to FormErrorHandler [\#783](https://github.com/schmittjoh/serializer/pull/783) ([prosalov](https://github.com/prosalov)) **Fixed bugs:** - Node no longer exists - Deserialize Error [\#817](https://github.com/schmittjoh/serializer/issues/817) - Serializer fails if there is no AnnotationDriver in the DriverChain instance [\#815](https://github.com/schmittjoh/serializer/issues/815) - Evaluate XML xsi:nil="1" to null [\#799](https://github.com/schmittjoh/serializer/pull/799) ([Bouwdie](https://github.com/Bouwdie)) **Closed issues:** - Empty array removed from XML serialization [\#816](https://github.com/schmittjoh/serializer/issues/816) - XML Discriminator tags don't work in YAML metadata [\#811](https://github.com/schmittjoh/serializer/issues/811) - Launching phpunit does not execute any test [\#809](https://github.com/schmittjoh/serializer/issues/809) - Add "bool" Annotation/Type [\#807](https://github.com/schmittjoh/serializer/issues/807) - Add support for overriding default annotation driver configuration [\#804](https://github.com/schmittjoh/serializer/issues/804) - Add description to PropertyMetadata? [\#800](https://github.com/schmittjoh/serializer/issues/800) **Merged pull requests:** - Workaround to avoid triggering simplexml warning [\#825](https://github.com/schmittjoh/serializer/pull/825) ([goetas](https://github.com/goetas)) - Added null metadata driver [\#822](https://github.com/schmittjoh/serializer/pull/822) ([goetas](https://github.com/goetas)) - Run Travis tests against modern PHP [\#819](https://github.com/schmittjoh/serializer/pull/819) ([Majkl578](https://github.com/Majkl578)) - Added bool type alias [\#818](https://github.com/schmittjoh/serializer/pull/818) ([Majkl578](https://github.com/Majkl578)) - Revert back to PSR-0 [\#797](https://github.com/schmittjoh/serializer/pull/797) ([goetas](https://github.com/goetas)) ## [1.8.1](https://github.com/schmittjoh/serializer/tree/1.8.1) (2017-07-13) **Closed issues:** - Version 1.8 is breaking backwards compatibility [\#796](https://github.com/schmittjoh/serializer/issues/796) ## [1.8.0](https://github.com/schmittjoh/serializer/tree/1.8.0) (2017-07-12) **Implemented enhancements:** - Detect XML xsi:nil="true" to null when deserializing [\#790](https://github.com/schmittjoh/serializer/pull/790) ([goetas](https://github.com/goetas)) - Added support for a third deserialize parameter for the DateTime type [\#788](https://github.com/schmittjoh/serializer/pull/788) ([bobvandevijver](https://github.com/bobvandevijver)) - Added trim to xml metadata reader for groups parameter, and added support for groups element [\#781](https://github.com/schmittjoh/serializer/pull/781) ([mrosiu](https://github.com/mrosiu)) - Add propertyMetdata to dynamic expression variables [\#778](https://github.com/schmittjoh/serializer/pull/778) ([goetas](https://github.com/goetas)) - Fix xml deserialization when xsi:nil="true" is set [\#771](https://github.com/schmittjoh/serializer/pull/771) ([Bouwdie](https://github.com/Bouwdie)) **Fixed bugs:** - do not disappear type params in DoctrineProxySubscriber [\#793](https://github.com/schmittjoh/serializer/pull/793) ([kriswallsmith](https://github.com/kriswallsmith)) - \#784 fix with inline array of type array\<K, V\> [\#785](https://github.com/schmittjoh/serializer/pull/785) ([aviortm](https://github.com/aviortm)) **Closed issues:** - inline array with type array\<K, V\> not serialized [\#784](https://github.com/schmittjoh/serializer/issues/784) - \[2.0\] \[Feature-request\] Provide InitializedObjectConstructor as default [\#775](https://github.com/schmittjoh/serializer/issues/775) - Allow access to PropertyMetadata in Dynamic Exclusion strategies [\#772](https://github.com/schmittjoh/serializer/issues/772) - Overriding groups at runtime does not work, or? [\#767](https://github.com/schmittjoh/serializer/issues/767) - DateTime format and control characters [\#94](https://github.com/schmittjoh/serializer/issues/94) **Merged pull requests:** - Missing features of the compiler pass [\#789](https://github.com/schmittjoh/serializer/pull/789) ([mikemix](https://github.com/mikemix)) - Updated documentation related to PR \#778 [\#780](https://github.com/schmittjoh/serializer/pull/780) ([bblue](https://github.com/bblue)) - \[RFC\] Move to PSR 4 [\#770](https://github.com/schmittjoh/serializer/pull/770) ([goetas](https://github.com/goetas)) - Re-formatted code for better PSR compliance [\#769](https://github.com/schmittjoh/serializer/pull/769) ([goetas](https://github.com/goetas)) - Proposing some guidelines for contributing [\#763](https://github.com/schmittjoh/serializer/pull/763) ([goetas](https://github.com/goetas)) ## [1.7.1](https://github.com/schmittjoh/serializer/tree/1.7.1) (2017-05-15) **Fixed bugs:** - Custom type handlers does not work with doctrine proxies anymore [\#765](https://github.com/schmittjoh/serializer/issues/765) - Doctrine listener should not change the type on proxies with virtual type [\#768](https://github.com/schmittjoh/serializer/pull/768) ([goetas](https://github.com/goetas)) **Closed issues:** - Missing bool type in graphNavigator.php in method accept\(\) [\#764](https://github.com/schmittjoh/serializer/issues/764) - The sub-class "Proxy-Class" is not listed in the discriminator of the base class "DiscriminatorClass" [\#459](https://github.com/schmittjoh/serializer/issues/459) - Configure whether serializing empty array. [\#124](https://github.com/schmittjoh/serializer/issues/124) ## [1.7.0](https://github.com/schmittjoh/serializer/tree/1.7.0) (2017-05-10) **Implemented enhancements:** - Skip doctrine proxy initializations when exclusion strategy will exclude it [\#760](https://github.com/schmittjoh/serializer/pull/760) ([goetas](https://github.com/goetas)) **Closed issues:** - Error deserializing a map of \(nullable\) objects [\#762](https://github.com/schmittjoh/serializer/issues/762) - Add data using setData produces hashes instead of arrays [\#761](https://github.com/schmittjoh/serializer/issues/761) ## [1.7.0-RC2](https://github.com/schmittjoh/serializer/tree/1.7.0-RC2) (2017-05-05) **Implemented enhancements:** - Make sure input is always a string [\#755](https://github.com/schmittjoh/serializer/pull/755) ([goetas](https://github.com/goetas)) - Allow namespaced XML element discriminator [\#753](https://github.com/schmittjoh/serializer/pull/753) ([goetas](https://github.com/goetas)) **Fixed bugs:** - Allow to skip "empty serialization result" when serializing [\#757](https://github.com/schmittjoh/serializer/pull/757) ([goetas](https://github.com/goetas)) **Closed issues:** - Is it possible to use @XmlNamespace & @XmlRoot in a class at same time ? [\#759](https://github.com/schmittjoh/serializer/issues/759) - Serializes FOS:User datas with ExclusionPolicy\("all"\) [\#599](https://github.com/schmittjoh/serializer/issues/599) **Merged pull requests:** - Add a quick reference for how to enable expression evaluator [\#758](https://github.com/schmittjoh/serializer/pull/758) ([chasen](https://github.com/chasen)) - Allow for setExpressionEvaluator usage to be chainable [\#756](https://github.com/schmittjoh/serializer/pull/756) ([chasen](https://github.com/chasen)) - Fix typo in annotation docs [\#754](https://github.com/schmittjoh/serializer/pull/754) ([JustBlackBird](https://github.com/JustBlackBird)) ## [1.7.0-RC1](https://github.com/schmittjoh/serializer/tree/1.7.0-RC1) (2017-04-25) **Implemented enhancements:** - Allow to configure the doctrine object constructor [\#751](https://github.com/schmittjoh/serializer/pull/751) ([goetas](https://github.com/goetas)) - Trigger doctrine events on doctrine proxies [\#750](https://github.com/schmittjoh/serializer/pull/750) ([goetas](https://github.com/goetas)) - Added stdClass serialization handler [\#749](https://github.com/schmittjoh/serializer/pull/749) ([goetas](https://github.com/goetas)) **Fixed bugs:** - Array gets serialized as object, not as array, depending on order. [\#709](https://github.com/schmittjoh/serializer/issues/709) - Doctrine Proxies and serializer.pre\_serialize [\#666](https://github.com/schmittjoh/serializer/issues/666) - Fix stdClass inconsistencies when serializing to JSON [\#730](https://github.com/schmittjoh/serializer/pull/730) ([goetas](https://github.com/goetas)) - Allow to typehint for the type \(array/hash\) of the root item to be serialized [\#728](https://github.com/schmittjoh/serializer/pull/728) ([goetas](https://github.com/goetas)) **Closed issues:** - Array serialized as JSON object [\#706](https://github.com/schmittjoh/serializer/issues/706) - From old issue \#290 [\#670](https://github.com/schmittjoh/serializer/issues/670) - Form validation error response - field names not converted from camel case to underscore [\#587](https://github.com/schmittjoh/serializer/issues/587) - Ability to getGroups on Context [\#554](https://github.com/schmittjoh/serializer/issues/554) - SerializedName misleading usage and constructor issue [\#548](https://github.com/schmittjoh/serializer/issues/548) - Discriminator should support xmlAttribute [\#547](https://github.com/schmittjoh/serializer/issues/547) - Public method accessor is required for excluded/not exposed properties [\#519](https://github.com/schmittjoh/serializer/issues/519) - Entity changed via preserialize and wrongly persisted [\#509](https://github.com/schmittjoh/serializer/issues/509) - XML deserialization properties null when using default namespace [\#504](https://github.com/schmittjoh/serializer/issues/504) - AccessorOrder is ignored [\#501](https://github.com/schmittjoh/serializer/issues/501) - Deserialization of sub entites with non existing id [\#492](https://github.com/schmittjoh/serializer/issues/492) - \[Question\] Handler/Converter for specific field [\#476](https://github.com/schmittjoh/serializer/issues/476) - getClassName regex may incorrectly retrieve a false class name from comments above the class. [\#460](https://github.com/schmittjoh/serializer/issues/460) - Multiple types for property? [\#445](https://github.com/schmittjoh/serializer/issues/445) - Allow non-qualified XML serialization when XML namespaces are part of the metadata [\#413](https://github.com/schmittjoh/serializer/issues/413) - Discriminator field name [\#412](https://github.com/schmittjoh/serializer/issues/412) - Serializing to and deserializing from DateTime is inconsistent [\#394](https://github.com/schmittjoh/serializer/issues/394) - ManyToOne and OneToMany Serialization Groups [\#387](https://github.com/schmittjoh/serializer/issues/387) - Static SubscribingHandlerInterface::getSubscribingMethod [\#380](https://github.com/schmittjoh/serializer/issues/380) - User defined ordering function [\#379](https://github.com/schmittjoh/serializer/issues/379) - serialized\_name for discriminator [\#372](https://github.com/schmittjoh/serializer/issues/372) - Serializing object with empty array [\#350](https://github.com/schmittjoh/serializer/issues/350) - VirtualProperty\(s\) are ignored with AccessorOrder [\#349](https://github.com/schmittjoh/serializer/issues/349) - When setting a group of serialization, the inheritance doesn't work anymore [\#328](https://github.com/schmittjoh/serializer/issues/328) - Serialization of empty object [\#323](https://github.com/schmittjoh/serializer/issues/323) - "Can't pop from an empty datastructure" error when multiple serializer calls [\#319](https://github.com/schmittjoh/serializer/issues/319) - virtual\_properties cannot be excluded with groups [\#291](https://github.com/schmittjoh/serializer/issues/291) - Integer serialized as String using VirtualProperty [\#289](https://github.com/schmittjoh/serializer/issues/289) - SimpleObjectProxy is not implement abstract methods of Proxy class [\#287](https://github.com/schmittjoh/serializer/issues/287) - Serializing array that have one of the element or member of an element an empty object [\#277](https://github.com/schmittjoh/serializer/issues/277) - Serialization with groups return json object instead array [\#267](https://github.com/schmittjoh/serializer/issues/267) - The purpose of "Force JSON output to "{}" instead of "\[\]" if it contains either no properties or all properties are null" [\#248](https://github.com/schmittjoh/serializer/issues/248) - Json array serialisation [\#242](https://github.com/schmittjoh/serializer/issues/242) - Ignoring "Assert" in output doc if excluded [\#241](https://github.com/schmittjoh/serializer/issues/241) - Alphabetical accessor order doesn't respect SerializedName overrides [\#240](https://github.com/schmittjoh/serializer/issues/240) - Request Annotation for Array Data [\#234](https://github.com/schmittjoh/serializer/issues/234) - Allow @var instead of @Type when deserializing [\#233](https://github.com/schmittjoh/serializer/issues/233) - Strange issue with groups exclusion strategy [\#230](https://github.com/schmittjoh/serializer/issues/230) - Warning when deserializing removed entity [\#216](https://github.com/schmittjoh/serializer/issues/216) - Where in the JMS code does the navigator call VisitProperty method for visitor [\#207](https://github.com/schmittjoh/serializer/issues/207) - Property of the type array is not in alphabetic order after serialization [\#196](https://github.com/schmittjoh/serializer/issues/196) - Magic and inconsistencies in array serialization [\#191](https://github.com/schmittjoh/serializer/issues/191) - PreSerialization Event not handled if the value is not object [\#162](https://github.com/schmittjoh/serializer/issues/162) - Hierarchical object serialization does not appear to inherit metadata from ancestors for metadata defined in XML [\#151](https://github.com/schmittjoh/serializer/issues/151) - When using MaxDepth, Serialization of an array entitiy is not working [\#132](https://github.com/schmittjoh/serializer/issues/132) - Switch to change default naming strategy [\#128](https://github.com/schmittjoh/serializer/issues/128) - Throw exceptions on invalid input [\#112](https://github.com/schmittjoh/serializer/issues/112) - Recursion detected error when serialization groups are in use [\#96](https://github.com/schmittjoh/serializer/issues/96) - Allow serialization groups to be accessible within event subscriber callbacks. [\#84](https://github.com/schmittjoh/serializer/issues/84) - Allow Constructed Object to be Passed to Deserialize [\#79](https://github.com/schmittjoh/serializer/issues/79) - JSON recursion when first object in root list is empty [\#61](https://github.com/schmittjoh/serializer/issues/61) - Can't serialize an array with an empty object [\#59](https://github.com/schmittjoh/serializer/issues/59) **Merged pull requests:** - Added runtime twig extension support \(significant performance improvements\) [\#747](https://github.com/schmittjoh/serializer/pull/747) ([goetas](https://github.com/goetas)) ## [1.6.2](https://github.com/schmittjoh/serializer/tree/1.6.2) (2017-04-17) **Fixed bugs:** - @VirtualProperty "exp" does not play nice with @ExclusionPolicy\("ALL"\) [\#746](https://github.com/schmittjoh/serializer/issues/746) ## [1.6.1](https://github.com/schmittjoh/serializer/tree/1.6.1) (2017-04-12) **Fixed bugs:** - Do not output the XML node when the object will be emtpy [\#744](https://github.com/schmittjoh/serializer/pull/744) ([goetas](https://github.com/goetas)) **Closed issues:** - XmlList not working since version 1.5.0 with xmlns attributes [\#742](https://github.com/schmittjoh/serializer/issues/742) - DoctrineObjectConstructor: how to use it without Symfony, in a PHP project [\#741](https://github.com/schmittjoh/serializer/issues/741) - Outdated docs site [\#733](https://github.com/schmittjoh/serializer/issues/733) - Why do we need this check inside SerializedName constructor, if there is name? [\#558](https://github.com/schmittjoh/serializer/issues/558) - Is it possible to deserialize Collection from Json [\#534](https://github.com/schmittjoh/serializer/issues/534) - PhpCollection 0.4 [\#531](https://github.com/schmittjoh/serializer/issues/531) - Possible mismatch of xml-attribute-map and $pMetadata-\>xmlAttribute in XmlDriver.php [\#422](https://github.com/schmittjoh/serializer/issues/422) - Access level propose for Handler/DateHandler.php [\#386](https://github.com/schmittjoh/serializer/issues/386) - Type DateTime and Timestamp \(U format\) [\#343](https://github.com/schmittjoh/serializer/issues/343) **Merged pull requests:** - Update PHPDocs [\#736](https://github.com/schmittjoh/serializer/pull/736) ([gnat42](https://github.com/gnat42)) ## [1.6.0](https://github.com/schmittjoh/serializer/tree/1.6.0) (2017-03-24) **Implemented enhancements:** - Add DateTimeImmutable support to DateHandler [\#543](https://github.com/schmittjoh/serializer/issues/543) **Fixed bugs:** - Virtual property having type overriden by doctrine metadata [\#276](https://github.com/schmittjoh/serializer/issues/276) **Closed issues:** - Serialize a subclass [\#735](https://github.com/schmittjoh/serializer/issues/735) - How to handle Doctrine not found entity ? [\#731](https://github.com/schmittjoh/serializer/issues/731) - Regression with 1.5.0 =\> Undefined offset 15 [\#715](https://github.com/schmittjoh/serializer/issues/715) - detect serialisation without groups set [\#546](https://github.com/schmittjoh/serializer/issues/546) - Introducing the NormalizerInterface [\#537](https://github.com/schmittjoh/serializer/issues/537) - How to set JSON serialization options? [\#535](https://github.com/schmittjoh/serializer/issues/535) - @MaxDepth doesn't seem to be working [\#522](https://github.com/schmittjoh/serializer/issues/522) - max\_depth in YML config is ignored [\#498](https://github.com/schmittjoh/serializer/issues/498) - Dynamic property type annotation [\#436](https://github.com/schmittjoh/serializer/issues/436) - How to deserialize JSON if property might have a list of subobjects? [\#355](https://github.com/schmittjoh/serializer/issues/355) - Object to array normalization [\#354](https://github.com/schmittjoh/serializer/issues/354) - Serialize Doctrine object without references [\#353](https://github.com/schmittjoh/serializer/issues/353) - Post\_serialize doesn't serialize relation! [\#236](https://github.com/schmittjoh/serializer/issues/236) - parsing string to date [\#217](https://github.com/schmittjoh/serializer/issues/217) - Discriminator is not exposed when using a group exclusion strategy [\#157](https://github.com/schmittjoh/serializer/issues/157) ## [1.6.0-RC1](https://github.com/schmittjoh/serializer/tree/1.6.0-RC1) (2017-03-14) **Implemented enhancements:** - Add symfony expression in exclusions/expositions [\#406](https://github.com/schmittjoh/serializer/issues/406) - check that cache directory was not created before throwing exception [\#729](https://github.com/schmittjoh/serializer/pull/729) ([mente](https://github.com/mente)) - \#720 - Adding support for DateInterval deserialization [\#721](https://github.com/schmittjoh/serializer/pull/721) ([c0ntax](https://github.com/c0ntax)) - Expression language based virtual properties [\#708](https://github.com/schmittjoh/serializer/pull/708) ([goetas](https://github.com/goetas)) - Added clearing previous libxml errors [\#688](https://github.com/schmittjoh/serializer/pull/688) ([zerkms](https://github.com/zerkms)) - Xml namespaces improvements [\#644](https://github.com/schmittjoh/serializer/pull/644) ([goetas](https://github.com/goetas)) **Fixed bugs:** - Serialize correctly empty intervals according to ISO-8601 [\#722](https://github.com/schmittjoh/serializer/pull/722) ([goetas](https://github.com/goetas)) **Closed issues:** - Is it possible to achieve something like - shouldSerializeEmpty [\#725](https://github.com/schmittjoh/serializer/issues/725) - How to handle DateTime serialization with fromArray method ? [\#723](https://github.com/schmittjoh/serializer/issues/723) - DateInterval supported for serialization but not deserialization [\#720](https://github.com/schmittjoh/serializer/issues/720) - Deserialization of collection when wraped by aditional xml tags [\#719](https://github.com/schmittjoh/serializer/issues/719) - SerializedName based on a property value [\#716](https://github.com/schmittjoh/serializer/issues/716) - Blank XML breaks XmlDeserializationVisitor error handling [\#701](https://github.com/schmittjoh/serializer/issues/701) - Problem with FOSUserBundle ROLE serialization [\#690](https://github.com/schmittjoh/serializer/issues/690) - Doctrine cache dependency when using setCacheDir [\#676](https://github.com/schmittjoh/serializer/issues/676) - OneToOne entities are not deserialized if passing a nested one-to-one property [\#652](https://github.com/schmittjoh/serializer/issues/652) - \[RFC\] Serialization refacotring [\#609](https://github.com/schmittjoh/serializer/issues/609) - Object handler callback returns array, but serialized object = null [\#594](https://github.com/schmittjoh/serializer/issues/594) - Cannot add @Discriminator field into specific @Group [\#557](https://github.com/schmittjoh/serializer/issues/557) - Object check on SerializationContext::isVisiting\(\) [\#502](https://github.com/schmittjoh/serializer/issues/502) - Define cdata and namespace for @XmlList elements [\#480](https://github.com/schmittjoh/serializer/issues/480) - Serializer working with parent class [\#376](https://github.com/schmittjoh/serializer/issues/376) - Add support for array format [\#374](https://github.com/schmittjoh/serializer/issues/374) - Obtain VirtualProperty value using a service [\#359](https://github.com/schmittjoh/serializer/issues/359) - make deserialisation of non existing id's configurable [\#333](https://github.com/schmittjoh/serializer/issues/333) - HHVM compatibility issue with undefined property JMS\Serializer\Metadata\ClassMetadata::$inline [\#312](https://github.com/schmittjoh/serializer/issues/312) - resources serialization [\#275](https://github.com/schmittjoh/serializer/issues/275) - I'm receiving "Class ArrayCollection does not exist" when serializing \(temporarily solved with a workaround\) [\#274](https://github.com/schmittjoh/serializer/issues/274) - Can't use handlers on strings \(and other simple types\) [\#194](https://github.com/schmittjoh/serializer/issues/194) - composer.json update for doctrine [\#178](https://github.com/schmittjoh/serializer/issues/178) - Use expression for virtual properties [\#171](https://github.com/schmittjoh/serializer/issues/171) - Handle classes that implement collections \(e.g. ArrayObject\) and properties [\#137](https://github.com/schmittjoh/serializer/issues/137) - Check CDATA is needed [\#136](https://github.com/schmittjoh/serializer/issues/136) - property path support [\#22](https://github.com/schmittjoh/serializer/issues/22) **Merged pull requests:** - Include reference to cache [\#727](https://github.com/schmittjoh/serializer/pull/727) ([hyperized](https://github.com/hyperized)) - A possible fix for the \#688 [\#689](https://github.com/schmittjoh/serializer/pull/689) ([zerkms](https://github.com/zerkms)) ## [1.5.0](https://github.com/schmittjoh/serializer/tree/1.5.0) (2017-02-14) **Fixed bugs:** - Deserializing XMLList with Namespaces not \(always\) working as intended [\#697](https://github.com/schmittjoh/serializer/pull/697) ([goetas](https://github.com/goetas)) **Closed issues:** - Serialized DateTime instances are not valid ISO-8601 [\#713](https://github.com/schmittjoh/serializer/issues/713) - Impossible to use discriminator field. Why we need StaticPropertyMetadata ? [\#705](https://github.com/schmittjoh/serializer/issues/705) - Deserializing XMLList with Namespaces not \(always\) working as intended [\#695](https://github.com/schmittjoh/serializer/issues/695) ## [1.5.0-RC1](https://github.com/schmittjoh/serializer/tree/1.5.0-RC1) (2017-01-19) **Implemented enhancements:** - added support for xml-attributes as discriminators [\#692](https://github.com/schmittjoh/serializer/pull/692) ([twtinteractive](https://github.com/twtinteractive)) - Prevent doctrine proxy loading for virtual types [\#684](https://github.com/schmittjoh/serializer/pull/684) ([goetas](https://github.com/goetas)) - Implemented dynamic exclusion using symfony expression language [\#673](https://github.com/schmittjoh/serializer/pull/673) ([goetas](https://github.com/goetas)) - Issue543 - Adding DateTimeImmutable support [\#635](https://github.com/schmittjoh/serializer/pull/635) ([toby-griffiths](https://github.com/toby-griffiths)) **Closed issues:** - Groups logic [\#693](https://github.com/schmittjoh/serializer/issues/693) - BC from 1.1.\* to ^1.2 [\#643](https://github.com/schmittjoh/serializer/issues/643) - DoctrineProxySubscriber forces loading of the proxy even if custom handler exist [\#575](https://github.com/schmittjoh/serializer/issues/575) - ConditionalExpose/Exclude annotation [\#540](https://github.com/schmittjoh/serializer/issues/540) - Deprecated usage of ValidatorInterface [\#438](https://github.com/schmittjoh/serializer/issues/438) - Missing addData in XmlSerializerVisitor makes it impossible to add data in serializer.post\_serialize event [\#235](https://github.com/schmittjoh/serializer/issues/235) - Support JSON PATCH for updating object graph [\#231](https://github.com/schmittjoh/serializer/issues/231) - Dynamic expose, aka 'fields' query param [\#195](https://github.com/schmittjoh/serializer/issues/195) **Merged pull requests:** - Added doc reference for disabling discriminator [\#699](https://github.com/schmittjoh/serializer/pull/699) ([dragosprotung](https://github.com/dragosprotung)) - Use GroupsExclusionStrategy::DEFAULT\_GROUP instead default group. [\#694](https://github.com/schmittjoh/serializer/pull/694) ([Aliance](https://github.com/Aliance)) - Improved Symfony 3.x compatibility [\#682](https://github.com/schmittjoh/serializer/pull/682) ([goetas](https://github.com/goetas)) - Discriminator Groups [\#579](https://github.com/schmittjoh/serializer/pull/579) ([maennchen](https://github.com/maennchen)) - Add extra test for handling child elements [\#569](https://github.com/schmittjoh/serializer/pull/569) ([tarjei](https://github.com/tarjei)) ## [1.4.2](https://github.com/schmittjoh/serializer/tree/1.4.2) (2016-11-13) **Fixed bugs:** - Warning: JMS\Serializer\XmlDeserializationVisitor::visitArray\(\): Node no longer exists [\#674](https://github.com/schmittjoh/serializer/issues/674) - Fixed xml arrays with namespaced entry triggers error [\#675](https://github.com/schmittjoh/serializer/pull/675) ([goetas](https://github.com/goetas)) **Closed issues:** - Max depth produces array of nulls [\#671](https://github.com/schmittjoh/serializer/issues/671) ## [1.4.1](https://github.com/schmittjoh/serializer/tree/1.4.1) (2016-11-02) **Fixed bugs:** - Groups context might be not initialized [\#669](https://github.com/schmittjoh/serializer/pull/669) ([goetas](https://github.com/goetas)) **Closed issues:** - Warning: Invalid argument supplied for foreach\(\) on getCurrentPath method [\#668](https://github.com/schmittjoh/serializer/issues/668) ## [1.4.0](https://github.com/schmittjoh/serializer/tree/1.4.0) (2016-10-31) **Implemented enhancements:** - Document the implied 'Default' property group when no group is specified [\#661](https://github.com/schmittjoh/serializer/pull/661) ([akoebbe](https://github.com/akoebbe)) - Allow discriminator map in the middle of the hierarchy when deserializing [\#659](https://github.com/schmittjoh/serializer/pull/659) ([goetas](https://github.com/goetas)) - Handle both int and integer [\#657](https://github.com/schmittjoh/serializer/pull/657) ([Aliance](https://github.com/Aliance)) - Can now override groups on specific paths of the graph [\#170](https://github.com/schmittjoh/serializer/pull/170) ([adrienbrault](https://github.com/adrienbrault)) **Fixed bugs:** - Deserialization fails when discriminator base class extends another class [\#182](https://github.com/schmittjoh/serializer/issues/182) - Xml setters ignored when deserializing [\#665](https://github.com/schmittjoh/serializer/pull/665) ([goetas](https://github.com/goetas)) **Closed issues:** - Move `FormErrorHandler` to the bundle [\#664](https://github.com/schmittjoh/serializer/issues/664) - Not compatible with Symfony 3's Controller::json\(\) [\#663](https://github.com/schmittjoh/serializer/issues/663) - Class name not reflecting in serialized json [\#662](https://github.com/schmittjoh/serializer/issues/662) - YML virtual\_properties no group exlcusion [\#656](https://github.com/schmittjoh/serializer/issues/656) - \[RFC\] Introduce normalizer\denormalizer interface [\#646](https://github.com/schmittjoh/serializer/issues/646) - Plain arrays are serialized \(normalized\) as "objects", ignoring serializeNull [\#641](https://github.com/schmittjoh/serializer/issues/641) - serializer doesn't serialize traits [\#638](https://github.com/schmittjoh/serializer/issues/638) - Add metadata informations [\#637](https://github.com/schmittjoh/serializer/issues/637) - Unexpected results when serializing arrays containing null value elements [\#593](https://github.com/schmittjoh/serializer/issues/593) - Allow to set default serialization context when building serializer [\#528](https://github.com/schmittjoh/serializer/issues/528) - Enable Sourcegraph [\#455](https://github.com/schmittjoh/serializer/issues/455) - Use different accessor for each group [\#420](https://github.com/schmittjoh/serializer/issues/420) - GenericSerializationVisitor and shouldSerializeNull [\#360](https://github.com/schmittjoh/serializer/issues/360) - Specify group along with MaxDepth [\#150](https://github.com/schmittjoh/serializer/issues/150) - Allow Post Serialize Event to overwrite existing data [\#129](https://github.com/schmittjoh/serializer/issues/129) - Warning: array\_key\_exists\(\) expects parameter 2 to be array, string given [\#70](https://github.com/schmittjoh/serializer/issues/70) **Merged pull requests:** - Nullable array inconsistency [\#660](https://github.com/schmittjoh/serializer/pull/660) ([goetas](https://github.com/goetas)) - Fixed PHP 7.0.11 BC break \(or bugfix\) [\#658](https://github.com/schmittjoh/serializer/pull/658) ([goetas](https://github.com/goetas)) - Renamed replaceData to setData [\#653](https://github.com/schmittjoh/serializer/pull/653) ([goetas](https://github.com/goetas)) - add required sqlite extension for developing [\#649](https://github.com/schmittjoh/serializer/pull/649) ([scasei](https://github.com/scasei)) - Run serialization benchmarks in the build process [\#647](https://github.com/schmittjoh/serializer/pull/647) ([goetas](https://github.com/goetas)) - Alcalyn feature default serializer context [\#645](https://github.com/schmittjoh/serializer/pull/645) ([goetas](https://github.com/goetas)) - Add format output option [\#640](https://github.com/schmittjoh/serializer/pull/640) ([AyrtonRicardo](https://github.com/AyrtonRicardo)) - Remove deprecated FileCacheReader for doctrine annotations [\#634](https://github.com/schmittjoh/serializer/pull/634) ([goetas](https://github.com/goetas)) - Added tests to ensure SerializeNull policy [\#633](https://github.com/schmittjoh/serializer/pull/633) ([goetas](https://github.com/goetas)) - Revert "Default `$serializeNull` to false" [\#630](https://github.com/schmittjoh/serializer/pull/630) ([goetas](https://github.com/goetas)) - Introducing NormalizerInterface [\#592](https://github.com/schmittjoh/serializer/pull/592) ([alcalyn](https://github.com/alcalyn)) - Fix inheritance of discriminators on Doctrine entities [\#382](https://github.com/schmittjoh/serializer/pull/382) ([xoob](https://github.com/xoob)) - Allow Post Serialize Event to overwrite existing data [\#273](https://github.com/schmittjoh/serializer/pull/273) ([jockri](https://github.com/jockri)) ## [1.3.1](https://github.com/schmittjoh/serializer/tree/1.3.1) (2016-08-23) **Closed issues:** - \[Idea\] Inline name [\#629](https://github.com/schmittjoh/serializer/issues/629) - indexBy property doesn't work since 1.2.0 [\#618](https://github.com/schmittjoh/serializer/issues/618) - Composer deps issue [\#494](https://github.com/schmittjoh/serializer/issues/494) - PHP 7 compatability issue [\#478](https://github.com/schmittjoh/serializer/issues/478) - Add new tag \(upgrade packagist\) [\#461](https://github.com/schmittjoh/serializer/issues/461) - Custom Type Handler for String Values [\#384](https://github.com/schmittjoh/serializer/issues/384) - serializer ignores properties added by traits [\#313](https://github.com/schmittjoh/serializer/issues/313) - Skip an element during Xml deserialization process [\#229](https://github.com/schmittjoh/serializer/issues/229) - Using serializer for JSON serialising [\#223](https://github.com/schmittjoh/serializer/issues/223) - No way to serialize binary data with a custom type [\#202](https://github.com/schmittjoh/serializer/issues/202) - Automatic mapping of properties [\#200](https://github.com/schmittjoh/serializer/issues/200) - Maybe the serializer should also allow the legal literals {1, 0} for booleans [\#198](https://github.com/schmittjoh/serializer/issues/198) - Customize how Booleans are serialized [\#180](https://github.com/schmittjoh/serializer/issues/180) - Problem with deserialize related entity [\#123](https://github.com/schmittjoh/serializer/issues/123) - serialized\_name does not work in yaml [\#118](https://github.com/schmittjoh/serializer/issues/118) ## [1.3.0](https://github.com/schmittjoh/serializer/tree/1.3.0) (2016-08-17) **Fixed bugs:** - Fix warning array\_key\_exists in deserialization. [\#398](https://github.com/schmittjoh/serializer/pull/398) ([leonnleite](https://github.com/leonnleite)) **Closed issues:** - problems with xml namespaces after update [\#621](https://github.com/schmittjoh/serializer/issues/621) - Trying to decorate a member to ArrayCollection but gets an error when deserilizing because composer didn't download the class from doctrine. [\#596](https://github.com/schmittjoh/serializer/issues/596) - Missing doctrine/common requirement ? [\#517](https://github.com/schmittjoh/serializer/issues/517) - PHP Fatal error: Using $this when not in object context in JMS/Serializer/Serializer.php on line 99 [\#441](https://github.com/schmittjoh/serializer/issues/441) - custom collection handler [\#415](https://github.com/schmittjoh/serializer/issues/415) - Exclude annotation not preventing attempt to find public methods when using AccessType [\#367](https://github.com/schmittjoh/serializer/issues/367) - serializer.pre\_serialize event only thrown on objects/classes [\#337](https://github.com/schmittjoh/serializer/issues/337) - Installing through composer gets "Segmentation fault" [\#308](https://github.com/schmittjoh/serializer/issues/308) - Erroneous data format for unserializing... [\#283](https://github.com/schmittjoh/serializer/issues/283) - DoctrineObjectConstructor should skip empty identifier field [\#193](https://github.com/schmittjoh/serializer/issues/193) **Merged pull requests:** - Added public `hasData` function to check if a data key already have been added. [\#625](https://github.com/schmittjoh/serializer/pull/625) ([goetas](https://github.com/goetas)) - $context is not used [\#622](https://github.com/schmittjoh/serializer/pull/622) ([olvlvl](https://github.com/olvlvl)) - Fix Doctrine PHPCR ODM 2.0 compatibility [\#605](https://github.com/schmittjoh/serializer/pull/605) ([wouterj](https://github.com/wouterj)) - Fixed type-hinting [\#586](https://github.com/schmittjoh/serializer/pull/586) ([jgendera](https://github.com/jgendera)) - Fix multiple handler callbacks in YamlDriver [\#515](https://github.com/schmittjoh/serializer/pull/515) ([mpajunen](https://github.com/mpajunen)) - Fixed minor typos [\#364](https://github.com/schmittjoh/serializer/pull/364) ([sdaoudi](https://github.com/sdaoudi)) - Default `$serializeNull` to false [\#317](https://github.com/schmittjoh/serializer/pull/317) ([steveYeah](https://github.com/steveYeah)) - Missing attribute 'xml-value' in XML Reference [\#269](https://github.com/schmittjoh/serializer/pull/269) ([holtkamp](https://github.com/holtkamp)) - Removed unnecessary use statement [\#262](https://github.com/schmittjoh/serializer/pull/262) ([dunglas](https://github.com/dunglas)) ## [1.2.0](https://github.com/schmittjoh/serializer/tree/1.2.0) (2016-08-03) **Fixed bugs:** - Fix xml-attribute-map for the xml driver [\#595](https://github.com/schmittjoh/serializer/pull/595) ([romantomchak](https://github.com/romantomchak)) - \#367 Exclude annotation not preventing attempt to find public methods when using AccessType [\#397](https://github.com/schmittjoh/serializer/pull/397) ([Strate](https://github.com/Strate)) **Closed issues:** - XML serialisation performance vs. SimpleXML? [\#606](https://github.com/schmittjoh/serializer/issues/606) - Undefined Offset 21 - PropertyMetadata \(master\) [\#581](https://github.com/schmittjoh/serializer/issues/581) - Invalid null serialization in arrays [\#571](https://github.com/schmittjoh/serializer/issues/571) - List Polymorphic with XML Deserialization [\#568](https://github.com/schmittjoh/serializer/issues/568) - Serialize null values as empty string [\#566](https://github.com/schmittjoh/serializer/issues/566) - Type mismatch should throw an exception instead of coercing when deserializing JSON [\#561](https://github.com/schmittjoh/serializer/issues/561) - Serialize to array [\#518](https://github.com/schmittjoh/serializer/issues/518) - AnnotationDriver Exception on Missing Setter/Getter even on @Exclude'd Properties [\#516](https://github.com/schmittjoh/serializer/issues/516) - Arrays are serialized as objects like {"0":... } when data contains empty objects [\#488](https://github.com/schmittjoh/serializer/issues/488) - Tag new release [\#465](https://github.com/schmittjoh/serializer/issues/465) - Forcing no scientific notation for larg number, type double [\#405](https://github.com/schmittjoh/serializer/issues/405) - PHP \< 5.3.9 BC break [\#383](https://github.com/schmittjoh/serializer/issues/383) - Ignoring a tag when deserializing [\#352](https://github.com/schmittjoh/serializer/issues/352) **Merged pull requests:** - Allow to not skip empty not inline array root node [\#611](https://github.com/schmittjoh/serializer/pull/611) ([goetas](https://github.com/goetas)) - Allow to use custom serializer with primitive type [\#610](https://github.com/schmittjoh/serializer/pull/610) ([goetas](https://github.com/goetas)) - Composer is not able to resolve a dependency [\#608](https://github.com/schmittjoh/serializer/pull/608) ([goetas](https://github.com/goetas)) - Test on Travis always high and low deps [\#584](https://github.com/schmittjoh/serializer/pull/584) ([goetas](https://github.com/goetas)) - Update Symfony validator and allow PHPUnit 7 [\#583](https://github.com/schmittjoh/serializer/pull/583) ([goetas](https://github.com/goetas)) - Fix serialize bug [\#582](https://github.com/schmittjoh/serializer/pull/582) ([goetas](https://github.com/goetas)) - HHVM compatibility [\#580](https://github.com/schmittjoh/serializer/pull/580) ([goetas](https://github.com/goetas)) - Fixed test suite on master [\#578](https://github.com/schmittjoh/serializer/pull/578) ([goetas](https://github.com/goetas)) - Fix for a broken test: a missing \(incorrectly positioned\) argument [\#577](https://github.com/schmittjoh/serializer/pull/577) ([zerkms](https://github.com/zerkms)) - Fix bug \#343 return integer when the column is datetime [\#562](https://github.com/schmittjoh/serializer/pull/562) ([Bukashk0zzz](https://github.com/Bukashk0zzz)) - \[doc\] fix AccessorOrder documentation [\#553](https://github.com/schmittjoh/serializer/pull/553) ([aledeg](https://github.com/aledeg)) - Generic way to solve setValue on a property which respects its setter [\#550](https://github.com/schmittjoh/serializer/pull/550) ([maennchen](https://github.com/maennchen)) - Added travis-ci label [\#399](https://github.com/schmittjoh/serializer/pull/399) ([spolischook](https://github.com/spolischook)) - Generate namespaced element on XmlList entries [\#301](https://github.com/schmittjoh/serializer/pull/301) ([goetas](https://github.com/goetas)) ## [1.1.0](https://github.com/schmittjoh/serializer/tree/1.1.0) (2015-10-27) **Closed issues:** - Possible to set xsi:schemalocation? [\#505](https://github.com/schmittjoh/serializer/issues/505) - Travis needs a renewed token to be able to set the status [\#495](https://github.com/schmittjoh/serializer/issues/495) - Serialize a many-to-many relation [\#474](https://github.com/schmittjoh/serializer/issues/474) - The document type "..." is not allowed [\#427](https://github.com/schmittjoh/serializer/issues/427) - Yml serializer don't serialize empty arrays [\#183](https://github.com/schmittjoh/serializer/issues/183) **Merged pull requests:** - Manage empty array for serializer [\#510](https://github.com/schmittjoh/serializer/pull/510) ([Soullivaneuh](https://github.com/Soullivaneuh)) - Fix the method name for the serialization context factory [\#490](https://github.com/schmittjoh/serializer/pull/490) ([stof](https://github.com/stof)) - Switch the Twig integration to use non-deprecated APIs [\#482](https://github.com/schmittjoh/serializer/pull/482) ([stof](https://github.com/stof)) - Add PHP 7 on Travis [\#477](https://github.com/schmittjoh/serializer/pull/477) ([Soullivaneuh](https://github.com/Soullivaneuh)) - Change Proxy class used to Doctrine\Common\Persistence\Proxy [\#351](https://github.com/schmittjoh/serializer/pull/351) ([bburnichon](https://github.com/bburnichon)) - Added PHP 5.6 [\#297](https://github.com/schmittjoh/serializer/pull/297) ([Nyholm](https://github.com/Nyholm)) ## [1.0.0](https://github.com/schmittjoh/serializer/tree/1.0.0) (2015-06-16) **Closed issues:** - Unrecognized 4 parts namespace [\#449](https://github.com/schmittjoh/serializer/issues/449) - Groups is ignored [\#440](https://github.com/schmittjoh/serializer/issues/440) - Property FelDev\CoreBundle\Entity\Persona::$apellido does not exist [\#432](https://github.com/schmittjoh/serializer/issues/432) - Erroneous data format for unserializing [\#430](https://github.com/schmittjoh/serializer/issues/430) - Deserialize JSON into existing Doctrine entities and empty strings are ignored [\#417](https://github.com/schmittjoh/serializer/issues/417) - Failing to deserealize JSON string [\#402](https://github.com/schmittjoh/serializer/issues/402) - Empty results serializing virtual\_properties [\#400](https://github.com/schmittjoh/serializer/issues/400) - API stable 1.0.0 release in sight? [\#395](https://github.com/schmittjoh/serializer/issues/395) - Is this project maintained still? [\#361](https://github.com/schmittjoh/serializer/issues/361) - PreSerialize [\#339](https://github.com/schmittjoh/serializer/issues/339) - Change default `access\_type` globally [\#336](https://github.com/schmittjoh/serializer/issues/336) - Deserialization of XmlList does not support namespaces [\#332](https://github.com/schmittjoh/serializer/issues/332) - Recursion groups, serializing properties in entities [\#329](https://github.com/schmittjoh/serializer/issues/329) - The testsuite is broken [\#326](https://github.com/schmittjoh/serializer/issues/326) - Namespaces and serialize/deserialize process [\#303](https://github.com/schmittjoh/serializer/issues/303) - Exclusion of parent properties failing [\#282](https://github.com/schmittjoh/serializer/issues/282) - How to deserialize correctly an array of arbitrary values ? [\#280](https://github.com/schmittjoh/serializer/issues/280) - Try to identify getter/setter from an excluded property [\#278](https://github.com/schmittjoh/serializer/issues/278) - Bug Entity constructor not called [\#270](https://github.com/schmittjoh/serializer/issues/270) - Make it possible to escape special characters on serialization [\#265](https://github.com/schmittjoh/serializer/issues/265) - doctrine annotations without namespace [\#264](https://github.com/schmittjoh/serializer/issues/264) - php-collection constraint [\#257](https://github.com/schmittjoh/serializer/issues/257) - \[Metadata\] PHP warning only when unittesting [\#255](https://github.com/schmittjoh/serializer/issues/255) - Discriminator [\#220](https://github.com/schmittjoh/serializer/issues/220) **Merged pull requests:** - fix json output \(from \[\] to {} if empty\) of form error [\#462](https://github.com/schmittjoh/serializer/pull/462) ([jhkchan](https://github.com/jhkchan)) - Add toArray and fromArray methods to the serializer [\#435](https://github.com/schmittjoh/serializer/pull/435) ([tystr](https://github.com/tystr)) - Erroneous data format for unserializing \#430 [\#431](https://github.com/schmittjoh/serializer/pull/431) ([tmilos](https://github.com/tmilos)) - Scrutinizer Auto-Fixes [\#381](https://github.com/schmittjoh/serializer/pull/381) ([scrutinizer-auto-fixer](https://github.com/scrutinizer-auto-fixer)) - Fixing tests for bugfixed PHP versions [\#375](https://github.com/schmittjoh/serializer/pull/375) ([urakozz](https://github.com/urakozz)) - Making test running against phpunit 4.\* [\#369](https://github.com/schmittjoh/serializer/pull/369) ([joelwurtz](https://github.com/joelwurtz)) - Fixes a typo in the annotations.rst [\#363](https://github.com/schmittjoh/serializer/pull/363) ([Potherca](https://github.com/Potherca)) - \[doc\] Default group informations [\#345](https://github.com/schmittjoh/serializer/pull/345) ([emilien-puget](https://github.com/emilien-puget)) - bump branch alias to 0.17 as 0.16 is already released [\#305](https://github.com/schmittjoh/serializer/pull/305) ([lsmith77](https://github.com/lsmith77)) - Unserialization of XML booleans [\#302](https://github.com/schmittjoh/serializer/pull/302) ([goetas](https://github.com/goetas)) - Added xml\_root\_namespace on YAML reference [\#299](https://github.com/schmittjoh/serializer/pull/299) ([goetas](https://github.com/goetas)) - Fixed yml mapping file name [\#256](https://github.com/schmittjoh/serializer/pull/256) ([spolischook](https://github.com/spolischook)) - Serialization of nested polymorphic objects [\#238](https://github.com/schmittjoh/serializer/pull/238) ([DavidMikeSimon](https://github.com/DavidMikeSimon)) ## [0.16.0](https://github.com/schmittjoh/serializer/tree/0.16.0) (2014-03-18) **Closed issues:** - best way to add root to json? [\#250](https://github.com/schmittjoh/serializer/issues/250) - Use Doctrine metadata [\#247](https://github.com/schmittjoh/serializer/issues/247) - Integration Points - run-time exclusion checking [\#239](https://github.com/schmittjoh/serializer/issues/239) - Using DoctrineTypeDriver to use Doctrine Anotations [\#232](https://github.com/schmittjoh/serializer/issues/232) - Virtual property documentation xml & yaml [\#100](https://github.com/schmittjoh/serializer/issues/100) **Merged pull requests:** - Changed some constraint to allow latest versions [\#251](https://github.com/schmittjoh/serializer/pull/251) ([stof](https://github.com/stof)) - XML root element namespace support [\#246](https://github.com/schmittjoh/serializer/pull/246) ([andreasferber](https://github.com/andreasferber)) - Added test for leading backslash in front of class name to TypeParserTest [\#245](https://github.com/schmittjoh/serializer/pull/245) ([deralex](https://github.com/deralex)) - Allow to fetch data from has\*\(\) with public\_method [\#243](https://github.com/schmittjoh/serializer/pull/243) ([jaymecd](https://github.com/jaymecd)) - Improve yaml documentacion Fix \#100 [\#221](https://github.com/schmittjoh/serializer/pull/221) ([BraisGabin](https://github.com/BraisGabin)) ## [0.15.0](https://github.com/schmittjoh/serializer/tree/0.15.0) (2014-02-10) **Closed issues:** - Add trait support [\#228](https://github.com/schmittjoh/serializer/issues/228) - "array" type: Not working for arrays of DateTime objects [\#199](https://github.com/schmittjoh/serializer/issues/199) - Discriminator field filtered by exclusion strategy [\#189](https://github.com/schmittjoh/serializer/issues/189) - DateTime within an array \(format get ignored\) [\#140](https://github.com/schmittjoh/serializer/issues/140) - EntityNotFoundException using softDeletable [\#101](https://github.com/schmittjoh/serializer/issues/101) **Merged pull requests:** - Read only class [\#227](https://github.com/schmittjoh/serializer/pull/227) ([goetas](https://github.com/goetas)) - @Alex88's Serialize only form child of type Form \#117 [\#224](https://github.com/schmittjoh/serializer/pull/224) ([minayaserrano](https://github.com/minayaserrano)) - @XmlElement notation consistency [\#219](https://github.com/schmittjoh/serializer/pull/219) ([ajgarlag](https://github.com/ajgarlag)) - add $this-\>maxDepth to serialize / unserialize [\#218](https://github.com/schmittjoh/serializer/pull/218) ([rothfahl](https://github.com/rothfahl)) - xml reference updated with virtual-property example [\#215](https://github.com/schmittjoh/serializer/pull/215) ([ribeiropaulor](https://github.com/ribeiropaulor)) - Add XmlNamespace annotation documentation [\#213](https://github.com/schmittjoh/serializer/pull/213) ([jeserkin](https://github.com/jeserkin)) - Scrutinizer Auto-Fixes [\#210](https://github.com/schmittjoh/serializer/pull/210) ([scrutinizer-auto-fixer](https://github.com/scrutinizer-auto-fixer)) - Scrutinizer Auto-Fixes [\#206](https://github.com/schmittjoh/serializer/pull/206) ([scrutinizer-auto-fixer](https://github.com/scrutinizer-auto-fixer)) - Add xmlAttributeMap to serialized values [\#204](https://github.com/schmittjoh/serializer/pull/204) ([colinfrei](https://github.com/colinfrei)) - fix issue \#199: "array" type ignoring DateTime format [\#201](https://github.com/schmittjoh/serializer/pull/201) ([lukey78](https://github.com/lukey78)) - Potential fix for "recursion detected" issue [\#104](https://github.com/schmittjoh/serializer/pull/104) ([tyler-sommer](https://github.com/tyler-sommer)) - Adds XML namespaces support [\#58](https://github.com/schmittjoh/serializer/pull/58) ([ajgarlag](https://github.com/ajgarlag)) ## [0.14.0](https://github.com/schmittjoh/serializer/tree/0.14.0) (2013-12-04) **Closed issues:** - @HandlerCallback not inherited [\#181](https://github.com/schmittjoh/serializer/issues/181) - Conditional serialization [\#173](https://github.com/schmittjoh/serializer/issues/173) - Deserialize XML partially [\#167](https://github.com/schmittjoh/serializer/issues/167) - getter is not called when serializing Discriminator parent entity [\#156](https://github.com/schmittjoh/serializer/issues/156) - Deserialize DateTime from js Date.toJSON format fail [\#145](https://github.com/schmittjoh/serializer/issues/145) - Yaml driver for the parameter xml\_attribute\_map is broken [\#141](https://github.com/schmittjoh/serializer/issues/141) - XmlKeyValueStore annotation does not seem to deserialize properly [\#139](https://github.com/schmittjoh/serializer/issues/139) - Boolean conversion gone wrong [\#134](https://github.com/schmittjoh/serializer/issues/134) - Serialize to/from array? [\#133](https://github.com/schmittjoh/serializer/issues/133) - @XmlRoot annotation no longer working [\#131](https://github.com/schmittjoh/serializer/issues/131) - Skip an element based on a condition in a XmlList [\#121](https://github.com/schmittjoh/serializer/issues/121) **Merged pull requests:** - No CData [\#187](https://github.com/schmittjoh/serializer/pull/187) ([mvrhov](https://github.com/mvrhov)) - composer is preinstalled on travis [\#185](https://github.com/schmittjoh/serializer/pull/185) ([lsmith77](https://github.com/lsmith77)) - \[WIP\] added support for PHPCR [\#184](https://github.com/schmittjoh/serializer/pull/184) ([lsmith77](https://github.com/lsmith77)) - Metadata filename convention added to yml/xml references [\#172](https://github.com/schmittjoh/serializer/pull/172) ([rodrigodiez](https://github.com/rodrigodiez)) - Fix inline bug with empty child [\#165](https://github.com/schmittjoh/serializer/pull/165) ([adrienbrault](https://github.com/adrienbrault)) - Add virtual properties yaml example [\#163](https://github.com/schmittjoh/serializer/pull/163) ([adrienbrault](https://github.com/adrienbrault)) - Allow deserialization to constructed objects [\#160](https://github.com/schmittjoh/serializer/pull/160) ([eugene-dounar](https://github.com/eugene-dounar)) - Fix DoctrineDriverTest random failures [\#155](https://github.com/schmittjoh/serializer/pull/155) ([eugene-dounar](https://github.com/eugene-dounar)) - Fix XML null DateTime deserialization [\#154](https://github.com/schmittjoh/serializer/pull/154) ([eugene-dounar](https://github.com/eugene-dounar)) - Update doctrine/orm dev dependency [\#153](https://github.com/schmittjoh/serializer/pull/153) ([eugene-dounar](https://github.com/eugene-dounar)) - composer install --dev fails [\#152](https://github.com/schmittjoh/serializer/pull/152) ([eugene-dounar](https://github.com/eugene-dounar)) - Update annotations.rst [\#146](https://github.com/schmittjoh/serializer/pull/146) ([chrisjohnson00](https://github.com/chrisjohnson00)) - Add Doctrine\ODM\PHPCR\ChildrenCollection to ArrayCollectionHandler [\#143](https://github.com/schmittjoh/serializer/pull/143) ([hacfi](https://github.com/hacfi)) - xml\_attribute\_map fix for the yaml driver [\#142](https://github.com/schmittjoh/serializer/pull/142) ([mvanmeerbeck](https://github.com/mvanmeerbeck)) - fix wrong quote in used in docs [\#130](https://github.com/schmittjoh/serializer/pull/130) ([jaapio](https://github.com/jaapio)) - Support PropelCollection serialization [\#81](https://github.com/schmittjoh/serializer/pull/81) ([zebraf1](https://github.com/zebraf1)) ## [0.13.0](https://github.com/schmittjoh/serializer/tree/0.13.0) (2013-07-29) **Closed issues:** - Documentation on Exclusion Strategies has an error [\#122](https://github.com/schmittjoh/serializer/issues/122) - How access to the current serializing group in a subscriber ? [\#99](https://github.com/schmittjoh/serializer/issues/99) - DoctrineProxySubscriber not found [\#93](https://github.com/schmittjoh/serializer/issues/93) - Namespaces at root level [\#86](https://github.com/schmittjoh/serializer/issues/86) - Issues when requesting JSON or XML using Doctrine MongoDB ODM [\#85](https://github.com/schmittjoh/serializer/issues/85) - addGlobalIgnoredName not working [\#78](https://github.com/schmittjoh/serializer/issues/78) - serialize\_null configuration [\#77](https://github.com/schmittjoh/serializer/issues/77) - Add json prefix to prevent script tag csrf attack [\#76](https://github.com/schmittjoh/serializer/issues/76) - Add support for replacing serialization object inside events [\#74](https://github.com/schmittjoh/serializer/issues/74) - Next stable version? [\#64](https://github.com/schmittjoh/serializer/issues/64) - Deserialize with object refs [\#62](https://github.com/schmittjoh/serializer/issues/62) **Merged pull requests:** - Document the handler $context argument [\#116](https://github.com/schmittjoh/serializer/pull/116) ([adrienbrault](https://github.com/adrienbrault)) - Document the SubscribingHandlerInterface a bit [\#115](https://github.com/schmittjoh/serializer/pull/115) ([adrienbrault](https://github.com/adrienbrault)) - Add getter for the xml serialization visitor defaultRootName property [\#114](https://github.com/schmittjoh/serializer/pull/114) ([adrienbrault](https://github.com/adrienbrault)) - Add Serializer::getMetadataFactory [\#113](https://github.com/schmittjoh/serializer/pull/113) ([adrienbrault](https://github.com/adrienbrault)) - Accessor order [\#108](https://github.com/schmittjoh/serializer/pull/108) ([jaapio](https://github.com/jaapio)) - Added xmlns:xsi namespace and fixed tests [\#107](https://github.com/schmittjoh/serializer/pull/107) ([josser](https://github.com/josser)) - \[Doc\] Fixed typo in event\_system [\#106](https://github.com/schmittjoh/serializer/pull/106) ([lyrixx](https://github.com/lyrixx)) - Fix discriminator map search in ClassMetadata [\#97](https://github.com/schmittjoh/serializer/pull/97) ([xanido](https://github.com/xanido)) - Use the AnnotationReader interface in the SerializerBuilder, instead of the implemented AnnotationReader itself [\#82](https://github.com/schmittjoh/serializer/pull/82) ([HarmenM](https://github.com/HarmenM)) - Remove useless YamlSerializationVisitor::prepare method [\#75](https://github.com/schmittjoh/serializer/pull/75) ([adrienbrault](https://github.com/adrienbrault)) - Add the PRE\_DESERIALIZE event to the Events class [\#73](https://github.com/schmittjoh/serializer/pull/73) ([adrienbrault](https://github.com/adrienbrault)) - Improve serialization example [\#71](https://github.com/schmittjoh/serializer/pull/71) ([tvlooy](https://github.com/tvlooy)) - Max depth strategy [\#4](https://github.com/schmittjoh/serializer/pull/4) ([adrienbrault](https://github.com/adrienbrault)) ## [0.12.0](https://github.com/schmittjoh/serializer/tree/0.12.0) (2013-03-28) **Closed issues:** - Serialization profile/definition builder [\#68](https://github.com/schmittjoh/serializer/issues/68) - I want to configure the default exclution policy [\#65](https://github.com/schmittjoh/serializer/issues/65) - Mulit type property mapping [\#56](https://github.com/schmittjoh/serializer/issues/56) - AccessType\("public\_method"\): Setters ignored when deserializing to non-standard XML properties [\#53](https://github.com/schmittjoh/serializer/issues/53) - Adding @Accessor with custom getter causes LogicException if Doctrine ManyToOneEntity [\#52](https://github.com/schmittjoh/serializer/issues/52) - Handler callback's does not get passed context [\#49](https://github.com/schmittjoh/serializer/issues/49) - PostSerialize callback causes data loss [\#46](https://github.com/schmittjoh/serializer/issues/46) - Empty Objects get serialized as "array\(\)" [\#43](https://github.com/schmittjoh/serializer/issues/43) - Exclusion Policies aren't properly applied when "serializeNull" is "true" [\#42](https://github.com/schmittjoh/serializer/issues/42) - Accessor annotation ignored [\#40](https://github.com/schmittjoh/serializer/issues/40) - Support for multiple exclusion strategies [\#39](https://github.com/schmittjoh/serializer/issues/39) - srholt123@yahoo.com [\#35](https://github.com/schmittjoh/serializer/issues/35) - Could you tag a stable version? [\#34](https://github.com/schmittjoh/serializer/issues/34) - Default conversion of camelCase to underscores is counterintuitive [\#33](https://github.com/schmittjoh/serializer/issues/33) - Define the xml root when deserializing [\#18](https://github.com/schmittjoh/serializer/issues/18) **Merged pull requests:** - \[Annotation\] Added the ability to set the type when using @VirtualProperty [\#69](https://github.com/schmittjoh/serializer/pull/69) ([pylebecq](https://github.com/pylebecq)) - Added documentation for the @VirtualProperty annotation [\#67](https://github.com/schmittjoh/serializer/pull/67) ([pylebecq](https://github.com/pylebecq)) - Metadata stack tests [\#57](https://github.com/schmittjoh/serializer/pull/57) ([adrienbrault](https://github.com/adrienbrault)) - Adding context to twig extension [\#55](https://github.com/schmittjoh/serializer/pull/55) ([smurfy](https://github.com/smurfy)) - Allow deserialization of polymorphic classes by class without specifying the type [\#48](https://github.com/schmittjoh/serializer/pull/48) ([gordalina](https://github.com/gordalina)) - Moves all state to dedicated context class [\#47](https://github.com/schmittjoh/serializer/pull/47) ([schmittjoh](https://github.com/schmittjoh)) - Add PropertyNamingStrategy [\#37](https://github.com/schmittjoh/serializer/pull/37) ([passkey1510](https://github.com/passkey1510)) - The NavigatorContext now holds a metadata stack [\#28](https://github.com/schmittjoh/serializer/pull/28) ([adrienbrault](https://github.com/adrienbrault)) ## [0.11.0](https://github.com/schmittjoh/serializer/tree/0.11.0) (2013-01-29) **Closed issues:** - Hooking into metadata directly... [\#17](https://github.com/schmittjoh/serializer/issues/17) - Serializing null values [\#14](https://github.com/schmittjoh/serializer/issues/14) - Strange caching-error [\#13](https://github.com/schmittjoh/serializer/issues/13) - handling of plain array [\#10](https://github.com/schmittjoh/serializer/issues/10) - Unsupported format doesn't throw exception anymore [\#8](https://github.com/schmittjoh/serializer/issues/8) **Merged pull requests:** - Fix typo [\#32](https://github.com/schmittjoh/serializer/pull/32) ([inanimatt](https://github.com/inanimatt)) - Fixed the serialization of pluralized form errors [\#31](https://github.com/schmittjoh/serializer/pull/31) ([stof](https://github.com/stof)) - Extract json specific logic from GenericSerializationVisitor [\#29](https://github.com/schmittjoh/serializer/pull/29) ([adrienbrault](https://github.com/adrienbrault)) - \[Serializer\] Misc cleanup [\#27](https://github.com/schmittjoh/serializer/pull/27) ([vicb](https://github.com/vicb)) - \[Builder\] Add ability to include if metadata [\#25](https://github.com/schmittjoh/serializer/pull/25) ([vicb](https://github.com/vicb)) - Fix DateTimeZone issue when using the DateTime type [\#23](https://github.com/schmittjoh/serializer/pull/23) ([colinmorelli](https://github.com/colinmorelli)) - Wrong exception message for parsing datetime [\#21](https://github.com/schmittjoh/serializer/pull/21) ([nickelc](https://github.com/nickelc)) - Fixed typo in doc/reference/annotations.rst [\#16](https://github.com/schmittjoh/serializer/pull/16) ([iambrosi](https://github.com/iambrosi)) - Typecast when serializing primitive types [\#15](https://github.com/schmittjoh/serializer/pull/15) ([baldurrensch](https://github.com/baldurrensch)) - add check and helpful exception message on inconsistent type situation [\#12](https://github.com/schmittjoh/serializer/pull/12) ([dbu](https://github.com/dbu)) - Dispatch pre-serialization event before handling data to have ability change type in listener [\#7](https://github.com/schmittjoh/serializer/pull/7) ([megazoll](https://github.com/megazoll)) - Fix tests running in different environments [\#6](https://github.com/schmittjoh/serializer/pull/6) ([megazoll](https://github.com/megazoll)) - Add DateInterval serialization to DateHandler formerly DateTimeHandler [\#5](https://github.com/schmittjoh/serializer/pull/5) ([rpg600](https://github.com/rpg600)) - WIP Navigator context [\#3](https://github.com/schmittjoh/serializer/pull/3) ([adrienbrault](https://github.com/adrienbrault)) - Update src/JMS/Serializer/Construction/DoctrineObjectConstructor.php [\#2](https://github.com/schmittjoh/serializer/pull/2) ([robocoder](https://github.com/robocoder)) - Filter out non-identifiers from $data before calling find\(\) [\#1](https://github.com/schmittjoh/serializer/pull/1) ([robocoder](https://github.com/robocoder)) \* *This Change Log was automatically generated by [github_changelog_generator](https://github.com/skywinder/Github-Changelog-Generator)* serializer/LICENSE 0000644 00000002047 14736103242 0007727 0 ustar 00 Copyright (c) 2018 Johannes M. Schmitt Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. serializer/.github/CONTRIBUTING.md 0000644 00000004644 14736103242 0012520 0 ustar 00 # CONTRIBUTING First of all, **thank you** for contributing, **you are awesome**! Before we can merge your Pull-Request here are some guidelines that you need to follow. These guidelines exist not to annoy you, but to keep the code base clean, unified and future proof. Thank you for contributing! ## Pull Request Description While creating your Pull Request on GitHub, you must write a description which gives the context and/or explains why you are creating it. ## Dependencies We're using [`composer/composer`](https://github.com/composer/composer) to manage dependencies ## Coding Standard We are using the latest [PSR](http://www.php-fig.org/psr/) recommendations. ## Unit-Tests We're using [`phpunit/phpunit`](https://github.com/sebastianbergmann/phpunit) to run tests. You can run the unit-tests by calling `vendor/bin/phpunit` from the root of the project. If you are changing code, you must update or add tests for your changes. ## Travis We automatically run your pull request through [Travis CI](http://www.travis-ci.org). If you break the tests, we cannot merge your code, so please make sure that your code is working before opening up a Pull-Request. ## Documentation If you are adding a new feature, you must update the documentation. ## Issues and Bugs To create a new issue, you can use the GitHub issue tracking system. Please avoid creating issues for support requests, please read carefully the project documentation, try more appropriate channels as forums, questions and answers platforms... Issues considered as "support request" will be closed, the discussion can continue on a closed issue, maintainers will do their best to help. ## Getting merged Please allow us time to review your pull requests. We will give our best to review everything as fast as possible, but cannot always live up to our own expectations. Please, write [commit messages that make sense](http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html), and [rebase your branch](http://git-scm.com/book/en/Git-Branching-Rebasing) before submitting your Pull Request. One may ask you to [squash your commits](http://gitready.com/advanced/2009/02/10/squashing-commits-with-rebase.html) too. This is used to "clean" your Pull Request before merging it (we don't want commits such as "fix tests", "fix 2", "fix 3", etc.). Pull requests without tests most probably will not be merged. Documentation PRs obviously do not require tests. serializer/.github/PULL_REQUEST_TEMPLATE.md 0000644 00000000603 14736103242 0014057 0 ustar 00 | Q | A | ------------- | --- | Bug fix? | yes/no | New feature? | yes/no | Doc updated | yes/no | BC breaks? | yes/no <!-- don't forget updating UPGRADING.md file --> | Deprecations? | yes/no <!-- don't forget updating UPGRADING.md file --> | Tests pass? | yes/no | Fixed tickets | #... <!-- #-prefixed issue number(s), if any --> | License | Apache-2.0 serializer/.github/CONDUCT.md 0000644 00000003575 14736103242 0011712 0 ustar 00 # Contributor Code of Conduct As contributors and maintainers of this project, and in the interest of fostering an open and welcoming community, we pledge to respect all people who contribute through reporting issues, posting feature requests, updating documentation, submitting pull requests or patches, and other activities. We are committed to making participation in this project a harassment-free experience for everyone, regardless of level of experience, gender, gender identity and expression, sexual orientation, disability, personal appearance, body size, race, ethnicity, age, religion, or nationality. Examples of unacceptable behavior by participants include: * The use of sexualized language or imagery * Personal attacks * Trolling or insulting/derogatory comments * Public or private harassment * Publishing other's private information, such as physical or electronic addresses, without explicit permission * Other unethical or unprofessional conduct * Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct. By adopting this Code of Conduct, project maintainers commit themselves to fairly and consistently applying these principles to every aspect of managing this project. Project maintainers who do not follow or enforce the Code of Conduct may be permanently removed from the project team. This code of conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by opening an issue or contacting one or more of the project maintainers. This Code of Conduct is adapted from the Contributor Covenant, version 1.2.0, available from http://contributor-covenant.org/version/1/2/0/ serializer/.github/ISSUE_TEMPLATE.md 0000644 00000000732 14736103242 0012766 0 ustar 00 | Q | A | ---------------- | ----- | Bug report? | yes/no | Feature request? | yes/no | BC Break report? | yes/no | RFC? | yes/no <!-- - Please fill in this template according to your issue. - For support request or how-tos, please have a look to the documentation - Otherwise, replace this comment by the description of your issue. --> ## Steps required to reproduce the problem 1. 2. 3. ## Expected Result * ## Actual Result * serializer/META.md 0000644 00000000257 14736103242 0007773 0 ustar 00 # Generating changelog Use: https://github.com/skywinder/Github-Changelog-Generator ```bash github_changelog_generator --pull-requests --no-compare-link -t GITHUB-TOKEN ``` metadata/README.rst 0000644 00000002351 14736103242 0010016 0 ustar 00 Metadata is a library for class/method/property metadata management in PHP ========================================================================== Overview -------- This library provides some commonly needed base classes for managing metadata for classes, methods and properties. The metadata can come from many different sources (annotations, YAML/XML/PHP configuration files). The metadata classes are used to abstract away that source and provide a common interface for all of them. Usage ----- The library provides three classes that you can extend to add your application specific properties, and flags: ``ClassMetadata``, ``MethodMetadata``, and ``PropertyMetadata`` After you have added, your properties in sub-classes, you also need to add ``DriverInterface`` implementations which know how to populate these classes from the different metadata sources. Finally, you can use the ``MetadataFactory`` to retrieve the metadata:: <?php use Metadata\MetadataFactory; use Metadata\Driver\DriverChain; $driver = new DriverChain(array( /** Annotation, YAML, XML, PHP, ... drivers */ )); $factory = new MetadataFactory($driver); $metadata = $factory->getMetadataForClass('MyNamespace\MyObject'); metadata/src/Metadata/Driver/LazyLoadingDriver.php 0000644 00000001110 14736103242 0016163 0 ustar 00 <?php namespace Metadata\Driver; use Symfony\Component\DependencyInjection\ContainerInterface; class LazyLoadingDriver implements DriverInterface { private $container; private $realDriverId; public function __construct(ContainerInterface $container, $realDriverId) { $this->container = $container; $this->realDriverId = $realDriverId; } /** * {@inheritDoc} */ public function loadMetadataForClass(\ReflectionClass $class) { return $this->container->get($this->realDriverId)->loadMetadataForClass($class); } } metadata/src/Metadata/Driver/AbstractFileDriver.php 0000644 00000002706 14736103242 0016325 0 ustar 00 <?php namespace Metadata\Driver; /** * Base file driver implementation. * * @author Johannes M. Schmitt <schmittjoh@gmail.com> */ abstract class AbstractFileDriver implements AdvancedDriverInterface { /** * @var FileLocatorInterface|FileLocator */ private $locator; public function __construct(FileLocatorInterface $locator) { $this->locator = $locator; } public function loadMetadataForClass(\ReflectionClass $class) { if (null === $path = $this->locator->findFileForClass($class, $this->getExtension())) { return null; } return $this->loadMetadataFromFile($class, $path); } /** * {@inheritDoc} */ public function getAllClassNames() { if (!$this->locator instanceof AdvancedFileLocatorInterface) { throw new \RuntimeException('Locator "%s" must be an instance of "AdvancedFileLocatorInterface".'); } return $this->locator->findAllClasses($this->getExtension()); } /** * Parses the content of the file, and converts it to the desired metadata. * * @param \ReflectionClass $class * @param string $file * * @return \Metadata\ClassMetadata|null */ abstract protected function loadMetadataFromFile(\ReflectionClass $class, $file); /** * Returns the extension of the file. * * @return string */ abstract protected function getExtension(); } metadata/src/Metadata/Driver/DriverChain.php 0000644 00000002555 14736103242 0015006 0 ustar 00 <?php namespace Metadata\Driver; final class DriverChain implements AdvancedDriverInterface { private $drivers; public function __construct(array $drivers = array()) { $this->drivers = $drivers; } public function addDriver(DriverInterface $driver) { $this->drivers[] = $driver; } public function loadMetadataForClass(\ReflectionClass $class) { foreach ($this->drivers as $driver) { if (null !== $metadata = $driver->loadMetadataForClass($class)) { return $metadata; } } return null; } /** * {@inheritDoc} */ public function getAllClassNames() { $classes = array(); foreach ($this->drivers as $driver) { if (!$driver instanceof AdvancedDriverInterface) { throw new \RuntimeException( sprintf( 'Driver "%s" must be an instance of "AdvancedDriverInterface" to use '. '"DriverChain::getAllClassNames()".', get_class($driver) ) ); } $driverClasses = $driver->getAllClassNames(); if (!empty($driverClasses)) { $classes = array_merge($classes, $driverClasses); } } return $classes; } } metadata/src/Metadata/Driver/FileLocatorInterface.php 0000644 00000000423 14736103242 0016624 0 ustar 00 <?php namespace Metadata\Driver; interface FileLocatorInterface { /** * @param \ReflectionClass $class * @param string $extension * * @return string|null */ public function findFileForClass(\ReflectionClass $class, $extension); } metadata/src/Metadata/Driver/AdvancedDriverInterface.php 0000644 00000000511 14736103242 0017300 0 ustar 00 <?php namespace Metadata\Driver; /** * Forces advanced logic to drivers. * * @author Jordan Stout <j@jrdn.org> */ interface AdvancedDriverInterface extends DriverInterface { /** * Gets all the metadata class names known to this driver. * * @return array */ public function getAllClassNames(); } metadata/src/Metadata/Driver/FileLocator.php 0000644 00000003323 14736103242 0015005 0 ustar 00 <?php namespace Metadata\Driver; class FileLocator implements AdvancedFileLocatorInterface { private $dirs; public function __construct(array $dirs) { $this->dirs = $dirs; } public function getDirs() { return $this->dirs; } /** * @param \ReflectionClass $class * @param string $extension * * @return string|null */ public function findFileForClass(\ReflectionClass $class, $extension) { foreach ($this->dirs as $prefix => $dir) { if ('' !== $prefix && 0 !== strpos($class->getNamespaceName(), $prefix)) { continue; } $len = '' === $prefix ? 0 : strlen($prefix) + 1; $path = $dir.'/'.str_replace('\\', '.', substr($class->name, $len)).'.'.$extension; if (file_exists($path)) { return $path; } } return null; } /** * {@inheritDoc} */ public function findAllClasses($extension) { $classes = array(); foreach ($this->dirs as $prefix => $dir) { /** @var $iterator \RecursiveIteratorIterator|\SplFileInfo[] */ $iterator = new \RecursiveIteratorIterator( new \RecursiveDirectoryIterator($dir), \RecursiveIteratorIterator::LEAVES_ONLY ); $nsPrefix = $prefix !== '' ? $prefix.'\\' : ''; foreach ($iterator as $file) { if (($fileName = $file->getBasename('.'.$extension)) == $file->getBasename()) { continue; } $classes[] = $nsPrefix.str_replace('.', '\\', $fileName); } } return $classes; } } metadata/src/Metadata/Driver/DriverInterface.php 0000644 00000000350 14736103242 0015653 0 ustar 00 <?php namespace Metadata\Driver; interface DriverInterface { /** * @param \ReflectionClass $class * * @return \Metadata\ClassMetadata */ public function loadMetadataForClass(\ReflectionClass $class); } metadata/src/Metadata/Driver/AdvancedFileLocatorInterface.php 0000644 00000000564 14736103242 0020260 0 ustar 00 <?php namespace Metadata\Driver; /** * Forces advanced logic on a file locator. * * @author Jordan Stout <j@jrdn.org> */ interface AdvancedFileLocatorInterface extends FileLocatorInterface { /** * Finds all possible metadata files. * * @param string $extension * * @return array */ public function findAllClasses($extension); } metadata/src/Metadata/MetadataFactory.php 0000644 00000013332 14736103242 0014420 0 ustar 00 <?php namespace Metadata; use Metadata\Driver\AdvancedDriverInterface; use Metadata\Driver\DriverInterface; use Metadata\Cache\CacheInterface; class MetadataFactory implements AdvancedMetadataFactoryInterface { private $driver; private $cache; private $loadedMetadata = array(); private $loadedClassMetadata = array(); private $hierarchyMetadataClass; private $includeInterfaces = false; private $debug; /** * @param DriverInterface $driver * @param string $hierarchyMetadataClass * @param boolean $debug */ public function __construct(DriverInterface $driver, $hierarchyMetadataClass = 'Metadata\ClassHierarchyMetadata', $debug = false) { $this->driver = $driver; $this->hierarchyMetadataClass = $hierarchyMetadataClass; $this->debug = (Boolean) $debug; } /** * @param boolean $include */ public function setIncludeInterfaces($include) { $this->includeInterfaces = (Boolean) $include; } public function setCache(CacheInterface $cache) { $this->cache = $cache; } /** * @param string $className * * @return ClassHierarchyMetadata|MergeableClassMetadata|null */ public function getMetadataForClass($className) { if (isset($this->loadedMetadata[$className])) { return $this->filterNullMetadata($this->loadedMetadata[$className]); } $metadata = null; foreach ($this->getClassHierarchy($className) as $class) { if (isset($this->loadedClassMetadata[$name = $class->getName()])) { if (null !== $classMetadata = $this->filterNullMetadata($this->loadedClassMetadata[$name])) { $this->addClassMetadata($metadata, $classMetadata); } continue; } // check the cache if (null !== $this->cache) { if (($classMetadata = $this->cache->loadClassMetadataFromCache($class)) instanceof NullMetadata) { $this->loadedClassMetadata[$name] = $classMetadata; continue; } if (null !== $classMetadata) { if ( ! $classMetadata instanceof ClassMetadata) { throw new \LogicException(sprintf('The cache must return instances of ClassMetadata, but got %s.', var_export($classMetadata, true))); } if ($this->debug && !$classMetadata->isFresh()) { $this->cache->evictClassMetadataFromCache($classMetadata->reflection); } else { $this->loadedClassMetadata[$name] = $classMetadata; $this->addClassMetadata($metadata, $classMetadata); continue; } } } // load from source if (null !== $classMetadata = $this->driver->loadMetadataForClass($class)) { $this->loadedClassMetadata[$name] = $classMetadata; $this->addClassMetadata($metadata, $classMetadata); if (null !== $this->cache) { $this->cache->putClassMetadataInCache($classMetadata); } continue; } if (null !== $this->cache && !$this->debug) { $this->cache->putClassMetadataInCache(new NullMetadata($class->getName())); } } if (null === $metadata) { $metadata = new NullMetadata($className); } return $this->filterNullMetadata($this->loadedMetadata[$className] = $metadata); } /** * {@inheritDoc} */ public function getAllClassNames() { if (!$this->driver instanceof AdvancedDriverInterface) { throw new \RuntimeException( sprintf('Driver "%s" must be an instance of "AdvancedDriverInterface".', get_class($this->driver)) ); } return $this->driver->getAllClassNames(); } /** * @param ClassMetadata|null $metadata * @param ClassMetadata $toAdd */ private function addClassMetadata(&$metadata, $toAdd) { if ($toAdd instanceof MergeableInterface) { if (null === $metadata) { $metadata = clone $toAdd; } else { $metadata->merge($toAdd); } } else { if (null === $metadata) { $metadata = new $this->hierarchyMetadataClass; } $metadata->addClassMetadata($toAdd); } } /** * @param string $class */ private function getClassHierarchy($class) { $classes = array(); $refl = new \ReflectionClass($class); do { $classes[] = $refl; $refl = $refl->getParentClass(); } while (false !== $refl); $classes = array_reverse($classes, false); if (!$this->includeInterfaces) { return $classes; } $addedInterfaces = array(); $newHierarchy = array(); foreach ($classes as $class) { foreach ($class->getInterfaces() as $interface) { if (isset($addedInterfaces[$interface->getName()])) { continue; } $addedInterfaces[$interface->getName()] = true; $newHierarchy[] = $interface; } $newHierarchy[] = $class; } return $newHierarchy; } /** * @param NullMetadata|null $metadata * * @return ClassMetadata|null */ private function filterNullMetadata($metadata = null) { return !$metadata instanceof NullMetadata ? $metadata : null; } } metadata/src/Metadata/Version.php 0000644 00000000123 14736103242 0012767 0 ustar 00 <?php namespace Metadata; final class Version { const VERSION = '1.6-DEV'; } metadata/src/Metadata/AdvancedMetadataFactoryInterface.php 0000644 00000000720 14736103242 0017664 0 ustar 00 <?php namespace Metadata; /** * Interface for advanced Metadata Factory implementations. * * @author Johannes M. Schmitt <schmittjoh@gmail.com> * @author Jordan Stout <j@jrdn.org> */ interface AdvancedMetadataFactoryInterface extends MetadataFactoryInterface { /** * Gets all the possible classes. * * @throws \RuntimeException if driver does not an advanced driver. * @return array */ public function getAllClassNames(); } metadata/src/Metadata/MetadataFactoryInterface.php 0000644 00000001323 14736103242 0016236 0 ustar 00 <?php namespace Metadata; /** * Interface for Metadata Factory implementations. * * @author Johannes M. Schmitt <schmittjoh@gmail.com> */ interface MetadataFactoryInterface { /** * Returns the gathered metadata for the given class name. * * If the drivers return instances of MergeableClassMetadata, these will be * merged prior to returning. Otherwise, all metadata for the inheritance * hierarchy will be returned as ClassHierarchyMetadata unmerged. * * If no metadata is available, null is returned. * * @param string $className * * @return ClassHierarchyMetadata|MergeableClassMetadata|null */ public function getMetadataForClass($className); } metadata/src/Metadata/MethodMetadata.php 0000644 00000002172 14736103242 0014231 0 ustar 00 <?php namespace Metadata; /** * Base class for method metadata. * * This class is intended to be extended to add your application specific * properties, and flags. * * @author Johannes M. Schmitt <schmittjoh@gmail.com> */ class MethodMetadata implements \Serializable { public $class; public $name; public $reflection; public function __construct($class, $name) { $this->class = $class; $this->name = $name; $this->reflection = new \ReflectionMethod($class, $name); $this->reflection->setAccessible(true); } /** * @param object $obj * @param array $args * * @return mixed */ public function invoke($obj, array $args = array()) { return $this->reflection->invokeArgs($obj, $args); } public function serialize() { return serialize(array($this->class, $this->name)); } public function unserialize($str) { list($this->class, $this->name) = unserialize($str); $this->reflection = new \ReflectionMethod($this->class, $this->name); $this->reflection->setAccessible(true); } } metadata/src/Metadata/Cache/CacheInterface.php 0000644 00000001342 14736103242 0015175 0 ustar 00 <?php namespace Metadata\Cache; use Metadata\ClassMetadata; interface CacheInterface { /** * Loads a class metadata instance from the cache * * @param \ReflectionClass $class * * @return ClassMetadata */ function loadClassMetadataFromCache(\ReflectionClass $class); /** * Puts a class metadata instance into the cache * * @param ClassMetadata $metadata * * @return void */ function putClassMetadataInCache(ClassMetadata $metadata); /** * Evicts the class metadata for the given class from the cache. * * @param \ReflectionClass $class * * @return void */ function evictClassMetadataFromCache(\ReflectionClass $class); } metadata/src/Metadata/Cache/DoctrineCacheAdapter.php 0000644 00000002203 14736103242 0016342 0 ustar 00 <?php namespace Metadata\Cache; use Doctrine\Common\Cache\Cache; use Metadata\ClassMetadata; /** * @author Henrik Bjornskov <henrik@bjrnskov.dk> */ class DoctrineCacheAdapter implements CacheInterface { /** * @param string $prefix */ private $prefix; /** * @var Cache $cache */ private $cache; /** * @param string $prefix * @param Cache $cache */ public function __construct($prefix, Cache $cache) { $this->prefix = $prefix; $this->cache = $cache; } /** * {@inheritDoc} */ public function loadClassMetadataFromCache(\ReflectionClass $class) { $cache = $this->cache->fetch($this->prefix . $class->name); return false === $cache ? null : $cache; } /** * {@inheritDoc} */ public function putClassMetadataInCache(ClassMetadata $metadata) { $this->cache->save($this->prefix . $metadata->name, $metadata); } /** * {@inheritDoc} */ public function evictClassMetadataFromCache(\ReflectionClass $class) { $this->cache->delete($this->prefix . $class->name); } } metadata/src/Metadata/Cache/FileCache.php 0000644 00000004574 14736103242 0014166 0 ustar 00 <?php namespace Metadata\Cache; use Metadata\ClassMetadata; class FileCache implements CacheInterface { private $dir; public function __construct($dir) { if (!is_dir($dir)) { throw new \InvalidArgumentException(sprintf('The directory "%s" does not exist.', $dir)); } $this->dir = rtrim($dir, '\\/'); } /** * {@inheritDoc} */ public function loadClassMetadataFromCache(\ReflectionClass $class) { $path = $this->dir.'/'.strtr($class->name, '\\', '-').'.cache.php'; if (!file_exists($path)) { return null; } return include $path; } /** * {@inheritDoc} */ public function putClassMetadataInCache(ClassMetadata $metadata) { if (!is_writable($this->dir)) { throw new \InvalidArgumentException(sprintf('The directory "%s" is not writable.', $this->dir)); } $path = $this->dir.'/'.strtr($metadata->name, '\\', '-').'.cache.php'; $tmpFile = tempnam($this->dir, 'metadata-cache'); file_put_contents($tmpFile, '<?php return unserialize('.var_export(serialize($metadata), true).');'); // Let's not break filesystems which do not support chmod. @chmod($tmpFile, 0666 & ~umask()); $this->renameFile($tmpFile, $path); } /** * Renames a file with fallback for windows * * @param string $source * @param string $target */ private function renameFile($source, $target) { if (false === @rename($source, $target)) { if (defined('PHP_WINDOWS_VERSION_BUILD')) { if (false === copy($source, $target)) { throw new \RuntimeException(sprintf('(WIN) Could not write new cache file to %s.', $target)); } if (false === unlink($source)) { throw new \RuntimeException(sprintf('(WIN) Could not delete temp cache file to %s.', $source)); } } else { throw new \RuntimeException(sprintf('Could not write new cache file to %s.', $target)); } } } /** * {@inheritDoc} */ public function evictClassMetadataFromCache(\ReflectionClass $class) { $path = $this->dir.'/'.strtr($class->name, '\\', '-').'.cache.php'; if (file_exists($path)) { unlink($path); } } } metadata/src/Metadata/Cache/PsrCacheAdapter.php 0000644 00000002301 14736103242 0015336 0 ustar 00 <?php namespace Metadata\Cache; use Metadata\ClassMetadata; use Psr\Cache\CacheItemPoolInterface; class PsrCacheAdapter implements CacheInterface { private $prefix; private $pool; private $lastItem; public function __construct($prefix, CacheItemPoolInterface $pool) { $this->prefix = $prefix; $this->pool = $pool; } /** * {@inheritDoc} */ public function loadClassMetadataFromCache(\ReflectionClass $class) { $this->lastItem = $this->pool->getItem(strtr($this->prefix . $class->name, '\\', '.')); return $this->lastItem->get(); } /** * {@inheritDoc} */ public function putClassMetadataInCache(ClassMetadata $metadata) { $key = strtr($this->prefix . $metadata->name, '\\', '.'); if (null === $this->lastItem || $this->lastItem->getKey() !== $key) { $this->lastItem = $this->pool->getItem($key); } $this->pool->save($this->lastItem->set($metadata)); } /** * {@inheritDoc} */ public function evictClassMetadataFromCache(\ReflectionClass $class) { $this->pool->deleteItem(strtr($this->prefix . $class->name, '\\', '.')); } } metadata/src/Metadata/PropertyMetadata.php 0000644 00000002435 14736103242 0014637 0 ustar 00 <?php namespace Metadata; /** * Base class for property metadata. * * This class is intended to be extended to add your application specific * properties, and flags. * * @author Johannes M. Schmitt <schmittjoh@gmail.com> */ class PropertyMetadata implements \Serializable { public $class; public $name; public $reflection; public function __construct($class, $name) { $this->class = $class; $this->name = $name; $this->reflection = new \ReflectionProperty($class, $name); $this->reflection->setAccessible(true); } /** * @param object $obj * * @return mixed */ public function getValue($obj) { return $this->reflection->getValue($obj); } /** * @param object $obj * @param string $value */ public function setValue($obj, $value) { $this->reflection->setValue($obj, $value); } public function serialize() { return serialize(array( $this->class, $this->name, )); } public function unserialize($str) { list($this->class, $this->name) = unserialize($str); $this->reflection = new \ReflectionProperty($this->class, $this->name); $this->reflection->setAccessible(true); } } metadata/src/Metadata/NullMetadata.php 0000644 00000000306 14736103242 0013720 0 ustar 00 <?php namespace Metadata; /** * Represents the metadata for a class that has not metadata. * * @author Adrien Brault <adrien.brault@gmail.com> */ class NullMetadata extends ClassMetadata { } metadata/src/Metadata/MergeableInterface.php 0000644 00000000310 14736103242 0015044 0 ustar 00 <?php namespace Metadata; interface MergeableInterface { /** * @param MergeableInterface $object * * @return void */ public function merge(MergeableInterface $object); } metadata/src/Metadata/ClassHierarchyMetadata.php 0000644 00000001427 14736103242 0015717 0 ustar 00 <?php namespace Metadata; /** * Represents the metadata for the entire class hierarchy. * * @author Johannes M. Schmitt <schmittjoh@gmail.com> */ class ClassHierarchyMetadata { public $classMetadata = array(); public function addClassMetadata(ClassMetadata $metadata) { $this->classMetadata[$metadata->name] = $metadata; } public function getRootClassMetadata() { return reset($this->classMetadata); } public function getOutsideClassMetadata() { return end($this->classMetadata); } public function isFresh($timestamp) { foreach ($this->classMetadata as $metadata) { if (!$metadata->isFresh($timestamp)) { return false; } } return true; } } metadata/src/Metadata/ClassMetadata.php 0000644 00000003563 14736103242 0014063 0 ustar 00 <?php namespace Metadata; /** * Base class for class metadata. * * This class is intended to be extended to add your own application specific * properties, and flags. * * @author Johannes M. Schmitt <schmittjoh@gmail.com> */ class ClassMetadata implements \Serializable { public $name; public $reflection; public $methodMetadata = array(); public $propertyMetadata = array(); public $fileResources = array(); public $createdAt; public function __construct($name) { $this->name = $name; $this->reflection = new \ReflectionClass($name); $this->createdAt = time(); } public function addMethodMetadata(MethodMetadata $metadata) { $this->methodMetadata[$metadata->name] = $metadata; } public function addPropertyMetadata(PropertyMetadata $metadata) { $this->propertyMetadata[$metadata->name] = $metadata; } public function isFresh($timestamp = null) { if (null === $timestamp) { $timestamp = $this->createdAt; } foreach ($this->fileResources as $filepath) { if (!file_exists($filepath)) { return false; } if ($timestamp < filemtime($filepath)) { return false; } } return true; } public function serialize() { return serialize(array( $this->name, $this->methodMetadata, $this->propertyMetadata, $this->fileResources, $this->createdAt, )); } public function unserialize($str) { list( $this->name, $this->methodMetadata, $this->propertyMetadata, $this->fileResources, $this->createdAt ) = unserialize($str); $this->reflection = new \ReflectionClass($this->name); } } metadata/src/Metadata/MergeableClassMetadata.php 0000644 00000001505 14736103242 0015661 0 ustar 00 <?php namespace Metadata; class MergeableClassMetadata extends ClassMetadata implements MergeableInterface { public function merge(MergeableInterface $object) { if (!$object instanceof MergeableClassMetadata) { throw new \InvalidArgumentException('$object must be an instance of MergeableClassMetadata.'); } $this->name = $object->name; $this->reflection = $object->reflection; $this->methodMetadata = array_merge($this->methodMetadata, $object->methodMetadata); $this->propertyMetadata = array_merge($this->propertyMetadata, $object->propertyMetadata); $this->fileResources = array_merge($this->fileResources, $object->fileResources); if ($object->createdAt < $this->createdAt) { $this->createdAt = $object->createdAt; } } } metadata/CHANGELOG.md 0000644 00000002211 14736103242 0010133 0 ustar 00 CHANGELOG ========= This changelog references all relevant changes: * 1.7.0 (2018-10-26) * allow to run the metadata on read-only file systems * Change license to MIT * Composer improvements * 1.6.0 (2016-12-05) * PRS cache adapter * other fixes * 1.5.0 (2013-11-06) * adds ability to inject new drivers into the DriverChain after it has been constructed * improves performance by removing some superfluous filesystem calls * made MetadataFactory implementation non-final * 1.4.1 (2013-08-26) * fixes a possible permission issue when using filesystem ACLs * 1.4.0 (2013-08-25) * fixes a race condition when writing cache files * 1.3.0 (2013-01-22) * added ability to retrieve all managed classes from the metadata factory * 1.2.0 (2012-08-21) * added a Doctrine Cache Adapter * better support for traits, and classes in the global namespace * 1.1.0 (2011-10-04) * added support for metadata on interfaces * added support for non annotation-based drivers * added support for merging metadata This release is fully backwards compatible with the 1.0.0 release. Therefore, the 1.0.x branch has been discontinued. * 1.0.0 (2011-07-09) metadata/LICENSE 0000644 00000002047 14736103242 0007336 0 ustar 00 Copyright (c) 2018 Johannes M. Schmitt Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. parser-lib/.jms.yml 0000644 00000000637 14736103242 0010206 0 ustar 00 filter: paths: [src/*, tests/*] excluded_paths: ["tests/*/Fixture/*"] default_config: psr0_compliance: true checkstyle: true composer_config_check: publish_checks: true level: warning reflection_fixes: true use_statement_fixes: true path_configs: tests: paths: [tests/*] psr0_compliance: false checkstyle: false phpunit_checks: true parser-lib/src/JMS/Parser/AbstractParser.php 0000644 00000007112 14736103242 0014714 0 ustar 00 <?php /* * Copyright 2012 Johannes M. Schmitt <schmittjoh@gmail.com> * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ namespace JMS\Parser; /** * Base Parser which provides some useful parsing methods intended for sub-classing. * * @author Johannes M. Schmitt <schmittjoh@gmail.com> */ abstract class AbstractParser { protected $lexer; protected $context; public function __construct(AbstractLexer $lexer) { $this->lexer = $lexer; } /** * Parses the given input. * * @param string $str * @param string $context parsing context (allows to produce better error messages) * * @return mixed */ public function parse($str, $context = null) { $this->lexer->setInput($str); $this->context = $context; $rs = $this->parseInternal(); if (null !== $this->lexer->next) { $this->syntaxError('end of input'); } return $rs; } /** * @return mixed */ abstract protected function parseInternal(); /** * Matches a token, and returns its value. * * @param integer $type * * @return mixed the value of the matched token */ protected function match($type) { if ( ! $this->lexer->isNext($type)) { $this->syntaxError($this->lexer->getName($type)); } $this->lexer->moveNext(); return $this->lexer->token[0]; } /** * Matches any of the passed tokens, and returns the matched token's value. * * @param array<integer> $types * * @return mixed */ protected function matchAny(array $types) { if ( ! $this->lexer->isNextAny($types)) { $this->syntaxError('any of '.implode(' or ', array_map(array($this->lexer, 'getName'), $types))); } $this->lexer->moveNext(); return $this->lexer->token[0]; } /** * Raises a syntax error exception. * * @param string $expectedDesc A human understandable explanation what was expected * @param array $actualToken The token that was found. If not given, next token will be assumed. */ protected function syntaxError($expectedDesc, $actualToken = null) { if (null === $actualToken) { $actualToken = $this->lexer->next; } if (null === $actualToken) { $actualDesc = 'end of input'; } else if ($actualToken[1] === 0) { $actualDesc = sprintf('"%s" of type %s at beginning of input', $actualToken[0], $this->lexer->getName($actualToken[2])); } else { $actualDesc = sprintf('"%s" of type %s at position %d (0-based)', $actualToken[0], $this->lexer->getName($actualToken[2]), $actualToken[1]); } $ex = new SyntaxErrorException(sprintf('Expected %s, but got %s%s.', $expectedDesc, $actualDesc, $this->context ? ' '.$this->context : '')); if (null !== $actualToken) { $ex->setActualToken($actualToken); } if (null !== $this->context) { $ex->setContext($this->context); } throw $ex; } } parser-lib/src/JMS/Parser/SyntaxErrorException.php 0000644 00000002144 14736103242 0016153 0 ustar 00 <?php /* * Copyright 2012 Johannes M. Schmitt <schmittjoh@gmail.com> * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ namespace JMS\Parser; class SyntaxErrorException extends \RuntimeException { private $actualToken; private $context; public function setActualToken(array $actualToken) { $this->actualToken = $actualToken; } public function setContext($context) { $this->context = $context; } public function getActualToken() { return $this->actualToken; } public function getContext() { return $this->context; } } parser-lib/src/JMS/Parser/AbstractLexer.php 0000644 00000007746 14736103242 0014554 0 ustar 00 <?php /* * Copyright 2012 Johannes M. Schmitt <schmittjoh@gmail.com> * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ namespace JMS\Parser; /** * Abstract Lexer. * * @author Johannes M. Schmitt <schmittjoh@gmail.com> */ abstract class AbstractLexer { public $token; public $next; private $i; private $peek; private $tokens; /** * Returns the name of the given token. * * @param integer $type * * @return string */ public function getName($type) { $ref = new \ReflectionClass($this); foreach ($ref->getConstants() as $name => $value) { if ($value === $type) { return $name; } } throw new \InvalidArgumentException(sprintf('There is no token with value %s.', json_encode($type))); } public function setInput($str) { $tokens = preg_split($this->getRegex(), $str, null, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY | PREG_SPLIT_OFFSET_CAPTURE); $this->tokens = array(); foreach ($tokens as $token) { list($token[2], $token[0]) = $this->determineTypeAndValue($token[0]); $this->tokens[] = $token; } $this->reset(); } public function reset() { $this->i = -1; $this->peek = 0; $this->token = $this->next = null; $this->moveNext(); } /** * Moves the pointer one token forward. * * @return boolean if we have not yet reached the end of the input */ public function moveNext() { $this->peek = 0; $this->token = $this->next; $this->next = isset($this->tokens[++$this->i]) ? $this->tokens[$this->i] : null; return null !== $this->next; } /** * Skips the token stream until a token of the given type. * * @param integer $type * * @return boolean true if a token of the passed type was found, false otherwise. */ public function skipUntil($type) { while ( ! $this->isNext($type) && $this->moveNext()); if ( ! $this->isNext($type)) { throw new \RuntimeException(sprintf('Could not find the token %s.', $this->getName($type))); } } /** * @param integer $type * * @return boolean */ public function isNext($type) { return null !== $this->next && $type === $this->next[2]; } /** * @param array<integer> $types * * @return boolean */ public function isNextAny(array $types) { if (null === $this->next) { return false; } foreach ($types as $type) { if ($type === $this->next[2]) { return true; } } return false; } /** * @return \PhpOption\Option<[string,integer,integer]> */ public function peek() { if ( ! isset($this->tokens[$this->i + (++$this->peek)])) { return \PhpOption\None::create(); } return new \PhpOption\Some($this->tokens[$this->i + $this->peek]); } /** * @return string */ abstract protected function getRegex(); /** * Determines the type of the given value. * * This method may also modify the passed value for example to cast them to * a different PHP type where necessary. * * @param string $value * * @return array a tupel of type and normalized value */ abstract protected function determineTypeAndValue($value); } parser-lib/src/JMS/Parser/SimpleLexer.php 0000644 00000003046 14736103242 0014227 0 ustar 00 <?php /* * Copyright 2012 Johannes M. Schmitt <schmittjoh@gmail.com> * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ namespace JMS\Parser; /** * The simple lexer is a fully usable lexer that does not require sub-classing. * * @author Johannes M. Schmitt <schmittjoh@gmail.com> */ class SimpleLexer extends AbstractLexer { private $regex; private $callable; private $tokenNames; public function __construct($regex, array $tokenNames, $typeCallable) { $this->regex = $regex; $this->callable = $typeCallable; $this->tokenNames = $tokenNames; } public function getName($type) { if ( ! isset($this->tokenNames[$type])) { throw new \InvalidArgumentException(sprintf('There is no token with type %s.', json_encode($type))); } return $this->tokenNames[$type]; } protected function getRegex() { return $this->regex; } protected function determineTypeAndValue($value) { return call_user_func($this->callable, $value); } } parser-lib/README.md 0000644 00000000156 14736103242 0010067 0 ustar 00 Parser Library ============== Learn more about it in its [documentation](http://jmsyst.com/libs/parser-lib). parser-lib/LICENSE 0000644 00000026134 14736103242 0007621 0 ustar 00 Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright [yyyy] [name of copyright owner] Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.