ModelTestor   A
last analyzed

Complexity

Total Complexity 28

Size/Duplication

Total Lines 174
Duplicated Lines 0 %

Importance

Changes 1
Bugs 1 Features 0
Metric Value
eloc 78
c 1
b 1
f 0
dl 0
loc 174
rs 10
wmc 28

17 Methods

Rating   Name   Duplication   Size   Complexity  
A assertHasBelongsToRelation() 0 18 3
A assertHasHasManyRelation() 0 14 2
A assertCanFillables() 0 6 1
A getModelTable() 0 9 2
A __construct() 0 5 1
A getTable() 0 6 1
A assertHasColumns() 0 7 1
A isExistingTable() 0 6 2
A isModelClass() 0 6 2
A assertHasManyToManyRelation() 0 14 2
A getModel() 0 6 2
A assertHasHasManyMorphRelation() 0 11 2
A getMorphs() 0 3 3
A getManyToManyRelationName() 0 3 1
A getBelongsToRelationName() 0 3 1
A getHasManyRelationName() 0 3 1
A assertHasBelongsToMorphRelation() 0 14 1
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 $relation = null): self
139
    {
140
        $relation = $relation ?: $this->getHasManyRelationName($related);
141
142
        $instance = factory($this->getModel())->create();
143
        $instance->{$relation}()->save(factory($related)->make());
144
        $instance->refresh();
145
146
        $this->assertInstanceOf($related, $instance->{$relation}->first());
147
148
        return $this;
149
    }
150
151
    public function assertHasBelongsToMorphRelation(string $related, string $name, ?string $type = null, ?string $id = null): self
152
    {
153
        [$type, $id] = $this->getMorphs($name, $type, $id);
154
155
        $instance = factory($related)->create();
156
        $morph = factory($this->getModel())->create([
157
            $id   => $instance->id,
158
            $type => $related,
159
        ]);
160
        $morph->refresh();
161
162
        $this->assertInstanceOf($related, $morph->{$name});
163
164
        return $this;
165
    }
166
167
    public function getBelongsToRelationName(string $related): string
168
    {
169
        return Str::snake(class_basename($related));
170
    }
171
172
    public function getHasManyRelationName(string $related): string
173
    {
174
        return Str::plural(Str::snake(class_basename($related)));
175
    }
176
177
    public function getManyToManyRelationName(string $related): string
178
    {
179
        return Str::plural(Str::snake(class_basename($related)));
180
    }
181
182
    private function getMorphs(string $name, ?string $type, ?string $id): array
183
    {
184
        return [$type ?: $name.'_type', $id ?: $name.'_id'];
185
    }
186
}
187