Skip to content

Commit 5a61a0f

Browse files
committed
refactor: support string-class model in hasOne and hasMany
1 parent be75022 commit 5a61a0f

File tree

4 files changed

+219
-24
lines changed

4 files changed

+219
-24
lines changed

src/System/Database/MyModel/Model.php

+53-15
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44

55
namespace System\Database\MyModel;
66

7-
use System\Collection\CollectionImmutable;
87
use System\Database\MyPDO;
98
use System\Database\MyQuery;
109
use System\Database\MyQuery\Bind;
@@ -112,6 +111,17 @@ public function setUp(
112111
*/
113112
public function __get(string $name)
114113
{
114+
if (method_exists($this, $name)) {
115+
$highorder = $this->{$name}();
116+
if (is_a($highorder, Model::class)) {
117+
return $highorder->first();
118+
}
119+
120+
if (is_a($highorder, ModelCollection::class)) {
121+
return $highorder->toArrayArray();
122+
}
123+
}
124+
115125
return $this->getter($name);
116126
}
117127

@@ -330,31 +340,59 @@ public function isExist(): bool
330340
}
331341

332342
/**
333-
* @return CollectionImmutable<string, mixed>
343+
* Get get model relation.
344+
*
345+
* @param class-string|string $model
346+
*
347+
* @return Model
334348
*/
335-
public function hasOne(string $table, string $ref = 'id')
349+
public function hasOne($model, ?string $ref = null)
336350
{
337-
$ref = MyQuery::from($this->table_name, $this->pdo)
338-
->select([$table . '.*'])
339-
->join(InnerJoin::ref($table, $this->primery_key, $ref))
351+
if (class_exists($model)) {
352+
$model = new $model($this->pdo, []);
353+
$table_name = $model->table_name;
354+
$join_ref = $ref ?? $model->primery_key;
355+
} else {
356+
$table_name = $model;
357+
$join_ref = $ref ?? $this->primery_key;
358+
$model = new Model($this->pdo, []);
359+
}
360+
$result = MyQuery::from($this->table_name, $this->pdo)
361+
->select([$table_name . '.*'])
362+
->join(InnerJoin::ref($table_name, $this->primery_key, $join_ref))
340363
->whereRef($this->where)
341364
->single();
365+
$model->columns = $model->fresh = [$result];
342366

343-
return new CollectionImmutable($ref);
367+
return $model;
344368
}
345369

346370
/**
347-
* @return CollectionImmutable<string|int, mixed>
371+
* Get get model relation.
372+
*
373+
* @param class-string|string $model
374+
*
375+
* @return ModelCollection<array-key, Model>
348376
*/
349-
public function hasMany(string $table, string $ref = 'id')
377+
public function hasMany($model, ?string $ref = null)
350378
{
351-
$ref = MyQuery::from($this->table_name, $this->pdo)
352-
->select([$table . '.*'])
353-
->join(InnerJoin::ref($table, $this->primery_key, $ref))
354-
->whereRef($this->where)
355-
->get();
379+
if (class_exists($model)) {
380+
$model = new $model($this->pdo, []);
381+
$table_name = $model->table_name;
382+
$join_ref = $ref ?? $model->primery_key;
383+
} else {
384+
$table_name = $model;
385+
$join_ref = $ref ?? $this->primery_key;
386+
$model = new Model($this->pdo, []);
387+
}
388+
$result = MyQuery::from($this->table_name, $this->pdo)
389+
->select([$table_name . '.*'])
390+
->join(InnerJoin::ref($table_name, $this->primery_key, $join_ref))
391+
->whereRef($this->where)
392+
->get();
393+
$model->columns = $model->fresh = $result->toArray();
356394

357-
return new CollectionImmutable($ref->immutable());
395+
return $model->get();
358396
}
359397

360398
/**

src/System/Database/MyModel/ModelCollection.php

+26-1
Original file line numberDiff line numberDiff line change
@@ -43,18 +43,24 @@ public function getPrimeryKey()
4343
return $primeryKeys;
4444
}
4545

46+
/**
47+
* Check every Model has clean column.
48+
*/
4649
public function isClean(?string $column = null): bool
4750
{
4851
return $this->every(fn ($model) => $model->isClean($column));
4952
}
5053

54+
/**
55+
* Check every Model has dirty column.
56+
*/
5157
public function isDirty(?string $column = null): bool
5258
{
5359
return !$this->isClean($column);
5460
}
5561

5662
/**
57-
* Global update (base on primerykey).
63+
* Update using query using model primery key.
5864
*
5965
* @param array<array-key, mixed> $values
6066
*/
@@ -70,6 +76,9 @@ public function update(array $values): bool
7076
return $update->execute();
7177
}
7278

79+
/**
80+
* Delete using query using model primery key.
81+
*/
7382
public function delete(): bool
7483
{
7584
$table_name = (fn () => $this->{'table_name'})->call($this->model);
@@ -81,4 +90,20 @@ public function delete(): bool
8190

8291
return $delete->execute();
8392
}
93+
94+
/**
95+
* Convert array of model to pure array;.
96+
*
97+
* @return array<array-key, mixed>
98+
*/
99+
public function toArrayArray(): array
100+
{
101+
/** @var array<array-key, mixed> */
102+
$arr = [];
103+
foreach ($this->collection as $model) {
104+
$arr = array_merge($arr, $model->toArray());
105+
}
106+
107+
return $arr;
108+
}
84109
}

tests/DataBase/Model/BaseModelTest.php

