Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Create MagicPropertiesTrait #318

Merged
merged 6 commits into from
May 20, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 12 additions & 5 deletions src/ActiveQueryInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@
namespace Yiisoft\ActiveRecord;

use Closure;
use ReflectionException;
use Throwable;
use Yiisoft\Db\Exception\Exception;
use Yiisoft\Db\Exception\InvalidArgumentException;
use Yiisoft\Db\Exception\InvalidConfigException;
use Yiisoft\Db\Query\QueryInterface;
Expand Down Expand Up @@ -334,16 +337,19 @@ public function sql(string|null $value): self;
public function populate(array $rows, Closure|string|null $indexBy = null): array;

/**
* Finds the related records for the specified primary record.
* Returns related record(s).
*
* This method is invoked when a relation of an ActiveRecord is being accessed in a lazy fashion.
*
* @param string $name The relation name.
* @param ActiveRecordInterface $model The primary model.
* @throws Exception
* @throws InvalidArgumentException
* @throws InvalidConfigException
* @throws ReflectionException
* @throws Throwable if the relation is invalid.
*
* @return mixed The related record(s).
* @return ActiveRecordInterface|array|null the related record(s).
*/
public function findFor(string $name, ActiveRecordInterface $model): mixed;
public function relatedRecords(): ActiveRecordInterface|array|null;

/**
* Returns a single active record instance by a primary key or an array of column values.
Expand Down Expand Up @@ -423,6 +429,7 @@ public function findFor(string $name, ActiveRecordInterface $model): mixed;
* ```
*
* @throws InvalidConfigException
*
* @return ActiveRecordInterface|array|null Instance matching the condition, or `null` if nothing matches.
*/
public function findOne(mixed $condition): array|ActiveRecordInterface|null;
Expand Down
2 changes: 2 additions & 0 deletions src/ActiveRecord.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
use Yiisoft\ActiveRecord\Trait\ArrayableTrait;
use Yiisoft\ActiveRecord\Trait\ArrayAccessTrait;
use Yiisoft\ActiveRecord\Trait\ArrayIteratorTrait;
use Yiisoft\ActiveRecord\Trait\MagicPropertiesTrait;
use Yiisoft\ActiveRecord\Trait\MagicRelationsTrait;
use Yiisoft\Arrays\ArrayableInterface;
use Yiisoft\Db\Exception\Exception;
Expand Down Expand Up @@ -96,6 +97,7 @@ class ActiveRecord extends BaseActiveRecord implements ArrayableInterface, Array
use ArrayableTrait;
use ArrayAccessTrait;
use ArrayIteratorTrait;
use MagicPropertiesTrait;
use MagicRelationsTrait;

/**
Expand Down
18 changes: 2 additions & 16 deletions src/ActiveRelationTrait.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
namespace Yiisoft\ActiveRecord;

use ReflectionException;
use ReflectionMethod;
use Stringable;
use Throwable;
use Yiisoft\Db\Exception\Exception;
Expand All @@ -25,8 +24,6 @@
use function is_scalar;
use function is_string;
use function key;
use function lcfirst;
use function method_exists;
use function reset;
use function serialize;

Expand Down Expand Up @@ -180,21 +177,10 @@ public function inverseOf(string $relationName): static
* @throws ReflectionException
* @throws Throwable if the relation is invalid.
*
* @return array|object|null the related record(s).
* @return ActiveRecordInterface|array|null the related record(s).
*/
public function findFor(string $name, ActiveRecordInterface $model): array|null|object
public function relatedRecords(): ActiveRecordInterface|array|null
{
if (method_exists($model, 'get' . $name)) {
$method = new ReflectionMethod($model, 'get' . $name);
$realName = lcfirst(substr($method->getName(), 3));
if ($realName !== $name) {
throw new InvalidArgumentException(
'Relation names are case sensitive. ' . $model::class
. " has a relation named \"$realName\" instead of \"$name\"."
);
}
}

return $this->multiple ? $this->all() : $this->onePopulate();
}

Expand Down
80 changes: 47 additions & 33 deletions src/BaseActiveRecord.php
Original file line number Diff line number Diff line change
Expand Up @@ -42,9 +42,6 @@
*/
abstract class BaseActiveRecord implements ActiveRecordInterface
{
use BaseActiveRecordTrait;

private array $attributes = [];
private array|null $oldAttributes = null;
private array $related = [];
/** @psalm-var string[][] */
Expand Down Expand Up @@ -81,13 +78,13 @@

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

Check warning on line 81 in src/BaseActiveRecord.php

View check run for this annotation

Codecov / codecov/patch

src/BaseActiveRecord.php#L81

Added line #L81 was not covered by tests
}

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

Check warning on line 87 in src/BaseActiveRecord.php

View check run for this annotation

Codecov / codecov/patch

src/BaseActiveRecord.php#L87

Added line #L87 was not covered by tests

if ($except !== []) {
$names = array_diff($names, $except);
Expand Down Expand Up @@ -210,9 +207,9 @@
return $this->related;
}

public function hasAttribute($name): bool
public function hasAttribute(string $name): bool

Check warning on line 210 in src/BaseActiveRecord.php

View check run for this annotation

Codecov / codecov/patch

src/BaseActiveRecord.php#L210

