Skip to content

Commit

Permalink
Merge pull request #655 from hkulekci/type-convertion-bug-fix-for-nul…
Browse files Browse the repository at this point in the history
…lable-fields

Type convertion bug fix for nullable fields
  • Loading branch information
TomHAnderson committed Nov 2, 2018
2 parents 854c26e + 03b972d commit 66addcc
Show file tree
Hide file tree
Showing 3 changed files with 152 additions and 2 deletions.
28 changes: 28 additions & 0 deletions src/DoctrineModule/Stdlib/Hydrator/DoctrineObject.php
Expand Up @@ -272,6 +272,10 @@ public function hydrateValue($name, $value, $data = null)
{
$value = parent::hydrateValue($name, $value, $data);

if (is_null($value) && $this->isNullable($name)) {
return null;
}

return $this->handleTypeConversions($value, $this->metadata->getTypeOfField($name));
}

Expand Down Expand Up @@ -535,6 +539,10 @@ function ($item) {
*/
protected function handleTypeConversions($value, $typeOfField)
{
if (is_null($value)) {
return null;
}

switch ($typeOfField) {
case 'boolean':
$value = (bool)$value;
Expand Down Expand Up @@ -630,6 +638,26 @@ function ($value) {
return false;
}

/**
* Check the field is nullable
*
* @param $name
* @return bool
*/
private function isNullable($name)
{
//TODO: need update after updating isNullable method of Doctrine\ORM\Mapping\ClassMetadata
if ($this->metadata->hasField($name)) {
return method_exists($this->metadata, 'isNullable') && $this->metadata->isNullable($name);
} else if ($this->metadata->hasAssociation($name) && method_exists($this->metadata, 'getAssociationMapping')) {
$mapping = $this->metadata->getAssociationMapping($name);

return false !== $mapping && isset($mapping['nullable']) && $mapping['nullable'];
}

return false;
}

/**
* Applies the naming strategy if there is one set
*
Expand Down
Expand Up @@ -1241,7 +1241,7 @@ public function testCanHydrateOneToOneAssociationByValueWithNullableRelation()

$data = ['toOne' => null];

$this->metadata->expects($this->once())
$this->metadata->expects($this->atLeastOnce())
->method('hasAssociation');

$object = $this->hydratorByValue->hydrate($data, $entity);
Expand All @@ -1255,7 +1255,7 @@ public function testCanHydrateOneToOneAssociationByReferenceWithNullableRelation

$this->configureObjectManagerForOneToOneEntity();
$this->objectManager->expects($this->never())->method('find');
$this->metadata->expects($this->once())->method('hasAssociation');
$this->metadata->expects($this->atLeastOnce())->method('hasAssociation');

$data = ['toOne' => null];

Expand Down
Expand Up @@ -119,6 +119,96 @@ function ($arg) use ($genericFieldType) {
);
}

public function configureObjectManagerForOneToOneEntity()
{
$refl = new ReflectionClass('DoctrineModuleTest\Stdlib\Hydrator\Asset\OneToOneEntity');

$this
->metadata
->expects($this->any())
->method('getFieldNames')
->will($this->returnValue(['id']));

$this
->metadata
->expects($this->any())
->method('getAssociationNames')
->will($this->returnValue(['toOne']));

$this
->metadata
->expects($this->any())
->method('getTypeOfField')
->with($this->logicalOr($this->equalTo('id'), $this->equalTo('toOne')))
->will(
$this->returnCallback(
function ($arg) {
if ($arg === 'id') {
return 'integer';
} elseif ($arg === 'toOne') {
return 'DoctrineModuleTest\Stdlib\Hydrator\Asset\ByValueDifferentiatorEntity';
}

throw new \InvalidArgumentException();
}
)
);

$this
->metadata
->expects($this->any())
->method('hasAssociation')
->with($this->logicalOr($this->equalTo('id'), $this->equalTo('toOne')))
->will(
$this->returnCallback(
function ($arg) {
if ($arg === 'id') {
return false;
} elseif ($arg === 'toOne') {
return true;
}

throw new \InvalidArgumentException();
}
)
);

$this
->metadata
->expects($this->any())
->method('isSingleValuedAssociation')
->with('toOne')
->will($this->returnValue(true));

$this
->metadata
->expects($this->any())
->method('getAssociationTargetClass')
->with('toOne')
->will($this->returnValue('DoctrineModuleTest\Stdlib\Hydrator\Asset\ByValueDifferentiatorEntity'));

$this
->metadata
->expects($this->any())
->method('getReflectionClass')
->will($this->returnValue($refl));

$this
->metadata
->expects($this->any())
->method('getIdentifier')
->will($this->returnValue(["id"]));

$this->hydratorByValue = new DoctrineObjectHydrator(
$this->objectManager,
true
);
$this->hydratorByReference = new DoctrineObjectHydrator(
$this->objectManager,
false
);
}

public function testHandleTypeConversionsDatetime()
{
// When using hydration by value, it will use the public API of the entity to set values (setters)
Expand Down Expand Up @@ -621,4 +711,36 @@ public function testHandleTypeConversionsDecimal()
$this->assertTrue(is_string($entity->getGenericField()));
$this->assertEquals('12345', $entity->getGenericField());
}

public function testHandleTypeConversionsNullable()
{
// When using hydration by value, it will use the public API of the entity to set values (setters)
$this->configureObjectManagerForSimpleEntityWithGenericField(null);

$entity = new Asset\SimpleEntityWithGenericField();
$data = ['genericField' => null];

$entity = $this->hydratorByValue->hydrate($data, $entity);

$this->assertNull($entity->getGenericField());

$entity = new Asset\SimpleEntityWithGenericField();
$data = ['genericField' => null];

$entity = $this->hydratorByReference->hydrate($data, $entity);

$this->assertNull($entity->getGenericField());
}

public function testHandleTypeConversionsNullableForAssociatedFields()
{
$this->configureObjectManagerForOneToOneEntity();

$entity = new Asset\OneToOneEntity();
$data = ['toOne' => null];

$entity = $this->hydratorByReference->hydrate($data, $entity);

$this->assertNull($entity->getToOne(false));
}
}

0 comments on commit 66addcc

Please sign in to comment.