Skip to content

Commit

Permalink
add FinderAggregateRepository
Browse files Browse the repository at this point in the history
  • Loading branch information
maxgu committed Mar 22, 2016
1 parent 2d0f09d commit 92bffa9
Showing 1 changed file with 272 additions and 0 deletions.
272 changes: 272 additions & 0 deletions src/FinderAggregateRepository.php
@@ -0,0 +1,272 @@
<?php

namespace T4webInfrastructure;

use ArrayObject;
use Zend\Db\TableGateway\TableGateway;
use Zend\Db\Sql\Select;
use T4webDomainInterface\Infrastructure\RepositoryInterface;
use T4webDomainInterface\Infrastructure\CriteriaInterface;
use T4webDomainInterface\EntityInterface;
use T4webDomainInterface\EntityFactoryInterface;

class FinderAggregateRepository implements RepositoryInterface
{
/**
* @var TableGateway
*/
private $tableGateway;

/**
* @var Mapper
*/
private $mapper;

/**
* @var EntityFactoryInterface
*/
private $entityFactory;

/**
* @var RepositoryInterface
*/
private $entityRepository;

/**
* @var RepositoryInterface[]
*/
private $relatedRepository;

/**
* @var array
*/
private $relationsConfig;

/**
* @var ArrayObject[]
*/
private $with;

/**
* FinderAggregateRepository constructor.
* @param TableGateway $tableGateway
* @param Mapper $mapper
* @param EntityFactoryInterface $entityFactory
* @param RepositoryInterface $entityRepository
* @param RepositoryInterface[] $relatedRepository
* @param array $relationsConfig
*/
public function __construct(
TableGateway $tableGateway,
Mapper $mapper,
EntityFactoryInterface $entityFactory,
RepositoryInterface $entityRepository,
array $relatedRepository,
array $relationsConfig)
{
$this->tableGateway = $tableGateway;
$this->mapper = $mapper;
$this->entityFactory = $entityFactory;
$this->entityRepository = $entityRepository;
$this->relatedRepository = $relatedRepository;
$this->relationsConfig = $relationsConfig;
}

public function findWith($entityName)
{
if (!isset($this->relatedRepository[$entityName])) {
throw new \RuntimeException(get_class($this) . ": related $entityName repository not exists");
}

$this->with[$entityName] = new ArrayObject();
}

/**
* @param mixed $criteria
* @return EntityInterface|null
*/
public function find($criteria)
{
if (empty($this->with)) {
return $this->entityRepository->find($criteria);
}

/** @var Select $select */
$select = $criteria->getQuery();

$select->limit(1)->offset(0);
$result = $this->tableGateway->selectWith($select)->toArray();

if (!isset($result[0])) {
return;
}

$row = $result[0];

foreach ($this->with as $relatedEntityName => $relatedEntityIds) {
$relatedField = $this->getRelatedField($relatedEntityName);

if (!isset($row[$relatedField])) {
throw new \RuntimeException(get_class($this) . ": relation field $relatedEntityName not fetched");
}

if (!in_array($row[$relatedField], (array)$relatedEntityIds)) {
$relatedEntityIds->append($row[$relatedField]);
}
}

$relatedEntities = [];
foreach ($this->with as $relatedEntityName => $relatedEntityIds) {
$criteria = $this->relatedRepository[$relatedEntityName]->createCriteria(['id.in' => (array)$relatedEntityIds]);
$relatedEntities[$relatedEntityName] = $this->relatedRepository[$relatedEntityName]->findMany($criteria);
}

$relatedField = $this->getRelatedField($relatedEntityName);

$entityArgs = [
'data' => $this->mapper->fromTableRow($row)
];

foreach ($this->relationsConfig as $entityName => $joinRule) {
if (isset($relatedEntities[$entityName])) {
if (isset($relatedEntities[$entityName][$row[$relatedField]])) {
$entityArgs['aggregateItems'][] = $relatedEntities[$entityName][$row[$relatedField]];
} else {
$entityArgs['aggregateItems'][] = null;
}
} else {
$entityArgs['aggregateItems'][] = null;
}
}

$entity = $this->entityFactory->create($entityArgs);

$this->with = null;

return $entity;
}

/**
* @param mixed $criteria
* @return EntityInterface[]
*/
public function findMany($criteria)
{
if (empty($this->with)) {
return $this->entityRepository->findMany($criteria);
}

/** @var Select $select */
$select = $criteria->getQuery();

$rows = $this->tableGateway->selectWith($select)->toArray();

foreach ($rows as $row) {
foreach ($this->with as $relatedEntityName => $relatedEntityIds) {
$relatedField = $this->getRelatedField($relatedEntityName);

if (!isset($row[$relatedField])) {
throw new \RuntimeException(get_class($this) . ": relation field $relatedEntityName not fetched");
}

if (!in_array($row[$relatedField], (array)$relatedEntityIds)) {
$relatedEntityIds->append($row[$relatedField]);
}
}
}

$relatedEntities = [];
foreach ($this->with as $relatedEntityName => $relatedEntityIds) {
$criteria = $this->relatedRepository[$relatedEntityName]->createCriteria(['id.in' => (array)$relatedEntityIds]);
$relatedEntities[$relatedEntityName] = $this->relatedRepository[$relatedEntityName]->findMany($criteria);
}

$entitiesArgs = [];
foreach ($rows as &$row) {
$relatedField = $this->getRelatedField($relatedEntityName);

$entityArgs = [
'data' => $this->mapper->fromTableRow($row)
];

foreach ($this->relationsConfig as $entityName => $joinRule) {
if (isset($relatedEntities[$entityName])) {
if (isset($relatedEntities[$entityName][$row[$relatedField]])) {
$entityArgs['aggregateItems'][] = $relatedEntities[$entityName][$row[$relatedField]];
} else {
$entityArgs['aggregateItems'][] = null;
}
} else {
$entityArgs['aggregateItems'][] = null;
}
}

$entitiesArgs[] = $entityArgs;
}

$entities = $this->entityFactory->createCollection($entitiesArgs);

$this->with = null;

return $entities;
}

/**
* @param mixed $id
* @return EntityInterface|null
*/
public function findById($id)
{
$criteria = $this->createCriteria();
$criteria->equalTo('id', $id);

return $this->find($criteria);
}

private function getRelatedField($entityName)
{
if (!isset($this->relationsConfig[$entityName])) {
throw new \RuntimeException(get_class($this) . ": relation $entityName not exists");
}

list($table, $field) = explode('.', $this->relationsConfig[$entityName][0]);

return $field;
}

/**
* @param mixed $criteria
* @return int
*/
public function count($criteria)
{
return $this->entityRepository->count($criteria);
}

/**
* @param array $filter
* @return CriteriaInterface
*/
public function createCriteria(array $filter = [])
{
return $this->entityRepository->createCriteria($filter);
}

/**
* @param EntityInterface $entity
* @return EntityInterface|int|null
*/
public function add(EntityInterface $entity)
{
throw new \RuntimeException(get_class($this) . ' cannot adding');
}

/**
* @param EntityInterface $entity
* @return void
*/
public function remove(EntityInterface $entity)
{
throw new \RuntimeException(get_class($this) . ' cannot removing');
}
}

0 comments on commit 92bffa9

Please sign in to comment.