Added line #L210 was not covered by tests
{
return isset($this->attributes[$name]) || in_array($name, $this->attributes(), true);
return in_array($name, $this->attributes(), true);

Check warning on line 212 in src/BaseActiveRecord.php

View check run for this annotation

Codecov / codecov/patch

src/BaseActiveRecord.php#L212

Added line #L212 was not covered by tests
}

/**
Expand Down Expand Up @@ -310,15 +307,11 @@
*/
public function isAttributeChanged(string $name, bool $identical = true): bool
{
if (isset($this->attributes[$name], $this->oldAttributes[$name])) {
if ($identical) {
return $this->attributes[$name] !== $this->oldAttributes[$name];
}

return $this->attributes[$name] !== $this->oldAttributes[$name];
if (isset($this->oldAttributes[$name])) {
return $this->$name !== $this->oldAttributes[$name];

Check warning on line 311 in src/BaseActiveRecord.php

View check run for this annotation

Codecov / codecov/patch

src/BaseActiveRecord.php#L310-L311

Added lines #L310 - L311 were not covered by tests
}

return isset($this->attributes[$name]) || isset($this->oldAttributes[$name]);
return false;

Check warning on line 314 in src/BaseActiveRecord.php

View check run for this annotation

Codecov / codecov/patch

src/BaseActiveRecord.php#L314

Added line #L314 was not covered by tests
}

public function isPrimaryKey(array $keys): bool
Expand Down Expand Up @@ -510,12 +503,7 @@
public function populateRecord(array|object $row): void
{
foreach ($row as $name => $value) {
if (property_exists($this, $name)) {
$this->$name = $value;
} else {
$this->attributes[$name] = $value;
}

$this->populateAttribute($name, $value);
$this->oldAttributes[$name] = $value;
}

Expand Down Expand Up @@ -545,6 +533,25 @@
return $this->refreshInternal($record);
}

public function resetRelation(string $name): void
{
foreach ($this->relationsDependencies as &$relationNames) {
unset($relationNames[$name]);
}

unset($this->related[$name]);
}

protected function retrieveRelation(string $name): ActiveRecordInterface|array|null
{
/** @var ActiveQueryInterface $query */
$query = $this->getRelation($name);

$this->setRelationDependencies($name, $query);

return $this->related[$name] = $query->relatedRecords();
}

/**
* Saves the current record.
*
Expand Down Expand Up @@ -582,17 +589,14 @@

public function setAttribute(string $name, mixed $value): void
{
if ($this->hasAttribute($name)) {
if (
!empty($this->relationsDependencies[$name])
&& (!array_key_exists($name, $this->attributes) || $this->attributes[$name] !== $value)
) {
$this->resetDependentRelations($name);
}
$this->attributes[$name] = $value;
} else {
throw new InvalidArgumentException(static::class . ' has no attribute named "' . $name . '".');
if (
isset($this->relationsDependencies[$name])
&& (!isset(get_object_vars($this)[$name]) || $this->$name !== $value)

Check warning on line 594 in src/BaseActiveRecord.php

View check run for this annotation

Codecov / codecov/patch

src/BaseActiveRecord.php#L593-L594

Added lines #L593 - L594 were not covered by tests
) {
$this->resetDependentRelations($name);

Check warning on line 596 in src/BaseActiveRecord.php

View check run for this annotation

Codecov / codecov/patch

src/BaseActiveRecord.php#L596

Added line #L596 was not covered by tests
}

$this->$name = $value;

Check warning on line 599 in src/BaseActiveRecord.php

View check run for this annotation

Codecov / codecov/patch

src/BaseActiveRecord.php#L599

Added line #L599 was not covered by tests
}

/**
Expand Down Expand Up @@ -621,7 +625,7 @@
*/
public function setIsNewRecord(bool $value): void
{
$this->oldAttributes = $value ? null : $this->attributes;
$this->oldAttributes = $value ? null : get_object_vars($this);

Check warning on line 628 in src/BaseActiveRecord.php

View check run for this annotation

Codecov / codecov/patch

src/BaseActiveRecord.php#L628

Added line #L628 was not covered by tests
}

/**
Expand Down Expand Up @@ -991,7 +995,7 @@
* @param ActiveQueryInterface $relation relation instance.
* @param string|null $viaRelationName intermediate relation.
*/
private function setRelationDependencies(
protected function setRelationDependencies(
string $name,
ActiveQueryInterface $relation,
string $viaRelationName = null
Expand Down Expand Up @@ -1173,12 +1177,17 @@
$foreignModel->save();
}

protected function hasDependentRelations(string $attribute): bool
{
return isset($this->relationsDependencies[$attribute]);
}

/**
* Resets dependent related models checking if their links contain specific attribute.
*
* @param string $attribute The changed attribute name.
*/
private function resetDependentRelations(string $attribute): void
protected function resetDependentRelations(string $attribute): void
{
foreach ($this->relationsDependencies[$attribute] as $relation) {
unset($this->related[$relation]);
Expand All @@ -1195,4 +1204,9 @@

return $this->tableName;
}

protected function populateAttribute(string $name, mixed $value): void

Check warning on line 1208 in src/BaseActiveRecord.php

View check run for this annotation

Codecov / codecov/patch

src/BaseActiveRecord.php#L1208

Added line #L1208 was not covered by tests
{
$this->$name = $value;

Check warning on line 1210 in src/BaseActiveRecord.php

View check run for this annotation

Codecov / codecov/patch

src/BaseActiveRecord.php#L1210

Added line #L1210 was not covered by tests
}
}
Loading
Loading