+117-4
Original file line numberDiff line numberDiff line change
@@ -166,9 +166,50 @@ public function itCanGetHasOne()
166166
$this->createProfileSchema();
167167
$this->createProfiles([$profile]);
168168

169+
$user = $this->user();
170+
$result = $user->hasOne(Profile::class, 'user');
171+
$this->assertEquals($profile, $result->first());
172+
}
173+
174+
/**
175+
* @test
176+
*
177+
* @group database
178+
*/
179+
public function itCanGetHasOneUsingMagicGetter()
180+
{
181+
// profile
182+
$profile = [
183+
'user' => 'taylor',
184+
'name' => 'taylor otwell',
185+
'gender' => 'male',
186+
];
187+
$this->createProfileSchema();
188+
$this->createProfiles([$profile]);
189+
190+
$user = $this->user();
191+
$this->assertEquals($profile, $user->profile);
192+
}
193+
194+
/**
195+
* @test
196+
*
197+
* @group database
198+
*/
199+
public function itCanGetHasOneWithTableName()
200+
{
201+
// profile
202+
$profile = [
203+
'user' => 'taylor',
204+
'name' => 'taylor otwell',
205+
'gender' => 'male',
206+
];
207+
$this->createProfileSchema();
208+
$this->createProfiles([$profile]);
209+
169210
$user = $this->user();
170211
$result = $user->hasOne('profiles', 'user');
171-
$this->assertEquals($profile, $result->toArray());
212+
$this->assertEquals($profile, $result->first());
172213
}
173214

174215
/**
@@ -196,16 +237,73 @@ public function itCanGetHasMany()
196237
$this->createOrders($order);
197238

198239
$user = $this->user();
199-
$result = $user->hasMany('orders', 'user');
200-
$this->assertEquals($order, $result->toArray());
240+
$result = $user->hasMany(Order::class, 'user');
241+
$this->assertEquals($order, $result->toArrayArray());
201242
}
202243

203244
/**
204245
* @test
205246
*
206247
* @group database
207248
*/
208-
public function itCanCheckisClean()
249+
public function itCanGetHasManyWithMagicGetter()
250+
{
251+
// order
252+
$order = [
253+
[
254+
'id' => '1',
255+
'user' => 'taylor',
256+
'name' => 'order 1',
257+
'type' => 'gadget',
258+
], [
259+
'id' => '3',
260+
'user' => 'taylor',
261+
'name' => 'order 2',
262+
'type' => 'gadget',
263+
],
264+
];
265+
$this->createOrderSchema();
266+
$this->createOrders($order);
267+
268+
$user = $this->user();
269+
$this->assertEquals($order, $user->orders);
270+
}
271+
272+
/**
273+
* @test
274+
*
275+
* @group database
276+
*/
277+
public function itCanGetHasManyWithTableName()
278+
{
279+
// order
280+
$order = [
281+
[
282+
'id' => '1',
283+
'user' => 'taylor',
284+
'name' => 'order 1',
285+
'type' => 'gadget',
286+
], [
287+
'id' => '3',
288+
'user' => 'taylor',
289+
'name' => 'order 2',
290+
'type' => 'gadget',
291+
],
292+
];
293+
$this->createOrderSchema();
294+
$this->createOrders($order);
295+
296+
$user = $this->user();
297+
$result = $user->hasMany(Order::class, 'user');
298+
$this->assertEquals($order, $result->toArrayArray());
299+
}
300+
301+
/**
302+
* @test
303+
*
304+
* @group database
305+
*/
306+
public function itCanCheckisCleanWith()
209307
{
210308
$user = $this->user();
211309
$this->assertTrue($user->isClean(), 'Check all column');
@@ -540,4 +638,19 @@ class User extends Model
540638
protected string $primery_key = 'user';
541639
/** @var string[] Hide from shoing column */
542640
protected $stash = ['password'];
641+
642+
public function profile()
643+
{
644+
return $this->hasOne(Profile::class, 'user');
645+
}
646+
647+
public function orders()
648+
{
649+
return $this->hasMany(Order::class, 'user');
650+
}
651+
}
652+
653+
class Order extends Model
654+
{
655+
protected string $table_name = 'orders';
543656
}

tests/DataBase/Model/BaseMultyModelTest.php

+23-4
Original file line numberDiff line numberDiff line change
@@ -161,8 +161,27 @@ public function itCanGetHasOne()
161161
$this->createProfiles([$profile]);
162162

163163
$user = $this->users();
164-
$result = $user->hasOne('profiles', 'user');
165-
$this->assertEquals($profile, $result->toArray());
164+
$this->assertEquals($profile, $user->profile()->first());
165+
}
166+
167+
/**
168+
* @test
169+
*
170+
* @group database
171+
*/
172+
public function itCanGetHasOneUsingMagicGetter()
173+
{
174+
// profile
175+
$profile = [
176+
'user' => 'taylor',
177+
'name' => 'taylor otwell',
178+
'gender' => 'male',
179+
];
180+
$this->createProfileSchema();
181+
$this->createProfiles([$profile]);
182+
183+
$user = $this->users();
184+
$this->assertEquals($profile, $user->profile);
166185
}
167186

168187
/**
@@ -190,8 +209,8 @@ public function itCanGetHasMany()
190209
$this->createOrders($order);
191210

192211
$user = $this->users();
193-
$result = $user->hasMany('orders', 'user');
194-
$this->assertEquals($order, $result->toArray());
212+
$result = $user->hasMany(Order::class, 'user');
213+
$this->assertEquals($order, $result->toArrayArray());
195214
}
196215

197216
/**

0 commit comments

Comments
 (0)