Created
September 16, 2016 10:27
-
-
Save greabock/ff4a33d20e9b10db86c63d1851d99038 to your computer and use it in GitHub Desktop.
Doctrine Mapper
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
namespace App\Services; | |
use Doctrine\ORM\EntityManager; | |
use Doctrine\ORM\Mapping\ClassMetadataInfo as MetaInfo; | |
use RuntimeException; | |
class Mapper | |
{ | |
/** | |
* @var EntityManager | |
*/ | |
protected $em; | |
/** | |
* @var callable | |
*/ | |
protected $factory; | |
public function __construct(EntityManager $em, callable $factory) | |
{ | |
$this->em = $em; | |
$this->factory = $factory; | |
} | |
public function json(string $name, $data) | |
{ | |
$properties = json_decode($data, true); | |
return $this->map($name, $properties); | |
} | |
public function map(string $name, array $data, $id = null) | |
{ | |
$meta = $this->em->getClassMetadata($name); | |
$identifier = array_first($meta->getIdentifier()); | |
$identifier = array_pull($data, $identifier); | |
$id = $id ?: $identifier; | |
return $this->buildEntity($meta, $data, $id); | |
} | |
/** | |
* TODO: распилить на части. | |
* | |
* @param MetaInfo $meta | |
* @param array $data | |
* @param null $id | |
* | |
* @return mixed|null|object | |
*/ | |
private function buildEntity(MetaInfo $meta, array $data, $id = null) | |
{ | |
$entity = $this->resolveEntity($meta->getName(), $id); | |
$relationsMaps = array_only($data, $meta->getAssociationNames()); | |
$entityFields = array_only($data, $meta->getFieldNames()); | |
$setters = []; | |
foreach ($relationsMaps as $name => $map) { | |
$setterName = $this->getSetterName($name); | |
if (!method_exists($entity, $setterName)) { | |
continue; | |
} | |
$mapping = $meta->getAssociationMapping($name); | |
$setters[$setterName] = | |
$this->mapRelation($mapping['type'], $mapping['targetEntity'], $map); | |
} | |
foreach ($entityFields as $name => $value) { | |
$setterName = $this->getSetterName($name); | |
if (!method_exists($entity, $setterName)) { | |
continue; | |
} | |
$setters[$setterName] = $value; | |
} | |
$this->fill($entity, $setters); | |
return $entity; | |
} | |
private function resolveEntity($entity, $id = null) | |
{ | |
if (!is_null($id)) { | |
$identity = $this->em->find($entity, $id); | |
if (is_null($identity)) { | |
throw new RuntimeException( | |
"Entity {$entity} with identifier '{$id}' not found" | |
); | |
} | |
return $identity; | |
} | |
return call_user_func($this->factory, $entity); | |
} | |
private function isToMany($type) | |
{ | |
return $type & (MetaInfo::ONE_TO_MANY | MetaInfo::MANY_TO_MANY); | |
} | |
private function mapMany($name, $data) | |
{ | |
return array_map(function ($item) use ($name) { | |
return $this->map($name, $item); | |
}, $data); | |
} | |
private function mapRelation($type, $targetEntity, $map) | |
{ | |
if ($this->isToMany($type)) { | |
return $this->mapMany($targetEntity, $map); | |
} | |
return $this->map($targetEntity, $map); | |
} | |
private function fill($entity, $setters) | |
{ | |
foreach ($setters as $setter => $value) { | |
call_user_func([$entity, $setter], $value); | |
} | |
} | |
private function getSetterName($name) | |
{ | |
return 'set' . studly_case($name); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Laravel binding factory sample