Skip to content

Commit

Permalink
Refactoring (#387)
Browse files Browse the repository at this point in the history
  • Loading branch information
Tigrov authored Sep 30, 2024
1 parent 5c4151d commit 3dde794
Show file tree
Hide file tree
Showing 10 changed files with 185 additions and 136 deletions.
11 changes: 8 additions & 3 deletions src/AbstractActiveRecord.php
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,12 @@
abstract class AbstractActiveRecord implements ActiveRecordInterface
{
private array|null $oldValues = null;
/**
* @var ActiveRecordInterface[]|ActiveRecordInterface[][]|array[]|array[][]
* @psalm-var array<string, ActiveRecordInterface|ActiveRecordInterface[]|array|array[]|null>
*/
private array $related = [];
/** @psalm-var string[][] */
/** @var string[][] */
private array $relationsDependencies = [];

/**
Expand Down Expand Up @@ -466,6 +470,7 @@ public function link(string $relationName, ActiveRecordInterface $arClass, array
if (!$relation->getMultiple()) {
$this->related[$relationName] = $arClass;
} elseif (isset($this->related[$relationName])) {
/** @psalm-var ActiveRecordInterface[] $this->related[$relationName] */
$indexBy = $relation->getIndexBy();
if ($indexBy !== null) {
if ($indexBy instanceof Closure) {
Expand Down Expand Up @@ -880,7 +885,7 @@ public function unlink(string $relationName, ActiveRecordInterface $arClass, boo
$values = $this->get($b);
/** relation via array valued property */
if (is_array($values)) {
if (($key = array_search($arClass->get($a), $values, false)) !== false) {
if (($key = array_search($arClass->get($a), $values)) !== false) {
unset($values[$key]);
$this->set($b, array_values($values));
}
Expand Down Expand Up @@ -1020,7 +1025,7 @@ public function unlinkAll(string $relationName, bool $delete = false): void
* @param ActiveQueryInterface $relation Relation instance.
* @param string|null $viaRelationName Intermediate relation.
*/
protected function setRelationDependencies(
private function setRelationDependencies(
string $name,
ActiveQueryInterface $relation,
string $viaRelationName = null
Expand Down
90 changes: 46 additions & 44 deletions src/ActiveQuery.php
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,9 @@
* query join condition.
*
* @psalm-import-type ARClass from ActiveQueryInterface
* @psalm-import-type IndexKey from ArArrayHelper
*
* @psalm-property IndexKey $indexBy
*/
class ActiveQuery extends Query implements ActiveQueryInterface
{
Expand Down Expand Up @@ -132,16 +135,12 @@ public function all(): array

public function batch(int $batchSize = 100): BatchQueryResultInterface
{
return parent::batch($batchSize)->setPopulatedMethod(
fn (array $rows, null|Closure|string $indexBy) => $this->populate($rows, $indexBy)
);
return parent::batch($batchSize)->setPopulatedMethod($this->populate(...));
}

public function each(int $batchSize = 100): BatchQueryResultInterface
{
return parent::each($batchSize)->setPopulatedMethod(
fn (array $rows, null|Closure|string $indexBy) => $this->populate($rows, $indexBy)
);
return parent::each($batchSize)->setPopulatedMethod($this->populate(...));
}

/**
Expand Down Expand Up @@ -182,8 +181,9 @@ public function prepare(QueryBuilderInterface $builder): QueryInterface
} else {
$where = $this->getWhere();

if ($this->via instanceof self) {
if ($this->via instanceof ActiveQueryInterface) {
/** via junction table */
/** @var self $this->via */
$viaModels = $this->via->findJunctionRows([$this->primaryModel]);

$this->filterByModels($viaModels);
Expand All @@ -194,6 +194,7 @@ public function prepare(QueryBuilderInterface $builder): QueryInterface
if ($viaCallableUsed) {
$viaModels = $viaQuery->all();
} elseif ($this->primaryModel->isRelationPopulated($viaName)) {
/** @var ActiveRecordInterface[]|array[] $viaModels */
$viaModels = $this->primaryModel->relation($viaName);
} else {
$viaModels = $viaQuery->all();
Expand Down Expand Up @@ -266,48 +267,53 @@ public function populate(array $rows, Closure|string|null $indexBy = null): arra
*
* This method is mainly called when a join query is performed, which may cause duplicated rows being returned.
*
* @param array $models The models to be checked.
* @param ActiveRecordInterface[]|array[] $models The models to be checked.
*
* @throws CircularReferenceException
* @throws Exception
* @throws InvalidConfigException
* @throws NotInstantiableException
*
* @return array The distinctive models.
* @return ActiveRecordInterface[]|array[] The distinctive models.
*/
private function removeDuplicatedModels(array $models): array
{
$model = reset($models);

if ($this->asArray) {
$pks = $this->getARInstance()->primaryKey();
$instance = $this->getARInstance();
$pks = $instance->primaryKey();

if (empty($pks)) {
throw new InvalidConfigException('Primary key of "' . $this->getARClassName() . '" can not be empty.');
throw new InvalidConfigException('Primary key of "' . $instance::class . '" can not be empty.');
}

foreach ($pks as $pk) {
/** @var array $model */
if (!isset($model[$pk])) {
return $models;
}
}

/** @var array[] $models */
if (count($pks) === 1) {
$hash = array_column($models, reset($pks));
} else {
$flippedPks = array_flip($pks);
$hash = array_map(
static fn ($model): string => serialize(array_intersect_key($model, $flippedPks)),
static fn (array $model): string => serialize(array_intersect_key($model, $flippedPks)),
$models
);
}
} else {
/** @var ActiveRecordInterface $model */
$pks = $model->getPrimaryKey(true);

if (empty($pks)) {
throw new InvalidConfigException('Primary key of "' . $this->getARClassName() . '" can not be empty.');
throw new InvalidConfigException('Primary key of "' . $model::class . '" can not be empty.');
}

/** @var ActiveRecordInterface[] $models */
foreach ($pks as $pk) {
if ($pk === null) {
return $models;
Expand All @@ -316,9 +322,15 @@ private function removeDuplicatedModels(array $models): array

if (count($pks) === 1) {
$key = array_key_first($pks);
$hash = array_map(static fn ($model): string => (string) $model->get($key), $models);
$hash = array_map(
static fn (ActiveRecordInterface $model): string => (string) $model->get($key),
$models
);
} else {
$hash = array_map(static fn ($model): string => serialize($model->getPrimaryKey(true)), $models);
$hash = array_map(
static fn (ActiveRecordInterface $model): string => serialize($model->getPrimaryKey(true)),
$models
);
}
}

Expand All @@ -327,6 +339,7 @@ private function removeDuplicatedModels(array $models): array

public function one(): array|ActiveRecordInterface|null
{
/** @var array|null $row */
$row = parent::one();

if ($row === null) {
Expand Down Expand Up @@ -384,7 +397,7 @@ public function joinWith(
array|string $with,
array|bool $eagerLoading = true,
array|string $joinType = 'LEFT JOIN'
): self {
): static {
$relations = [];

foreach ((array) $with as $name => $callback) {
Expand All @@ -399,7 +412,7 @@ public function joinWith(

$name = $relation;

$callback = static function (self $query) use ($callback, $alias): void {
$callback = static function (ActiveQueryInterface $query) use ($callback, $alias): void {
$query->alias($alias);

if ($callback !== null) {
Expand Down Expand Up @@ -492,7 +505,7 @@ public function buildJoinWith(): void
}
}

public function innerJoinWith(array|string $with, array|bool $eagerLoading = true): self
public function innerJoinWith(array|string $with, array|bool $eagerLoading = true): static
{
return $this->joinWith($with, $eagerLoading, 'INNER JOIN');
}
Expand Down Expand Up @@ -633,7 +646,7 @@ private function joinWithRelation(ActiveQueryInterface $parent, ActiveQueryInter
/** @var ActiveQuery $child */
$child->via = null;

if ($via instanceof self) {
if ($via instanceof ActiveQueryInterface) {
// via table
$this->joinWithRelation($parent, $via, $joinType);
$this->joinWithRelation($via, $child, $joinType);
Expand Down Expand Up @@ -716,7 +729,7 @@ private function joinWithRelation(ActiveQueryInterface $parent, ActiveQueryInter
}
}

public function onCondition(array|string $condition, array $params = []): self
public function onCondition(array|string $condition, array $params = []): static
{
$this->on = $condition;

Expand All @@ -725,7 +738,7 @@ public function onCondition(array|string $condition, array $params = []): self
return $this;
}

public function andOnCondition(array|string $condition, array $params = []): self
public function andOnCondition(array|string $condition, array $params = []): static
{
if ($this->on === null) {
$this->on = $condition;
Expand All @@ -738,7 +751,7 @@ public function andOnCondition(array|string $condition, array $params = []): sel
return $this;
}

public function orOnCondition(array|string $condition, array $params = []): self
public function orOnCondition(array|string $condition, array $params = []): static
{
if ($this->on === null) {
$this->on = $condition;
Expand All @@ -751,13 +764,15 @@ public function orOnCondition(array|string $condition, array $params = []): self
return $this;
}

public function viaTable(string $tableName, array $link, callable $callable = null): self
public function viaTable(string $tableName, array $link, callable $callable = null): static
{
$arClass = $this->primaryModel ?? $this->arClass;
$arClassInstance = new self($arClass);

/** @psalm-suppress UndefinedMethod */
$relation = $arClassInstance->from([$tableName])->link($link)->multiple(true)->asArray();
$relation = (new static($arClass))
->from([$tableName])
->link($link)
->multiple(true)
->asArray();

$this->via = $relation;

Expand All @@ -768,9 +783,9 @@ public function viaTable(string $tableName, array $link, callable $callable = nu
return $this;
}

public function alias(string $alias): self
public function alias(string $alias): static
{
if (empty($this->from) || count($this->from) < 2) {
if (count($this->from) < 2) {
[$tableName] = $this->getTableNameAndAlias();
$this->from = [$alias => $tableName];
} else {
Expand Down Expand Up @@ -906,36 +921,23 @@ protected function findByCondition(mixed $condition): static
return $this->where($condition);
}

public function findBySql(string $sql, array $params = []): self
public function findBySql(string $sql, array $params = []): static
{
return $this->sql($sql)->params($params);
}

public function on(array|string|null $value): self
public function on(array|string|null $value): static
{
$this->on = $value;
return $this;
}

public function sql(string|null $value): self
public function sql(string|null $value): static
{
$this->sql = $value;
return $this;
}

public function getARClassName(): string
{
if ($this->arClass instanceof ActiveRecordInterface) {
return $this->arClass::class;
}

if ($this->arClass instanceof Closure) {
return ($this->arClass)()::class;
}

return $this->arClass;
}

public function getARInstance(): ActiveRecordInterface
{
if ($this->arClass instanceof ActiveRecordInterface) {
Expand Down
Loading

0 comments on commit 3dde794

Please sign in to comment.