Skip to content

Commit 3bed01c

Browse files
niqingyangTigrov
andauthored
implement the interface ArrayableInterface for BaseActiveRecord (#273)
Co-authored-by: Sergei Tigrov <rrr-r@ya.ru>
1 parent 41c6691 commit 3bed01c

6 files changed

Lines changed: 121 additions & 35 deletions

File tree

composer.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
"require": {
2222
"php": "^8.0",
2323
"ext-json": "*",
24+
"yiisoft/arrays": "^3.0",
2425
"yiisoft/db": "^1.1",
2526
"yiisoft/factory": "^1.0"
2627
},

src/ActiveRecordInterface.php

Lines changed: 0 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44

55
namespace Yiisoft\ActiveRecord;
66

7-
use Closure;
87
use Throwable;
98
use Yiisoft\Db\Exception\Exception;
109
use Yiisoft\Db\Exception\InvalidArgumentException;
@@ -86,14 +85,6 @@ public function deleteAll(array $condition = []): int;
8685
*/
8786
public function equals(self $record): bool;
8887

89-
/**
90-
* @return array The default implementation returns the names of the columns whose values have been populated into
91-
* this record.
92-
*
93-
* @psalm-return array<string, string|Closure>
94-
*/
95-
public function fields(): array;
96-
9788
/**
9889
* Filters array condition before it's assigned to a Query filter.
9990
*
@@ -499,9 +490,4 @@ public function getOldAttributes(): array;
499490
* @throws InvalidConfigException
500491
*/
501492
public function populateRecord(array|object $row): void;
502-
503-
/**
504-
* Serializes the active record into its array implementation with attribute name as a key, and it values as value.
505-
*/
506-
public function toArray(): array;
507493
}

src/BaseActiveRecord.php

Lines changed: 5 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@
99
use IteratorAggregate;
1010
use ReflectionException;
1111
use Throwable;
12+
use Yiisoft\Arrays\ArrayableInterface;
13+
use Yiisoft\Arrays\ArrayableTrait;
1214
use Yiisoft\Db\Connection\ConnectionInterface;
1315
use Yiisoft\Db\Exception\Exception;
1416
use Yiisoft\Db\Exception\InvalidArgumentException;
@@ -40,8 +42,9 @@
4042
* @template-implements ArrayAccess<int, mixed>
4143
* @template-implements IteratorAggregate<int>
4244
*/
43-
abstract class BaseActiveRecord implements ActiveRecordInterface, IteratorAggregate, ArrayAccess
45+
abstract class BaseActiveRecord implements ActiveRecordInterface, IteratorAggregate, ArrayAccess, ArrayableInterface
4446
{
47+
use ArrayableTrait;
4548
use BaseActiveRecordTrait;
4649

4750
private array $attributes = [];
@@ -115,7 +118,7 @@ public function extraFields(): array
115118
}
116119

117120
/**
118-
* @psalm-suppress MixedReturnTypeCoercion
121+
* @psalm-return array<string, string|Closure>
119122
*/
120123
public function fields(): array
121124
{
@@ -1265,20 +1268,4 @@ public function getTableName(): string
12651268

12661269
return $this->tableName;
12671270
}
1268-
1269-
public function toArray(): array
1270-
{
1271-
$data = [];
1272-
1273-
foreach ($this->fields() as $key => $value) {
1274-
if ($value instanceof Closure) {
1275-
/** @var mixed */
1276-
$data[$key] = $value($this);
1277-
} else {
1278-
/** @var mixed */
1279-
$data[$value] = $this[$value];
1280-
}
1281-
}
1282-
return $data;
1283-
}
12841271
}

src/BaseActiveRecordTrait.php

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -250,11 +250,11 @@ public function offsetGet(mixed $offset): mixed
250250
* It is implicitly called when you use something like `$model[$offset] = $item;`.
251251
*
252252
* @param mixed $offset the offset to set element.
253-
* @param mixed $item the element value.
253+
* @param mixed $value the element value.
254254
*/
255-
public function offsetSet(mixed $offset, mixed $item): void
255+
public function offsetSet(mixed $offset, mixed $value): void
256256
{
257-
$this->$offset = $item;
257+
$this->$offset = $value;
258258
}
259259

