Skip to content

Commit 0c060da

Browse files
author
Piotr Krajewski
committed
Support MorphOne and MorphMany
1 parent f42cdf6 commit 0c060da

File tree

4 files changed

+72
-37
lines changed

4 files changed

+72
-37
lines changed

composer.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
"keywords": [
66
"Laravel", "Lumen", "Eloquent", "Nested Attributes"
77
],
8-
"version": "0.0.2",
8+
"version": "0.0.3",
99
"homepage": "https://github.com/mits87/eloquent-nested-attributes",
1010
"license": "MIT",
1111
"authors": [

phpunit.xml

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
<?xml version="1.0" encoding="UTF-8"?>
2-
32
<phpunit bootstrap="vendor/autoload.php"
43
backupGlobals="false"
54
backupStaticAttributes="false"
@@ -16,11 +15,10 @@
1615
<directory suffix=".php">./tests/</directory>
1716
</testsuite>
1817
</testsuites>
19-
18+
2019
<php>
2120
<env name="APP_ENV" value="testing"/>
2221
<env name="DB_CONNECTION" value="sqlite"/>
2322
<env name="DB_DATABASE" value=":memory:"/>
2423
</php>
25-
2624
</phpunit>

src/Traits/HasNestedAttributesTrait.php

Lines changed: 31 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,9 @@
55
use Exception;
66
use Illuminate\Support\Facades\DB;
77
use Illuminate\Database\Eloquent\Relations\HasOne;
8+
use Illuminate\Database\Eloquent\Relations\MorphOne;
89
use Illuminate\Database\Eloquent\Relations\HasMany;
10+
use Illuminate\Database\Eloquent\Relations\MorphMany;
911
use Illuminate\Database\Eloquent\Builder;
1012

1113
trait HasNestedAttributesTrait
@@ -65,32 +67,20 @@ public function save(array $options = [])
6567

6668
foreach ($this->getAcceptNestedAttributesFor() as $attribute => $stack) {
6769
$methodName = lcfirst(join(array_map('ucfirst', explode('_', $attribute))));
68-
70+
6971
if (!method_exists($this, $methodName)) {
7072
throw new Exception('The nested atribute relation "' . $methodName . '" does not exists.');
7173
}
72-
74+
7375
$relation = $this->$methodName();
7476

75-
if ($relation instanceof HasOne) {
76-
if ($this->exists && $model = $relation->first()) {
77-
if (!$model->update($stack)) {
78-
return false;
79-
}
80-
} else if (!$relation->create($stack)) {
77+
if ($relation instanceof HasOne || $relation instanceof MorphOne) {
78+
if (!$this->saveNestedAttributes($relation, $stack)) {
8179
return false;
8280
}
83-
} else if ($relation instanceof HasMany) {
84-
foreach ($stack as $attrs) {
85-
if (isset($attrs['id']) && $this->exists) {
86-
if (!$model = $relation->find($attrs['id'])) {
87-
throw new Exception('Not found.');
88-
}
89-
90-
if (!$model->update($attrs)) {
91-
return false;
92-
}
93-
} else if (!$relation->create($attrs)) {
81+
} else if ($relation instanceof HasMany || $relation instanceof MorphMany) {
82+
foreach ($stack as $params) {
83+
if (!$this->saveNestedAttributes($relation, $params)) {
9484
return false;
9585
}
9686
}
@@ -102,4 +92,26 @@ public function save(array $options = [])
10292
DB::commit();
10393
return true;
10494
}
95+
96+
/**
97+
* Save the nested relation attributes to the database.
98+
*
99+
* @param Illuminate\Database\Eloquent\Relations $relation
100+
* @param array $params
101+
* @return bool
102+
*/
103+
protected function saveNestedAttributes($relation, array $params)
104+
{
105+
if ($this->exists) {
106+
if (isset($params['id'])) {
107+
$model = $relation->findOrFail($params['id']);
108+
} else {
109+
$model = $relation->firstOrFail();
110+
}
111+
return $model->update($params);
112+
} else if ($relation->create($params)) {
113+
return true;
114+
}
115+
return false;
116+
}
105117
}

tests/HasNestedAttributesTraitTest.php

Lines changed: 39 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -23,35 +23,60 @@ public function tearDown()
2323
Mockery::close();
2424
}
2525

26+
/**
27+
* The fillable test.
28+
*/
2629
public function testFillable()
2730
{
28-
$params = [
29-
'title' => 'foo',
30-
31+
$payload = [
32+
'title' => 'foo',
3133
'not_exists' => [],
32-
33-
'model_bar' => [
34-
'text' => 'bar'
35-
],
36-
34+
'model_bar' => ['text' => 'bar'],
3735
'model_foos' => [
38-
['text' => 'foo']
36+
['text' => 'foo1'],
37+
['text' => 'foo2'],
3938
]
4039
];
4140

42-
$this->model->fill($params);
41+
$this->model->fill($payload);
4342

4443
$this->assertEquals(['title' => 'foo'], $this->model->getAttributes());
45-
4644
$this->assertEquals([
4745
'model_bar' => ['text' => 'bar'],
48-
'model_foos' => [['text' => 'foo']]
46+
'model_foos' => [
47+
['text' => 'foo1'],
48+
['text' => 'foo2']
49+
]
4950
], $this->model->getAcceptNestedAttributesFor());
5051
}
5152
}
5253

5354
class ModelEloquentStub extends Model {
54-
protected $table = 'stub';
55+
protected $table = 'stubs';
5556
protected $fillable = ['title'];
56-
protected $nested = ['model_bar', 'model_foos' ];
57+
protected $nested = ['model_bar', 'model_foos' ];
58+
59+
public function modelBar() {
60+
return $this->hasOne(ModelBarStub::class);
61+
}
62+
63+
public function modelFoos() {
64+
return $this->hasOne(ModelFooStub::class);
65+
}
66+
}
67+
68+
class ModelBarStub extends Model {
69+
protected $fillable = ['text'];
70+
71+
public function parent() {
72+
return $this->belongsTo(ModelEloquentStub::class);
73+
}
74+
}
75+
76+
class ModelFooStub extends Model {
77+
protected $fillable = ['text'];
78+
79+
public function parent() {
80+
return $this->belongsTo(ModelEloquentStub::class);
81+
}
5782
}

0 commit comments

Comments
 (0)