Skip to content

Commit

Permalink
Refactor ArrayAccessTrait (#333)
Browse files Browse the repository at this point in the history
  • Loading branch information
Tigrov authored May 21, 2024
1 parent 5c28c20 commit c3477c4
Showing 1 changed file with 82 additions and 6 deletions.
88 changes: 82 additions & 6 deletions src/Trait/ArrayAccessTrait.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,36 @@

namespace Yiisoft\ActiveRecord\Trait;

use InvalidArgumentException;
use Yiisoft\ActiveRecord\ActiveRecordInterface;

use function get_object_vars;
use function is_array;
use function property_exists;

/**
* Trait to implement {@see ArrayAccess} interface for ActiveRecord.
*
* @method mixed getAttribute(string $name)
* @see ActiveRecordInterface::getAttribute()
*
* @method bool hasAttribute(string $name)
* @see ActiveRecordInterface::hasAttribute()
*
* @method void setAttribute(string $name, mixed $value)
* @see ActiveRecordInterface::getAttribute()
*
* @method ActiveRecordInterface|array|null relation(string $name)
* @see ActiveRecordInterface::relation()
*
* @method bool isRelationPopulated(string $name)
* @see ActiveRecordInterface::isRelationPopulated()
*
* @method void populateRelation(string $name, ActiveRecordInterface|array|null $record)
* @see ActiveRecordInterface::populateRelation()
*
* @method void resetRelation(string $name)
* @see ActiveRecordInterface::resetRelation()
*/
trait ArrayAccessTrait
{
Expand All @@ -18,16 +44,41 @@ trait ArrayAccessTrait
*
* It is implicitly called when you use something like `isset($model[$offset])`.
*
* @param string $offset the offset to check on.
*
* @return bool whether or not an offset exists.
*/
public function offsetExists(mixed $offset): bool
{
return isset($this->$offset);
if ($this->hasAttribute($offset)) {
return $this->getAttribute($offset) !== null;
}

if (property_exists($this, $offset)) {
return isset(get_object_vars($this)[$offset]);
}

if ($this->isRelationPopulated($offset)) {
return $this->relation($offset) !== null;
}

return false;
}

/**
* @param string $offset the offset to retrieve element.
*/
public function offsetGet(mixed $offset): mixed
{
return $this->$offset;
if ($this->hasAttribute($offset)) {
return $this->getAttribute($offset);
}

if (property_exists($this, $offset)) {
return get_object_vars($this)[$offset] ?? null;
}

return $this->relation($offset);
}

/**
Expand All @@ -36,10 +87,27 @@ public function offsetGet(mixed $offset): mixed
* This method is required by the SPL interface {@see ArrayAccess}.
*
* It is implicitly called when you use something like `$model[$offset] = $item;`.
*
* @param string $offset the offset to set element.
*/
public function offsetSet(mixed $offset, mixed $value): void
{
$this->$offset = $value;
if ($this->hasAttribute($offset)) {
$this->setAttribute($offset, $value);
return;
}

if (property_exists($this, $offset)) {
$this->$offset = $value;
return;
}

if ($value instanceof ActiveRecordInterface || is_array($value) || $value === null) {
$this->populateRelation($offset, $value);
return;
}

throw new InvalidArgumentException('Setting unknown property: ' . static::class . '::' . $offset);
}

/**
Expand All @@ -48,13 +116,21 @@ public function offsetSet(mixed $offset, mixed $value): void
* This method is required by the SPL interface {@see ArrayAccess}.
*
* It is implicitly called when you use something like `unset($model[$offset])`.
*
* @param string $offset the offset to unset element
*/
public function offsetUnset(mixed $offset): void
{
if (is_string($offset) && property_exists($this, $offset)) {
if ($this->hasAttribute($offset)) {
$this->setAttribute($offset, null);
return;
}

if (property_exists($this, $offset)) {
$this->$offset = null;
} else {
unset($this->$offset);
return;
}

$this->resetRelation($offset);
}
}

0 comments on commit c3477c4

Please sign in to comment.