protected function setUp() { $this->propertyMetadata = new PropertyMetadata('test'); $this->propertyMetadata->setSinceVersion('5.0'); $this->propertyMetadata->setUntilVersion('5.4'); $this->propertyMetadata->setGroups(array('test', 'foo', 'bar')); $this->propertySkipper = new PropertySkipper(); }
/** * @param PropertyMetadata $property * @return PropertyMetadata */ private function makeItemProperty(PropertyMetadata $property) { $itemProperty = new PropertyMetadata($property->getName()); $itemProperty->setExpose(true)->setSerializedName($property->getSerializedName()); if (preg_match('/array<(?<type>[a-zA-Z\\\\]+)>/', $property->getType(), $matches)) { $itemProperty->setType($matches['type']); } return $itemProperty; }
/** * {@inheritDoc} * * @param PropertyMetadata $property * @return bool */ public function shouldSkipProperty(PropertyMetadata $property) { if (null !== ($version = $property->getSinceVersion()) && version_compare($this->version, $version, '<')) { return true; } if (null !== ($version = $property->getUntilVersion()) && version_compare($this->version, $version, '>')) { return true; } return false; }
/** * @param PropertyMetadata $property * @return bool */ public function shouldSkip(PropertyMetadata $property) { if (!$property->isExpose()) { return true; } foreach ($this->specifications as $specification) { if ($specification->isSatisfiedBy($property)) { return true; } } return false; }
/** * {@inheritDoc} * * @param PropertyMetadata $property * @return bool */ public function isSatisfiedBy(PropertyMetadata $property) { if (!$property->getGroups()) { return true; } foreach ($property->getGroups() as $group) { if (isset($this->groups[$group])) { return false; } } return true; }
/** * @param mixed $value * @param PropertyMetadata $property * @param object $object * @return object */ public function denormalize($value, $property, $object) { $type = $property->getType(); if (!is_object($object) || !$object instanceof $type) { if (PHP_VERSION_ID >= 50400) { $rc = new \ReflectionClass($type); $object = $rc->newInstanceWithoutConstructor(); } else { $object = unserialize(sprintf('O:%d:"%s":0:{}', strlen($type), $type)); } } return $this->normalizer->denormalize($value, $object); }
public function loadMetadataForClass($className) { $metadata = new ClassMetadata($className); $reflectionClass = new \ReflectionClass($className); $reflectionProperties = $reflectionClass->getProperties(); foreach ($reflectionProperties as $reflectionProperty) { $name = $reflectionProperty->getName(); $pMetadata = new PropertyMetadata($name); $annotations = $this->reader->getPropertyAnnotations($reflectionProperty); foreach ($annotations as $annotation) { if ($annotation instanceof Annotations\Expose) { $pMetadata->setExpose((bool) $annotation->value); } elseif ($annotation instanceof Annotations\Type) { $pMetadata->setType((string) $annotation->value); } elseif ($annotation instanceof Annotations\Groups) { $pMetadata->setGroups($annotation->value); } elseif ($annotation instanceof Annotations\SerializedName) { $pMetadata->setSerializedName((string) $annotation->value); } elseif ($annotation instanceof Annotations\SinceVersion) { $pMetadata->setSinceVersion((string) $annotation->value); } elseif ($annotation instanceof Annotations\UntilVersion) { $pMetadata->setUntilVersion((string) $annotation->value); } } $metadata->addPropertyMetadata($pMetadata); } return $metadata; }
/** * {@inheritDoc} * * @param string $className * @param string $file * @return null|ClassMetadata * @throws RuntimeException */ protected function loadMetadataFromFile($className, $file) { $config = Yaml::parse(file_get_contents($file)); if (!isset($config[$name = $className])) { throw new RuntimeException(sprintf('Expected metadata for class %s to be defined in %s.', $className, $file)); } $config = $config[$name]; $metadata = new ClassMetadata($name); $metadata->addFileResource($file); foreach ($config['properties'] as $propertyName => $propertyOptions) { $pMetadata = new PropertyMetadata($propertyName); if (isset($propertyOptions['expose'])) { $pMetadata->setExpose((bool) $propertyOptions['expose']); } if (isset($propertyOptions['serialized_name'])) { $pMetadata->setSerializedName((string) $propertyOptions['serialized_name']); } if (isset($propertyOptions['since_version'])) { $pMetadata->setSinceVersion((string) $propertyOptions['since_version']); } if (isset($propertyOptions['until_version'])) { $pMetadata->setUntilVersion((string) $propertyOptions['until_version']); } if (isset($propertyOptions['type'])) { $pMetadata->setType((string) $propertyOptions['type']); } if (isset($propertyOptions['groups'])) { $pMetadata->setGroups($propertyOptions['groups']); } $metadata->addPropertyMetadata($pMetadata); } return $metadata; }
/** * @depends testConstructor * @depends testSettersGetters */ public function testSerializeUnserialize() { $unitUnderTest = new PropertyMetadata('test'); $unitUnderTest->setExpose(true)->setSerializedName('serialize')->setType('string')->setGroups(array('test'))->setSinceVersion('1.0')->setUntilVersion('2.0'); $serializedString = serialize($unitUnderTest); $unserializedObject = unserialize($serializedString); $this->assertInstanceOf('Opensoft\\SimpleSerializer\\Metadata\\PropertyMetadata', $unserializedObject); $this->assertEquals('test', $unserializedObject->getName()); $this->assertTrue($unserializedObject->isExpose()); $this->assertEquals('string', $unserializedObject->getType()); $this->assertEquals('serialize', $unserializedObject->getSerializedName()); $this->assertEquals(array('test'), $unserializedObject->getGroups()); $this->assertEquals('1.0', $unserializedObject->getSinceVersion()); $this->assertEquals('2.0', $unserializedObject->getUntilVersion()); }
public function testAddClassMetadata() { $metadata = new ClassMetadata('testClass'); sleep(2); $unitUnderTest = new ClassHierarchyMetadata(); $property = new PropertyMetadata('property'); $property->setType('string'); $metadata->addFileResource('/tmp/fileNotExists')->addPropertyMetadata($property); $unitUnderTest->addFileResource('/tmp/fileNotExists2'); $property = new PropertyMetadata('property2'); $property->setType('integer'); $unitUnderTest->addPropertyMetadata($property); $unitUnderTest->addClassMetadata($metadata); $this->assertEquals($metadata->getName(), $unitUnderTest->getName()); $this->assertEquals($metadata->getCreatedAt(), $unitUnderTest->getCreatedAt()); $this->assertCount(2, $unitUnderTest->getFileResources()); $this->assertCount(2, $unitUnderTest->getProperties()); $this->assertEquals(array('/tmp/fileNotExists2', '/tmp/fileNotExists'), $unitUnderTest->getFileResources()); $this->assertArrayHasKey('property', $unitUnderTest->getProperties()); $this->assertArrayHasKey('property2', $unitUnderTest->getProperties()); }
/** * @depends testConstructor * @depends testSettersGetters */ public function testSerializeUnserialize() { $unitUnderTest = new ClassMetadata('testClass'); $property = new PropertyMetadata('property'); $property->setType('string'); $unitUnderTest->addFileResource('/tmp/fileNotExists')->addPropertyMetadata($property); $serializedString = serialize($unitUnderTest); $unserializedObject = unserialize($serializedString); $this->assertInstanceOf('Opensoft\\SimpleSerializer\\Metadata\\ClassMetadata', $unserializedObject); $this->assertEquals('testClass', $unserializedObject->getName()); $this->assertNotNull($unserializedObject->getCreatedAt()); $fileResources = $unserializedObject->getFileResources(); $this->assertCount(1, $fileResources); $this->assertEquals('/tmp/fileNotExists', $fileResources[0]); $properties = $unserializedObject->getProperties(); $this->assertCount(1, $properties); $this->assertArrayHasKey('property', $properties); $this->assertInstanceOf('Opensoft\\SimpleSerializer\\Metadata\\PropertyMetadata', $properties['property']); $this->assertEquals('property', $properties['property']->getName()); $this->assertEquals('string', $properties['property']->getType()); }
/** * Convert serialized value to DateTime object * @param string $value * @param PropertyMetadata $property * @param mixed $object * @return DateTime * @throws InvalidArgumentException */ public function denormalize($value, $property, $object) { // we should not allow empty string as date time argument. //It can lead us to unexpected results //Only 'null' is possible empty value $originalValue = trim($value); if (!$originalValue) { throw new InvalidArgumentException('DateTime argument should be well formed string'); } $dateTimeFormat = $this->extractDateTimeFormat($property->getType()); try { $value = new DateTime($value); } catch (\Exception $e) { throw new InvalidArgumentException(sprintf('Invalid DateTime argument "%s"', $value), $e->getCode(), $e); } // if format was specified in metadata - format and compare parsed DateTime object with original string if (isset($dateTimeFormat) && $value->format($dateTimeFormat) !== $originalValue) { throw new InvalidArgumentException(sprintf('Invalid DateTime argument "%s"', $originalValue)); } return $value; }
/** * @param ArrayNormalizer $normalizer * @param mixed $value * @param PropertyMetadata $property * @param mixed $object * @param bool $inner * @return array|bool|DateTime|float|int|null|string * @throws InvalidArgumentException */ public function denormalizeProcess(ArrayNormalizer $normalizer, $value, $property, $object, $inner = false) { if ($value === null) { return null; } $transformerAliases = array(TransformerFactory::TYPE_SIMPLE_TRANSFORMER, TransformerFactory::TYPE_DATETIME_TRANSFORMER, TransformerFactory::TYPE_ARRAY_TRANSFORMER, TransformerFactory::TYPE_OBJECT_TRANSFORMER); $supports = false; foreach ($transformerAliases as $transformerAlias) { $transformer = $this->transformerFactory->getTransformer($transformerAlias, $normalizer, $this); if ($transformer->supportType($property->getType()) && $transformer->supportValueForDenormalization($value)) { if ($transformerAlias === TransformerFactory::TYPE_OBJECT_TRANSFORMER && !$inner) { $object = ObjectHelper::expose($object, $property); } $value = $transformer->denormalize($value, $property, $object); $supports = true; break; } } if (!$supports && $property->getType() !== null) { throw new InvalidArgumentException(sprintf('Unsupported type: %s', $property->getType())); } return $value; }
/** * @param $value * @param PropertyMetadata $property * @param $direct * @param null|mixed $object * @param bool $inner * @throws \Opensoft\SimpleSerializer\Exception\InvalidArgumentException * @return array|bool|float|int|string|null */ private function handleValue($value, $property, $direct, $object = null, $inner = false) { $type = $property->getType(); if ($value !== null) { if ($type === 'string') { $value = (string) $value; } elseif ($type === 'boolean') { $value = (bool) $value; } elseif ($type === 'integer') { $value = (int) $value; } elseif ($type === 'double') { $value = (double) $value; } elseif ($type === 'DateTime' || $type[0] === 'D' && strpos($type, 'DateTime<') === 0) { if ($direct == self::DIRECTION_SERIALIZE) { $dateTimeFormat = $this->extractDateTimeFormat($type, DateTime::ISO8601); $value = $value->format($dateTimeFormat); } elseif ($direct == self::DIRECTION_UNSERIALIZE) { $originalValue = trim($value); $dateTimeFormat = $this->extractDateTimeFormat($type); // we should not allow empty string as date time argument. //It can lead us to unexpected results //Only 'null' is possible empty value if (!$originalValue) { throw new InvalidArgumentException('DateTime argument should be well formed string'); } try { $value = new DateTime($value); } catch (\Exception $e) { throw new InvalidArgumentException(sprintf('Invalid DateTime argument "%s"', $value), $e->getCode(), $e); } // if format was specified in metadata - format and compare parsed DateTime object with original string if (isset($dateTimeFormat) && $value->format($dateTimeFormat) !== $originalValue) { throw new InvalidArgumentException(sprintf('Invalid DateTime argument "%s"', $originalValue)); } } } elseif ($type === 'array' || $type[0] === 'a' && strpos($type, 'array<') === 0) { $tmpResult = array(); $tmpType = new PropertyMetadata($property->getName()); $tmpType->setExpose(true)->setSerializedName($property->getSerializedName()); if (preg_match('/array<(?<type>[a-zA-Z\\\\]+)>/', $type, $matches)) { $tmpType->setType($matches['type']); } if ($direct == self::DIRECTION_UNSERIALIZE) { $existsData = $this->exposeValue($object, $property); } foreach ($value as $k => $v) { $tmpObject = $object; if ($direct == self::DIRECTION_UNSERIALIZE && isset($existsData[$k]) && is_object($existsData[$k])) { $tmpObject = $existsData[$k]; $inner = true; } $v = $this->handleValue($v, $tmpType, $direct, $tmpObject, $inner); $tmpResult[$k] = $v; unset($tmpObject); } $value = $tmpResult; unset($tmpResult, $tmpType); } elseif (is_object($value) && $direct == self::DIRECTION_SERIALIZE) { $value = $this->toArray($value); } elseif (is_array($value) && $direct == self::DIRECTION_UNSERIALIZE) { if ($inner) { $innerObject = $object; } else { $innerObject = $this->exposeValue($object, $property); } if (!is_object($innerObject) || !$innerObject instanceof $type) { if (PHP_VERSION_ID >= 50400) { $rc = new \ReflectionClass($type); $innerObject = $rc->newInstanceWithoutConstructor(); } else { $innerObject = unserialize(sprintf('O:%d:"%s":0:{}', strlen($type), $type)); } } $value = $this->toObject($value, $innerObject); } elseif ($type !== null) { throw new InvalidArgumentException(sprintf('Unsupported type: %s', $type)); } } return $value; }
/** * @dataProvider dateTimeProvider * @expectedException \Opensoft\SimpleSerializer\Exception\InvalidArgumentException */ public function testDenormalizationExceptionWrongFormat(DateTime $testDateTime) { $property = new PropertyMetadata('dateTime'); $property->setType('DateTime<Y-m-d H:i>'); $this->datetimeTransformer->denormalize($testDateTime->format(DateTime::COOKIE), $property, new \stdClass()); }
/** * @param PropertyMetadata $metadata */ public function addPropertyMetadata(PropertyMetadata $metadata) { $this->properties[$metadata->getName()] = $metadata; }
/** * @param string $propertyName * @param string|null $propertyType * @return PropertyMetadata */ protected function makeSimpleProperty($propertyName, $propertyType = null) { $simpleProperty = new PropertyMetadata($propertyName); $simpleProperty->setType($propertyType); return $simpleProperty; }