260260
/**

tests/ActiveRecordTest.php

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
use Yiisoft\ActiveRecord\Tests\Stubs\ActiveRecord\Cat;
1111
use Yiisoft\ActiveRecord\Tests\Stubs\ActiveRecord\Customer;
1212
use Yiisoft\ActiveRecord\Tests\Stubs\ActiveRecord\CustomerClosureField;
13+
use Yiisoft\ActiveRecord\Tests\Stubs\ActiveRecord\CustomerForArrayable;
1314
use Yiisoft\ActiveRecord\Tests\Stubs\ActiveRecord\CustomerWithAlias;
1415
use Yiisoft\ActiveRecord\Tests\Stubs\ActiveRecord\Dog;
1516
use Yiisoft\ActiveRecord\Tests\Stubs\ActiveRecord\Item;
@@ -763,4 +764,58 @@ public function testToArrayWithClosure(): void
763764
$customer->toArray(),
764765
);
765766
}
767+
768+
public function testToArrayForArrayable(): void
769+
{
770+
$this->checkFixture($this->db, 'customer', true);
771+
772+
$customerQuery = new ActiveQuery(CustomerForArrayable::class, $this->db);
773+
774+
/** @var CustomerForArrayable $customer */
775+
$customer = $customerQuery->findOne(1);
776+
/** @var CustomerForArrayable $customer2 */
777+
$customer2 = $customerQuery->findOne(2);
778+
/** @var CustomerForArrayable $customer3 */
779+
$customer3 = $customerQuery->findOne(3);
780+
781+
$customer->setItem($customer2);
782+
$customer->setItems($customer3);
783+
784+
$this->assertSame(
785+
[
786+
'id' => 1,
787+
'email' => 'user1@example.com',
788+
'name' => 'user1',
789+
'address' => 'address1',
790+
'status' => 'active',
791+
'item' => [
792+
'id' => 2,
793+
'email' => 'user2@example.com',
794+
'name' => 'user2',
795+
'status' => 'active',
796+
],
797+
'items' => [
798+
[
799+
'id' => 3,
800+
'email' => 'user3@example.com',
801+
'name' => 'user3',
802+
'status' => 'inactive',
803+
],
804+
],
805+
],
806+
$customer->toArray([
807+
'id',
808+
'name',
809+
'email',
810+
'address',
811+
'status',
812+
'item.id',
813+
'item.name',
814+
'item.email',
815+
'items.0.id',
816+
'items.0.name',
817+
'items.0.email',
818+
]),
819+
);
820+
}
766821
}
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Yiisoft\ActiveRecord\Tests\Stubs\ActiveRecord;
6+
7+
use Yiisoft\ActiveRecord\ActiveRecord;
8+
9+
/**
10+
* Class CustomerClosureField.
11+
*
12+
* @property int $id
13+
* @property string $name
14+
* @property string $email
15+
* @property string $address
16+
* @property int $status
17+
*/
18+
class CustomerForArrayable extends ActiveRecord
19+
{
20+
public array $items = [];
21+
22+
public ?CustomerForArrayable $item = null;
23+
24+
public function getTableName(): string
25+
{
26+
return 'customer';
27+
}
28+
29+
public function fields(): array
30+
{
31+
$fields = parent::fields();
32+
33+
$fields['item'] = 'item';
34+
$fields['items'] = 'items';
35+
36+
return $fields;
37+
}
38+
39+
public function setItem(self $item)
40+
{
41+
$this->item = $item;
42+
}
43+
44+
public function setItems(self ...$items)
45+
{
46+
$this->items = $items;
47+
}
48+
49+
public function toArray(array $fields = [], array $expand = [], bool $recursive = true): array
50+
{
51+
$data = parent::toArray($fields, $expand, $recursive);
52+
53+
$data['status'] = $this->status == 1 ? 'active' : 'inactive';
54+
55+
return $data;
56+
}
57+
}

0 commit comments

Comments
 (0)