[Serializer] Improve ObjectNormalizer performance
This commit is contained in:
parent
1abfecf5ca
commit
683f0f7315
@ -26,6 +26,8 @@ use Symfony\Component\Serializer\NameConverter\NameConverterInterface;
|
|||||||
*/
|
*/
|
||||||
class ObjectNormalizer extends AbstractNormalizer
|
class ObjectNormalizer extends AbstractNormalizer
|
||||||
{
|
{
|
||||||
|
private static $attributesCache = array();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var PropertyAccessorInterface
|
* @var PropertyAccessorInterface
|
||||||
*/
|
*/
|
||||||
@ -58,42 +60,7 @@ class ObjectNormalizer extends AbstractNormalizer
|
|||||||
}
|
}
|
||||||
|
|
||||||
$data = array();
|
$data = array();
|
||||||
$attributes = $this->getAllowedAttributes($object, $context, true);
|
$attributes = $this->getAttributes($object, $context);
|
||||||
|
|
||||||
// If not using groups, detect manually
|
|
||||||
if (false === $attributes) {
|
|
||||||
$attributes = array();
|
|
||||||
|
|
||||||
// methods
|
|
||||||
$reflClass = new \ReflectionClass($object);
|
|
||||||
foreach ($reflClass->getMethods(\ReflectionMethod::IS_PUBLIC) as $reflMethod) {
|
|
||||||
if (
|
|
||||||
!$reflMethod->isStatic() &&
|
|
||||||
!$reflMethod->isConstructor() &&
|
|
||||||
!$reflMethod->isDestructor() &&
|
|
||||||
0 === $reflMethod->getNumberOfRequiredParameters()
|
|
||||||
) {
|
|
||||||
$name = $reflMethod->getName();
|
|
||||||
|
|
||||||
if (strpos($name, 'get') === 0 || strpos($name, 'has') === 0) {
|
|
||||||
// getters and hassers
|
|
||||||
$attributes[lcfirst(substr($name, 3))] = true;
|
|
||||||
} elseif (strpos($name, 'is') === 0) {
|
|
||||||
// issers
|
|
||||||
$attributes[lcfirst(substr($name, 2))] = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// properties
|
|
||||||
foreach ($reflClass->getProperties(\ReflectionProperty::IS_PUBLIC) as $reflProperty) {
|
|
||||||
if (!$reflProperty->isStatic()) {
|
|
||||||
$attributes[$reflProperty->getName()] = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$attributes = array_keys($attributes);
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach ($attributes as $attribute) {
|
foreach ($attributes as $attribute) {
|
||||||
if (in_array($attribute, $this->ignoredAttributes)) {
|
if (in_array($attribute, $this->ignoredAttributes)) {
|
||||||
@ -162,4 +129,64 @@ class ObjectNormalizer extends AbstractNormalizer
|
|||||||
|
|
||||||
return $object;
|
return $object;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets and caches attributes for this class and context.
|
||||||
|
*
|
||||||
|
* @param object $object
|
||||||
|
* @param array $context
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
private function getAttributes($object, array $context)
|
||||||
|
{
|
||||||
|
$key = sprintf('%s-%s', get_class($object), serialize($context));
|
||||||
|
|
||||||
|
if (isset(self::$attributesCache[$key])) {
|
||||||
|
return self::$attributesCache[$key];
|
||||||
|
}
|
||||||
|
|
||||||
|
$allowedAttributes = $this->getAllowedAttributes($object, $context, true);
|
||||||
|
|
||||||
|
if (false !== $allowedAttributes) {
|
||||||
|
return self::$attributesCache[$key] = $allowedAttributes;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If not using groups, detect manually
|
||||||
|
$attributes = array();
|
||||||
|
|
||||||
|
// methods
|
||||||
|
$reflClass = new \ReflectionClass($object);
|
||||||
|
foreach ($reflClass->getMethods(\ReflectionMethod::IS_PUBLIC) as $reflMethod) {
|
||||||
|
if (
|
||||||
|
$reflMethod->getNumberOfRequiredParameters() !== 0 ||
|
||||||
|
$reflMethod->isStatic() ||
|
||||||
|
$reflMethod->isConstructor() ||
|
||||||
|
$reflMethod->isDestructor()
|
||||||
|
) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$name = $reflMethod->getName();
|
||||||
|
|
||||||
|
if (strpos($name, 'get') === 0 || strpos($name, 'has') === 0) {
|
||||||
|
// getters and hassers
|
||||||
|
$attributes[lcfirst(substr($name, 3))] = true;
|
||||||
|
} elseif (strpos($name, 'is') === 0) {
|
||||||
|
// issers
|
||||||
|
$attributes[lcfirst(substr($name, 2))] = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// properties
|
||||||
|
foreach ($reflClass->getProperties(\ReflectionProperty::IS_PUBLIC) as $reflProperty) {
|
||||||
|
if ($reflProperty->isStatic()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$attributes[$reflProperty->getName()] = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return self::$attributesCache[$key] = array_keys($attributes);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -29,7 +29,7 @@ use Symfony\Component\Serializer\Tests\Fixtures\GroupDummy;
|
|||||||
class ObjectNormalizerTest extends \PHPUnit_Framework_TestCase
|
class ObjectNormalizerTest extends \PHPUnit_Framework_TestCase
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* @var ObjectNormalizerTest
|
* @var ObjectNormalizer
|
||||||
*/
|
*/
|
||||||
private $normalizer;
|
private $normalizer;
|
||||||
/**
|
/**
|
||||||
@ -239,6 +239,18 @@ class ObjectNormalizerTest extends \PHPUnit_Framework_TestCase
|
|||||||
$this->assertEquals($obj, $normalized);
|
$this->assertEquals($obj, $normalized);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function testNormalizeNoPropertyInGroup()
|
||||||
|
{
|
||||||
|
$classMetadataFactory = new ClassMetadataFactory(new AnnotationLoader(new AnnotationReader()));
|
||||||
|
$this->normalizer = new ObjectNormalizer($classMetadataFactory);
|
||||||
|
$this->normalizer->setSerializer($this->serializer);
|
||||||
|
|
||||||
|
$obj = new GroupDummy();
|
||||||
|
$obj->setFoo('foo');
|
||||||
|
|
||||||
|
$this->assertEquals(array(), $this->normalizer->normalize($obj, null, array('groups' => array('notExist'))));
|
||||||
|
}
|
||||||
|
|
||||||
public function testGroupsNormalizeWithNameConverter()
|
public function testGroupsNormalizeWithNameConverter()
|
||||||
{
|
{
|
||||||
$classMetadataFactory = new ClassMetadataFactory(new AnnotationLoader(new AnnotationReader()));
|
$classMetadataFactory = new ClassMetadataFactory(new AnnotationLoader(new AnnotationReader()));
|
||||||
|
Reference in New Issue
Block a user