Passed
Push — master ( 67253f...d311a4 )
by Dominic
03:15
created

ModelTestor::getBelongsToRelationName()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 1
c 0
b 0
f 0
nc 1
nop 1
dl 0
loc 3
rs 10
1
<?php
2
3
namespace Thomasdominic\EloquentModelTestor;
4
5
use Illuminate\Database\Eloquent\Collection;
6
use Illuminate\Database\Eloquent\Model;
7
use Illuminate\Support\Facades\Schema;
8
use Illuminate\Support\Str;
9
use PHPUnit\Framework\TestCase;
10
11
class ModelTestor extends TestCase
12
{
13
    private ?string $tested;
14
15
    private ?string $table;
16
17
    public function __construct(?string $tested, ?string $table = null)
18
    {
19
        parent::__construct();
20
        $this->tested = $tested;
21
        $this->table = $table;
22
    }
23
24
    public function getModel(): ?string
25
    {
26
        throw_if(is_null($this->tested) || ! $this->isModelClass($this->tested),
27
            new \Exception('You have to use a Eloquent Model'));
28
29
        return $this->tested;
30
    }
31
32
    public function getTable(): string
33
    {
34
        throw_if(! $this->isExistingTable($this->table),
35
            new \Exception('You have to use an existing table'));
36
37
        return $this->getModelTable();
38
    }
39
40
    public function getModelTable(): string
41
    {
42
        if (! empty($this->table)) {
43
            return $this->table;
44
        }
45
46
        $modelClass = $this->getModel();
47
48
        return (new $modelClass)->getTable();
49
    }
50
51
    public function isModelClass(?string $modelClass = null): bool
52
    {
53
        if (! is_null($modelClass)) {
54
            return (new $modelClass) instanceof Model;
55
        } else {
56
            return (new $this->tested) instanceof Model;
57
        }
58
    }
59
60
    public function isExistingTable(?string $tableName = null): bool
61
    {
62
        if (! is_null($tableName)) {
63
            return Schema::hasTable($tableName);
64
        } else {
65
            return Schema::hasTable($this->getModelTable());
66
        }
67
    }
68
69
    public function assertHasColumns(array $columns): self
70
    {
71
        collect($columns)->each(function ($column) {
72
            $this->assertTrue(in_array($column, Schema::getColumnListing($this->getTable())));
73
        });
74
75
        return $this;
76
    }
77
78
    public function assertCanFillables(array $columns = []): self
79
    {
80
        $modelClass = $this->getModel();
81
        $this->assertEquals([], collect($columns)->diff((new $modelClass)->getFillable())->toArray());
82
83
        return $this;
84
    }
85
86
    public function assertHasHasManyRelation(string $related, ?string $relation = null): self
87
    {
88
        $relation = $relation ?: $this->getHasManyRelationName($related);
89
90
        $modelInstance = factory($this->getModel())->create();
91
        $relatedInstance = $modelInstance->{$relation}()->save(factory($related)->make());
92
        $modelInstance->refresh();
93
94
        $this->assertTrue($modelInstance->{$relation}->contains($relatedInstance));
95
        $this->assertEquals(1, $modelInstance->{$relation}->count());
96
        $this->assertInstanceOf(Collection::class, $modelInstance->{$relation});
97
        $this->assertInstanceOf($related, $modelInstance->{$relation}->first());
98
99
        return $this;
100
    }
101
102
    public function assertHasBelongsToRelation(string $related, ?string $relation = null, ?string $foreignKey = null): self
103
    {
104
        $relation = $relation ?: $this->getBelongsToRelationName($related);
105
106
        $relatedInstance = factory($related)->create();
107
        $foreignKey = $foreignKey ?: $relatedInstance->getForeignKey();
108
109
        $modelInstance = factory($this->getModel())->create([$foreignKey => $relatedInstance->id]);
110
        $relatedInstance2 = factory($related)->create();
111
        $modelInstance2 = factory($this->getModel())->make();
112
        $modelInstance2->{$relation}()->associate($relatedInstance2)->save();
113
114
        $this->assertEquals($modelInstance->{$relation}->id, $relatedInstance->id);
115
        $this->assertInstanceOf($related, $modelInstance->{$relation});
116
        $this->assertEquals($modelInstance2->{$foreignKey}, $relatedInstance2->id);
117
        $this->assertInstanceOf($related, $modelInstance2->{$relation});
118
119
        return $this;
120
    }
121
122
    public function assertHasManyToManyRelation(string $related, ?string $relation = null): self
123
    {
124
        $relation = $relation ?: $this->getManyToManyRelationName($related);
125
126
        $modelInstance = factory($this->getModel())->create();
127
        $relatedInstance = factory($related)->create();
128
        $modelInstance->{$relation}()->attach($relatedInstance);
129
130
        $this->assertTrue($modelInstance->{$relation}->contains($relatedInstance));
131
        $this->assertEquals($relatedInstance->id, $modelInstance->{$relation}->first()->id);
132
        $this->assertEquals(1, $modelInstance->{$relation}->count());
133
        $this->assertInstanceOf($related, $modelInstance->{$relation}->first());
134
135
        return $this;
136
    }
137
138
    public function assertHasHasManyMorphRelation(string $related, string $name): self
139
    {
140
        $instance = factory($this->getModel())->create();
141
        $instance->{$name}()->save(factory($related)->make());
142
        $instance->refresh();
143
144
        $this->assertInstanceOf($related, $instance->{$name}->first());
145
146
        return $this;
147
    }
148
149
    public function assertHasBelongsToMorphRelation(string $related, string $name, ?string $type = null, ?string $id = null): self
150
    {
151
        [$type, $id] = $this->getMorphs($name, $type, $id);
152
153
        $instance = factory($related)->create();
154
        $morph = factory($this->getModel())->create([
155
            $id   => $instance->id,
156
            $type => $related,
157
        ]);
158
        $morph->refresh();
159
160
        $this->assertInstanceOf($related, $morph->{$name});
161
162
        return $this;
163
    }
164
165
    public function getBelongsToRelationName(string $related): string
166
    {
167
        return Str::snake(class_basename($related));
168
    }
169
170
    public function getHasManyRelationName(string $related): string
171
    {
172
        return Str::plural(Str::snake(class_basename($related)));
173
    }
174
175
    public function getManyToManyRelationName(string $related): string
176
    {
177
        return Str::plural(Str::snake(class_basename($related)));
178
    }
179
180
    private function getMorphs(string $name, ?string $type, ?string $id): array
181
    {
182
        return [$type ?: $name.'_type', $id ?: $name.'_id'];
183
    }
184
}
185