Skip to content

Commit

Permalink
implement the interface ArrayableInterface for BaseActiveRecord (#273)
Browse files Browse the repository at this point in the history
Co-authored-by: Sergei Tigrov <[email protected]>
  • Loading branch information
niqingyang and Tigrov authored Dec 16, 2023
1 parent 41c6691 commit 3bed01c
Show file tree
Hide file tree
Showing 6 changed files with 121 additions and 35 deletions.
1 change: 1 addition & 0 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
"require": {
"php": "^8.0",
"ext-json": "*",
"yiisoft/arrays": "^3.0",
"yiisoft/db": "^1.1",
"yiisoft/factory": "^1.0"
},
Expand Down
14 changes: 0 additions & 14 deletions src/ActiveRecordInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@

namespace Yiisoft\ActiveRecord;

use Closure;
use Throwable;
use Yiisoft\Db\Exception\Exception;
use Yiisoft\Db\Exception\InvalidArgumentException;
Expand Down Expand Up @@ -86,14 +85,6 @@ public function deleteAll(array $condition = []): int;
*/
public function equals(self $record): bool;

/**
* @return array The default implementation returns the names of the columns whose values have been populated into
* this record.
*
* @psalm-return array<string, string|Closure>
*/
public function fields(): array;

/**
* Filters array condition before it's assigned to a Query filter.
*
Expand Down Expand Up @@ -499,9 +490,4 @@ public function getOldAttributes(): array;
* @throws InvalidConfigException
*/
public function populateRecord(array|object $row): void;

/**
* Serializes the active record into its array implementation with attribute name as a key, and it values as value.
*/
public function toArray(): array;
}
23 changes: 5 additions & 18 deletions src/BaseActiveRecord.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
use IteratorAggregate;
use ReflectionException;
use Throwable;
use Yiisoft\Arrays\ArrayableInterface;
use Yiisoft\Arrays\ArrayableTrait;
use Yiisoft\Db\Connection\ConnectionInterface;
use Yiisoft\Db\Exception\Exception;
use Yiisoft\Db\Exception\InvalidArgumentException;
Expand Down Expand Up @@ -40,8 +42,9 @@
* @template-implements ArrayAccess<int, mixed>
* @template-implements IteratorAggregate<int>
*/
abstract class BaseActiveRecord implements ActiveRecordInterface, IteratorAggregate, ArrayAccess
abstract class BaseActiveRecord implements ActiveRecordInterface, IteratorAggregate, ArrayAccess, ArrayableInterface
{
use ArrayableTrait;
use BaseActiveRecordTrait;

private array $attributes = [];
Expand Down Expand Up @@ -115,7 +118,7 @@ public function extraFields(): array
}

/**
* @psalm-suppress MixedReturnTypeCoercion
* @psalm-return array<string, string|Closure>
*/
public function fields(): array
{
Expand Down Expand Up @@ -1265,20 +1268,4 @@ public function getTableName(): string

return $this->tableName;
}

public function toArray(): array
{
$data = [];

foreach ($this->fields() as $key => $value) {
if ($value instanceof Closure) {
/** @var mixed */
$data[$key] = $value($this);
} else {
/** @var mixed */
$data[$value] = $this[$value];
}
}
return $data;
}
}
6 changes: 3 additions & 3 deletions src/BaseActiveRecordTrait.php
Original file line number Diff line number Diff line change
Expand Up @@ -250,11 +250,11 @@ public function offsetGet(mixed $offset): mixed
* It is implicitly called when you use something like `$model[$offset] = $item;`.
*
* @param mixed $offset the offset to set element.
* @param mixed $item the element value.
* @param mixed $value the element value.
*/
public function offsetSet(mixed $offset, mixed $item): void
public function offsetSet(mixed $offset, mixed $value): void
{
$this->$offset = $item;
$this->$offset = $value;
}

/**
Expand Down
55 changes: 55 additions & 0 deletions tests/ActiveRecordTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
use Yiisoft\ActiveRecord\Tests\Stubs\ActiveRecord\Cat;
use Yiisoft\ActiveRecord\Tests\Stubs\ActiveRecord\Customer;
use Yiisoft\ActiveRecord\Tests\Stubs\ActiveRecord\CustomerClosureField;
use Yiisoft\ActiveRecord\Tests\Stubs\ActiveRecord\CustomerForArrayable;
use Yiisoft\ActiveRecord\Tests\Stubs\ActiveRecord\CustomerWithAlias;
use Yiisoft\ActiveRecord\Tests\Stubs\ActiveRecord\Dog;
use Yiisoft\ActiveRecord\Tests\Stubs\ActiveRecord\Item;
Expand Down Expand Up @@ -763,4 +764,58 @@ public function testToArrayWithClosure(): void
$customer->toArray(),
);
}

public function testToArrayForArrayable(): void
{
$this->checkFixture($this->db, 'customer', true);

$customerQuery = new ActiveQuery(CustomerForArrayable::class, $this->db);

/** @var CustomerForArrayable $customer */
$customer = $customerQuery->findOne(1);
/** @var CustomerForArrayable $customer2 */
$customer2 = $customerQuery->findOne(2);
/** @var CustomerForArrayable $customer3 */
$customer3 = $customerQuery->findOne(3);

$customer->setItem($customer2);
$customer->setItems($customer3);

$this->assertSame(
[
'id' => 1,
'email' => '[email protected]',
'name' => 'user1',
'address' => 'address1',
'status' => 'active',
'item' => [
'id' => 2,
'email' => '[email protected]',
'name' => 'user2',
'status' => 'active',
],
'items' => [
[
'id' => 3,
'email' => '[email protected]',
'name' => 'user3',
'status' => 'inactive',
],
],
],
$customer->toArray([
'id',
'name',
'email',
'address',
'status',
'item.id',
'item.name',
'item.email',
'items.0.id',
'items.0.name',
'items.0.email',
]),
);
}
}
57 changes: 57 additions & 0 deletions tests/Stubs/ActiveRecord/CustomerForArrayable.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
<?php

declare(strict_types=1);

namespace Yiisoft\ActiveRecord\Tests\Stubs\ActiveRecord;

use Yiisoft\ActiveRecord\ActiveRecord;

/**
* Class CustomerClosureField.
*
* @property int $id
* @property string $name
* @property string $email
* @property string $address
* @property int $status
*/
class CustomerForArrayable extends ActiveRecord
{
public array $items = [];

public ?CustomerForArrayable $item = null;

public function getTableName(): string
{
return 'customer';
}

public function fields(): array
{
$fields = parent::fields();

$fields['item'] = 'item';
$fields['items'] = 'items';

return $fields;
}

public function setItem(self $item)
{
$this->item = $item;
}

public function setItems(self ...$items)
{
$this->items = $items;
}

public function toArray(array $fields = [], array $expand = [], bool $recursive = true): array
{
$data = parent::toArray($fields, $expand, $recursive);

$data['status'] = $this->status == 1 ? 'active' : 'inactive';

return $data;
}
}

0 comments on commit 3bed01c

Please sign in to comment.