Skip to content

Commit

Permalink
[PropertyInfo] Import the component
Browse files Browse the repository at this point in the history
  • Loading branch information
dunglas authored and fabpot committed Sep 26, 2015
1 parent d1ae400 commit f1eb185
Show file tree
Hide file tree
Showing 29 changed files with 2,306 additions and 1 deletion.
7 changes: 6 additions & 1 deletion composer.json
Expand Up @@ -48,6 +48,7 @@
"symfony/options-resolver": "self.version",
"symfony/process": "self.version",
"symfony/property-access": "self.version",
"symfony/property-info": "self.version",
"symfony/proxy-manager-bridge": "self.version",
"symfony/routing": "self.version",
"symfony/security": "self.version",
Expand Down Expand Up @@ -76,7 +77,11 @@
"monolog/monolog": "~1.11",
"ircmaxell/password-compat": "~1.0",
"ocramius/proxy-manager": "~0.4|~1.0",
"egulias/email-validator": "~1.2"
"egulias/email-validator": "~1.2",
"phpdocumentor/reflection": "^1.0.7"
},
"conflict": {
"phpdocumentor/reflection": "<1.0.7"
},
"autoload": {
"psr-4": {
Expand Down
149 changes: 149 additions & 0 deletions src/Symfony/Bridge/Doctrine/PropertyInfo/DoctrineExtractor.php
@@ -0,0 +1,149 @@
<?php

/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace Symfony\Bridge\Doctrine\PropertyInfo;

use Doctrine\Common\Persistence\Mapping\ClassMetadataFactory;
use Doctrine\Common\Persistence\Mapping\MappingException;
use Doctrine\ORM\Mapping\ClassMetadataInfo;
use Symfony\Component\PropertyInfo\PropertyListExtractorInterface;
use Symfony\Component\PropertyInfo\PropertyTypeExtractorInterface;
use Symfony\Component\PropertyInfo\Type;

/**
* Extracts data using Doctrine ORM and ODM metadata.
*
* @author Kévin Dunglas <dunglas@gmail.com>
*/
class DoctrineExtractor implements PropertyListExtractorInterface, PropertyTypeExtractorInterface
{
/**
* @var ClassMetadataFactory
*/
private $classMetadataFactory;

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

/**
* {@inheritdoc}
*/
public function getProperties($class, array $context = array())
{
try {
$metadata = $this->classMetadataFactory->getMetadataFor($class);
} catch (MappingException $exception) {
return;
}

return array_merge($metadata->getFieldNames(), $metadata->getAssociationNames());
}

/**
* {@inheritdoc}
*/
public function getTypes($class, $property, array $context = array())
{
try {
$metadata = $this->classMetadataFactory->getMetadataFor($class);
} catch (MappingException $exception) {
return;
}

if ($metadata->hasAssociation($property)) {
$class = $metadata->getAssociationTargetClass($property);

if ($metadata->isSingleValuedAssociation($property)) {
if ($metadata instanceof ClassMetadataInfo) {
$nullable = isset($metadata->discriminatorColumn['nullable']) ? $metadata->discriminatorColumn['nullable'] : false;
} else {
$nullable = false;
}

return array(new Type(Type::BUILTIN_TYPE_OBJECT, $nullable, $class));
}

return array(new Type(
Type::BUILTIN_TYPE_OBJECT,
false,
'Doctrine\Common\Collections\Collection',
true,
new Type(Type::BUILTIN_TYPE_INT),
new Type(Type::BUILTIN_TYPE_OBJECT, false, $class)
));
}

if ($metadata->hasField($property)) {
$typeOfField = $metadata->getTypeOfField($property);
$nullable = $metadata instanceof ClassMetadataInfo && $metadata->isNullable($property);

switch ($typeOfField) {
case 'date':
case 'datetime':
case 'datetimetz':
case 'time':
return array(new Type(Type::BUILTIN_TYPE_OBJECT, $nullable, 'DateTime'));

case 'array':
return array(new Type(Type::BUILTIN_TYPE_ARRAY, $nullable, null, true));

case 'simple_array':
return array(new Type(Type::BUILTIN_TYPE_ARRAY, $nullable, null, true, new Type(Type::BUILTIN_TYPE_INT), new Type(Type::BUILTIN_TYPE_STRING)));

case 'json_array':
return array(new Type(Type::BUILTIN_TYPE_ARRAY, $nullable, null, true));

default:
return array(new Type($this->getPhpType($typeOfField), $nullable));
}
}
}

/**
* Gets the corresponding built-in PHP type.
*
* @param string $doctrineType
*
* @return string
*/
private function getPhpType($doctrineType)
{
switch ($doctrineType) {
case 'smallint':
// No break
case 'bigint':
// No break
case 'integer':
return Type::BUILTIN_TYPE_INT;

case 'decimal':
return Type::BUILTIN_TYPE_FLOAT;

case 'text':
// No break
case 'guid':
return Type::BUILTIN_TYPE_STRING;

case 'boolean':
return Type::BUILTIN_TYPE_BOOL;

case 'blob':
// No break
case 'binary':
return Type::BUILTIN_TYPE_RESOURCE;

default:
return $doctrineType;
}
}
}
@@ -0,0 +1,84 @@
<?php

/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace Symfony\Bridge\Doctrine\PropertyInfo\Tests;

use Doctrine\ORM\EntityManager;
use Doctrine\ORM\Tools\Setup;
use Symfony\Bridge\Doctrine\PropertyInfo\DoctrineExtractor;
use Symfony\Component\PropertyInfo\Type;

/**
* @author Kévin Dunglas <dunglas@gmail.com>
*/
class DoctrineExtractorTest extends \PHPUnit_Framework_TestCase
{
/**
* @var DoctrineExtractor
*/
private $extractor;

public function setUp()
{
$config = Setup::createAnnotationMetadataConfiguration(array(__DIR__.DIRECTORY_SEPARATOR.'Fixtures'), true);
$entityManager = EntityManager::create(array('driver' => 'pdo_sqlite'), $config);

$this->extractor = new DoctrineExtractor($entityManager->getMetadataFactory());
}

public function testGetProperties()
{
$this->assertEquals(
array(
'id',
'guid',
'time',
'json',
'simpleArray',
'bool',
'binary',
'foo',
'bar',
),
$this->extractor->getProperties('Symfony\Bridge\Doctrine\Tests\PropertyInfo\Fixtures\DoctrineDummy')
);
}

/**
* @dataProvider typesProvider
*/
public function testExtract($property, array $type = null)
{
$this->assertEquals($type, $this->extractor->getTypes('Symfony\Bridge\Doctrine\Tests\PropertyInfo\Fixtures\DoctrineDummy', $property, array()));
}

public function typesProvider()
{
return array(
array('id', array(new Type(Type::BUILTIN_TYPE_INT))),
array('guid', array(new Type(Type::BUILTIN_TYPE_STRING))),
array('bool', array(new Type(Type::BUILTIN_TYPE_BOOL))),
array('binary', array(new Type(Type::BUILTIN_TYPE_RESOURCE))),
array('json', array(new Type(Type::BUILTIN_TYPE_ARRAY, false, null, true))),
array('foo', array(new Type(Type::BUILTIN_TYPE_OBJECT, false, 'Symfony\Bridge\Doctrine\Tests\PropertyInfo\Fixtures\DoctrineRelation'))),
array('bar', array(new Type(
Type::BUILTIN_TYPE_OBJECT,
false,
'Doctrine\Common\Collections\Collection',
true,
new Type(Type::BUILTIN_TYPE_INT),
new Type(Type::BUILTIN_TYPE_OBJECT, false, 'Symfony\Bridge\Doctrine\Tests\PropertyInfo\Fixtures\DoctrineRelation')
))),
array('simpleArray', array(new Type(Type::BUILTIN_TYPE_ARRAY, false, null, true, new Type(Type::BUILTIN_TYPE_INT), new Type(Type::BUILTIN_TYPE_STRING)))),
array('notMapped', null),
);
}
}
@@ -0,0 +1,74 @@
<?php

/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace Symfony\Bridge\Doctrine\Tests\PropertyInfo\Fixtures;

use Doctrine\ORM\Mapping\Column;
use Doctrine\ORM\Mapping\Entity;
use Doctrine\ORM\Mapping\Id;
use Doctrine\ORM\Mapping\ManyToMany;
use Doctrine\ORM\Mapping\ManyToOne;

/**
* @Entity
*
* @author Kévin Dunglas <dunglas@gmail.com>
*/
class DoctrineDummy
{
/**
* @Id
* @Column(type="smallint")
*/
public $id;

/**
* @ManyToOne(targetEntity="DoctrineRelation")
*/
public $foo;

/**
* @ManyToMany(targetEntity="DoctrineRelation")
*/
public $bar;

/**
* @Column(type="guid")
*/
protected $guid;

/**
* @Column(type="time")
*/
private $time;

/**
* @Column(type="json_array")
*/
private $json;

/**
* @Column(type="simple_array")
*/
private $simpleArray;

/**
* @Column(type="boolean")
*/
private $bool;

/**
* @Column(type="binary")
*/
private $binary;

public $notMapped;
}
@@ -0,0 +1,29 @@
<?php

/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace Symfony\Bridge\Doctrine\Tests\PropertyInfo\Fixtures;

use Doctrine\ORM\Mapping\Column;
use Doctrine\ORM\Mapping\Id;

/**
* @Entity
*
* @author Kévin Dunglas <dunglas@gmail.com>
*/
class DoctrineRelation
{
/**
* @Id
* @Column(type="smallint")
*/
public $id;
}
2 changes: 2 additions & 0 deletions src/Symfony/Bridge/Doctrine/composer.json
Expand Up @@ -26,6 +26,7 @@
"symfony/form": "~2.8|~3.0.0",
"symfony/http-kernel": "~2.2|~3.0.0",
"symfony/property-access": "~2.3|~3.0.0",
"symfony/property-info": "~2.8|3.0",
"symfony/security": "~2.2|~3.0.0",
"symfony/expression-language": "~2.2|~3.0.0",
"symfony/validator": "~2.5,>=2.5.5|~3.0.0",
Expand All @@ -37,6 +38,7 @@
"suggest": {
"symfony/form": "",
"symfony/validator": "",
"symfony/property-info": "",
"doctrine/data-fixtures": "",
"doctrine/dbal": "",
"doctrine/orm": ""
Expand Down

0 comments on commit f1eb185

Please sign in to comment.