Skip to content

Commit

Permalink
Merge branch 'refs/heads/master' into add-MagicActiveRecord
Browse files Browse the repository at this point in the history
  • Loading branch information
Tigrov committed May 28, 2024
2 parents a4b600e + bc8b6fb commit e23cab2
Show file tree
Hide file tree
Showing 7 changed files with 275 additions and 270 deletions.
40 changes: 19 additions & 21 deletions src/AbstractActiveRecord.php
Original file line number Diff line number Diff line change
Expand Up @@ -56,17 +56,11 @@ public function __construct(
/**
* Returns the public and protected property values of an Active Record object.
*
* This method is provided because a direct call of {@see get_object_vars()} within the {@see AbstractActiveRecord}
* class will return also private property values of {@see AbstractActiveRecord} class.
*
* @param ActiveRecordInterface $object
*
* @return array
* @link https://www.php.net/manual/en/function.get-object-vars.php
*
* @psalm-return array<string, mixed>
*/
abstract protected function getObjectVars(ActiveRecordInterface $object): array;
abstract protected function getAttributesInternal(): array;

/**
* Inserts Active Record values into DB without considering transaction.
Expand Down Expand Up @@ -112,18 +106,18 @@ public function equals(ActiveRecordInterface $record): bool

public function getAttribute(string $name): mixed
{
return $this->getObjectVars($this)[$name] ?? null;
return $this->getAttributesInternal()[$name] ?? null;
}

public function getAttributes(array $names = null, array $except = []): array
public function getAttributes(array|null $names = null, array $except = []): array
{
$names ??= $this->attributes();

if ($except !== []) {
if (!empty($except)) {
$names = array_diff($names, $except);
}

return array_intersect_key($this->getObjectVars($this), array_flip($names));
return array_intersect_key($this->getAttributesInternal(), array_flip($names));
}

public function getIsNewRecord(): bool
Expand Down Expand Up @@ -196,10 +190,8 @@ public function getOldPrimaryKey(bool $asArray = false): mixed
);
}

if (count($keys) === 1) {
$key = $this->oldAttributes[$keys[0]] ?? null;

return $asArray ? [$keys[0] => $key] : $key;
if ($asArray === false && count($keys) === 1) {
return $this->oldAttributes[$keys[0]] ?? null;
}

$values = [];
Expand All @@ -215,8 +207,8 @@ public function getPrimaryKey(bool $asArray = false): mixed
{
$keys = $this->primaryKey();

if (count($keys) === 1) {
return $asArray ? [$keys[0] => $this->getAttribute($keys[0])] : $this->getAttribute($keys[0]);
if ($asArray === false && count($keys) === 1) {
return $this->getAttribute($keys[0]);
}

$values = [];
Expand Down Expand Up @@ -345,11 +337,13 @@ public function instantiateQuery(string $arClass): ActiveQueryInterface
*/
public function isAttributeChanged(string $name, bool $identical = true): bool
{
if (!isset($this->oldAttributes[$name])) {
return array_key_exists($name, $this->getObjectVars($this));
$attributes = $this->getAttributesInternal();

if (empty($this->oldAttributes) || !array_key_exists($name, $this->oldAttributes)) {
return array_key_exists($name, $attributes);
}

return $this->getAttribute($name) !== $this->oldAttributes[$name];
return !array_key_exists($name, $attributes) || $attributes[$name] !== $this->oldAttributes[$name];
}

public function isPrimaryKey(array $keys): bool
Expand Down Expand Up @@ -537,6 +531,10 @@ public function optimisticLock(): string|null
*/
public function populateRecord(array|object $row): void
{
if ($row instanceof ActiveRecordInterface) {
$row = $row->getAttributes();
}

foreach ($row as $name => $value) {
$this->populateAttribute($name, $value);
$this->oldAttributes[$name] = $value;
Expand Down Expand Up @@ -674,7 +672,7 @@ public function setAttributes(array $values): void
*/
public function setIsNewRecord(bool $value): void
{
$this->oldAttributes = $value ? null : $this->getObjectVars($this);
$this->oldAttributes = $value ? null : $this->getAttributesInternal();
}

/**
Expand Down
77 changes: 41 additions & 36 deletions src/ActiveQuery.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,12 @@
use Yiisoft\Definitions\Exception\NotInstantiableException;
use Yiisoft\Factory\NotFoundException;

use function array_column;
use function array_combine;
use function array_flip;
use function array_intersect_key;
use function array_key_first;
use function array_map;
use function array_merge;
use function array_values;
use function count;
Expand Down Expand Up @@ -269,7 +275,7 @@ public function populate(array $rows, Closure|string|null $indexBy = null): arra
$this->addInverseRelations($models);
}

return ArArrayHelper::populate($models, $indexBy);
return ArArrayHelper::index($models, $indexBy);
}

/**
Expand All @@ -289,53 +295,52 @@ public function populate(array $rows, Closure|string|null $indexBy = null): arra
*/
private function removeDuplicatedModels(array $models): array
{
$hash = [];
$model = reset($models);

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

if (count($pks) > 1) {
// Composite primary key.
foreach ($models as $i => $model) {
$key = [];
foreach ($pks as $pk) {
if (!isset($model[$pk])) {
// Don't continue if the primary key isn't part of the result set.
break 2;
}
$key[] = $model[$pk];
}

$key = serialize($key);

if (isset($hash[$key])) {
unset($models[$i]);
} else {
$hash[$key] = true;
}
if (empty($pks)) {
throw new InvalidConfigException("Primary key of '$this->arClass' can not be empty.");
}
} elseif (empty($pks)) {
throw new InvalidConfigException("Primary key of '$this->arClass' can not be empty.");
} else {
// Single column primary key.
$pk = reset($pks);

foreach ($models as $i => $model) {
foreach ($pks as $pk) {
if (!isset($model[$pk])) {
// Don't continue if the primary key isn't part of the result set.
break;
return $models;
}
}

$key = $model[$pk];
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)),
$models
);
}
} else {
$pks = $model->getPrimaryKey(true);

if (isset($hash[$key])) {
unset($models[$i]);
} else {
$hash[$key] = true;
if (empty($pks)) {
throw new InvalidConfigException("Primary key of '$this->arClass' can not be empty.");
}

foreach ($pks as $pk) {
if ($pk === null) {
return $models;
}
}

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

return array_values($models);
return array_values(array_combine($hash, $models));
}

/**
Expand Down
2 changes: 1 addition & 1 deletion src/ActiveRecordInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,7 @@ public function getAttribute(string $name): mixed;
*
* @return array Attribute values (name => value).
*/
public function getAttributes(array $names = null, array $except = []): array;
public function getAttributes(array|null $names = null, array $except = []): array;

/**
* Returns a value indicating whether the current record is new (not saved in the database).
Expand Down
Loading

0 comments on commit e23cab2

Please sign in to comment.