200 lines
6.2 KiB
PHP
200 lines
6.2 KiB
PHP
<?php
|
|
|
|
namespace Nest\Model;
|
|
|
|
use Nest\Database\Query\Raw;
|
|
use Nest\Database\Exceptions\UnknownDatabaseException;
|
|
use Nest\Model\Query\EntityQuery;
|
|
use function Nest\Utils\array_first;
|
|
use function Nest\Utils\array_first_or_val;
|
|
use function Nest\Utils\str_snake_singularize;
|
|
|
|
class EntityPropertyInstance extends ReadableEntityPropertyBlueprint
|
|
{
|
|
/**
|
|
* Goal entity instance.
|
|
* @var Entity
|
|
*/
|
|
private Entity $entity;
|
|
|
|
/**
|
|
* Create an entity property instance from an entity property definition.
|
|
* @param EntityPropertyBlueprint $entityProperty The entity property to copy from.
|
|
*/
|
|
public function __construct(EntityPropertyBlueprint $entityProperty)
|
|
{
|
|
// Copy all fields.
|
|
$this->class = $entityProperty->class;
|
|
$this->multiple = $entityProperty->multiple;
|
|
$this->allowInline = $entityProperty->allowInline;
|
|
$this->mode = $entityProperty->mode;
|
|
$this->localKey = $entityProperty->localKey;
|
|
$this->relatedKey = $entityProperty->relatedKey;
|
|
$this->pivotTable = $entityProperty->pivotTable;
|
|
$this->pivotLocalKey = $entityProperty->pivotLocalKey;
|
|
$this->pivotRelatedKey = $entityProperty->pivotRelatedKey;
|
|
$this->eagerLoad = $entityProperty->eagerLoad;
|
|
|
|
// Initialize goal entity.
|
|
$this->entity = new ($this->getClass())();
|
|
}
|
|
|
|
/**
|
|
* Create a new related entity.
|
|
* @return Entity A new related entity instance.
|
|
*/
|
|
public function newEntity(): Entity
|
|
{
|
|
return $this->entity->new();
|
|
}
|
|
|
|
/**
|
|
* Determine if the property can be inline loaded.
|
|
* @return bool True if the property can be inline loaded.
|
|
*/
|
|
public function canInlineLoad(): bool
|
|
{
|
|
return !$this->isMultiple() && $this->isInlineAllowed();
|
|
}
|
|
|
|
/**
|
|
* Build a query to retrieve relations for the given entities.
|
|
* @param Entity[] $entities Entities for which to retrieve relations.
|
|
* @return EntityQuery Built entities query.
|
|
* @throws UnknownDatabaseException
|
|
*/
|
|
public function queryFor(array $entities): EntityQuery
|
|
{
|
|
// Initialize query.
|
|
$query = $this->entity->query();
|
|
|
|
if (empty($entities))
|
|
// No entities, return a simple query without conditions.
|
|
return $query;
|
|
|
|
// Get a reference entity.
|
|
$referenceEntity = array_first($entities);
|
|
// Entity primary key.
|
|
$entityPrimaryKey = array_first_or_val($referenceEntity->getPrimaryFields());
|
|
|
|
// Get keys from entities list.
|
|
$entitiesKeys = array_column($entities, $entityPrimaryKey);
|
|
|
|
switch ($this->getMode())
|
|
{ // Build query depending on the relation mode.
|
|
case EntityPropertyMode::LOCAL:
|
|
$query
|
|
->select(new Raw("\"{$referenceEntity->getTableName()}\".\"$entityPrimaryKey\" AS \"__reference_key\""))
|
|
// Generate SELECT for the related entity.
|
|
->select(...$this->entity->sqlSelectFields())
|
|
->innerJoin($referenceEntity->getTableName())->on(
|
|
"{$this->entity->getTableName()}.".(
|
|
$this->getRelatedKey() ?? array_first_or_val($this->entity->getPrimaryFields())
|
|
),
|
|
"=",
|
|
"{$referenceEntity->getTableName()}.".(
|
|
$this->getLocalKey() ?? str_snake_singularize($this->entity->getTableName())."_id"
|
|
),
|
|
)->whereIn(
|
|
"{$referenceEntity->getTableName()}.$entityPrimaryKey", $entitiesKeys
|
|
);
|
|
break;
|
|
case EntityPropertyMode::RELATED:
|
|
$query
|
|
->select(new Raw("\"{$this->entity->getTableName()}\".\"".(
|
|
$this->getRelatedKey() ?? str_snake_singularize($referenceEntity->getTableName())."_id"
|
|
)."\" AS \"__reference_key\""))
|
|
// Generate SELECT for the related entity.
|
|
->select(...$this->entity->sqlSelectFields())
|
|
->whereIn(
|
|
"{$this->entity->getTableName()}.".(
|
|
$this->getRelatedKey() ?? str_snake_singularize($referenceEntity->getTableName())."_id"
|
|
)."",
|
|
$entitiesKeys
|
|
);
|
|
break;
|
|
case EntityPropertyMode::PIVOT:
|
|
$query
|
|
->select(new Raw("\"{$this->entity->getTableName()}\".\"".(
|
|
$this->getPivotLocalKey() ?? str_snake_singularize($referenceEntity->getTableName())."_id"
|
|
)."\" AS \"__reference_key\""))
|
|
// Generate SELECT for the related entity.
|
|
->select(...$this->entity->sqlSelectFields())
|
|
->innerJoin($this->getPivotTable())->on(
|
|
"{$query->getTableName()}.".(
|
|
$this->getRelatedKey() ?? $query->getPrimaryKeyName()
|
|
),
|
|
"=",
|
|
"{$this->getPivotTable()}.".(
|
|
$this->getPivotLocalKey() ?? str_snake_singularize($query->getTableName())."_id"
|
|
),
|
|
)
|
|
->whereIn(
|
|
"{$this->getPivotTable()}.".(
|
|
$this->getPivotLocalKey() ?? str_snake_singularize($referenceEntity->getTableName())."_id"
|
|
),
|
|
$entitiesKeys
|
|
);
|
|
break;
|
|
}
|
|
|
|
return $query;
|
|
}
|
|
|
|
/**
|
|
* Setup inline loading for the current property in an entity query.
|
|
* @param EntityQuery $query The entity query to alter.
|
|
* @return void
|
|
*/
|
|
public function setupInlineLoading(EntityQuery $query): void
|
|
{
|
|
switch ($this->getMode())
|
|
{ // Add join depending on the relation mode.
|
|
case EntityPropertyMode::LOCAL:
|
|
$query
|
|
->leftJoin($this->entity->getTableName())->on(
|
|
"{$query->getTableName()}.".(
|
|
$this->getLocalKey() ?? str_snake_singularize($this->entity->getTableName())."_id"
|
|
),
|
|
"=",
|
|
"{$this->entity->getTableName()}.".(
|
|
$this->getRelatedKey() ?? array_first_or_val($this->entity->getPrimaryFields())
|
|
),
|
|
);
|
|
break;
|
|
case EntityPropertyMode::RELATED:
|
|
$query
|
|
->leftJoin($this->entity->getTableName())->on(
|
|
"{$query->getTableName()}.".(
|
|
$this->getLocalKey() ?? $query->getPrimaryKeyName()
|
|
),
|
|
"=",
|
|
"{$this->entity->getTableName()}.".(
|
|
$this->getRelatedKey() ?? str_snake_singularize($query->getTableName())."_id"
|
|
),
|
|
);
|
|
break;
|
|
case EntityPropertyMode::PIVOT:
|
|
$query
|
|
->leftJoin($this->getPivotTable())->on(
|
|
"{$query->getTableName()}.".(
|
|
$this->getLocalKey() ?? $query->getPrimaryKeyName()
|
|
),
|
|
"=",
|
|
"{$this->getPivotTable()}.".(
|
|
$this->getPivotLocalKey() ?? str_snake_singularize($query->getTableName())."_id"
|
|
),
|
|
)
|
|
->leftJoin($this->entity->getTableName())->on(
|
|
"{$this->getPivotTable()}.".(
|
|
$this->getPivotRelatedKey() ?? str_snake_singularize($this->entity->getTableName())."_id"
|
|
),
|
|
"=",
|
|
"{$this->entity->getTableName()}.".(
|
|
$this->getRelatedKey() ?? array_first_or_val($this->entity->getPrimaryFields())
|
|
),
|
|
);
|
|
break;
|
|
}
|
|
}
|
|
}
|