Passed
Push — next ( bea07e...b4e6e6 )
by Bas
05:12 queued 01:45
created

ModelInspector::addSystemAttributes()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 35
Code Lines 19

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 29
CRAP Score 2

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 2
eloc 19
nc 2
nop 2
dl 0
loc 35
ccs 29
cts 29
cp 1
crap 2
rs 9.6333
c 1
b 0
f 0
1
<?php
2
3
namespace LaravelFreelancerNL\Aranguent\Eloquent;
4
5
use Illuminate\Contracts\Container\BindingResolutionException;
6
use Illuminate\Database\Eloquent\ModelInspector as IlluminateModelInspector;
7
use Illuminate\Support\Collection;
8
use LaravelFreelancerNL\Aranguent\Connection;
9
10
use function Illuminate\Support\enum_value;
11
12
class ModelInspector extends IlluminateModelInspector
13
{
14
    /**
15
     * The methods that can be called in a model to indicate a relation.
16
     *
17
     * @var array<int, string>
18
     */
19
    protected $relationMethods = [
20
        'hasMany',
21
        'hasManyThrough',
22
        'hasOneThrough',
23
        'belongsToMany',
24
        'hasOne',
25
        'belongsTo',
26
        'morphOne',
27
        'morphTo',
28
        'morphMany',
29
        'morphToMany',
30
        'morphedByMany',
31
    ];
32
33
    /**
34
     * Extract model details for the given model.
35
     *
36
     * @param  class-string<\Illuminate\Database\Eloquent\Model>|string  $model
0 ignored issues
show
Documentation Bug introduced by
The doc comment class-string<\Illuminate...\Eloquent\Model>|string at position 0 could not be parsed: Unknown type name 'class-string' at position 0 in class-string<\Illuminate\Database\Eloquent\Model>|string.
Loading history...
37
     * @param  string|null  $connection
38
     * @return array{"class": class-string<\Illuminate\Database\Eloquent\Model>, database: string, table: string, policy: class-string|null, attributes: Collection, relations: Collection, events: Collection, observers: Collection, collection: class-string<\Illuminate\Database\Eloquent\Collection<\Illuminate\Database\Eloquent\Model>>, builder: class-string<\Illuminate\Database\Eloquent\Builder<\Illuminate\Database\Eloquent\Model>>}
0 ignored issues
show
Documentation Bug introduced by
The doc comment array{"class": class-str...abase\Eloquent\Model>>} at position 4 could not be parsed: Unknown type name 'class-string' at position 4 in array{"class": class-string<\Illuminate\Database\Eloquent\Model>, database: string, table: string, policy: class-string|null, attributes: Collection, relations: Collection, events: Collection, observers: Collection, collection: class-string<\Illuminate\Database\Eloquent\Collection<\Illuminate\Database\Eloquent\Model>>, builder: class-string<\Illuminate\Database\Eloquent\Builder<\Illuminate\Database\Eloquent\Model>>}.
Loading history...
39
     *
40
     * @throws BindingResolutionException
41
     */
42 4
    public function inspect($model, $connection = null)
43
    {
44 4
        $class = $this->qualifyModel($model);
45
46
        /** @var \Illuminate\Database\Eloquent\Model $model */
47 4
        $model = $this->app->make($class);
48
49 4
        if ($connection !== null) {
50
            $model->setConnection($connection);
51
        }
52
53
54
        /* @phpstan-ignore-next-line  */
55 4
        return [
56 4
            'class' => get_class($model),
57 4
            'database' => $model->getConnection()->getName() ?? '',
58 4
            'table' => $model->getConnection()->getTablePrefix() . $model->getTable(),
59 4
            'policy' => $this->getPolicy($model) ?? '',
60 4
            'attributes' => $this->getAttributes($model),
61 4
            'relations' => $this->getRelations($model),
62 4
            'events' => $this->getEvents($model),
63 4
            'observers' => $this->getObservers($model),
64 4
            'collection' => $this->getCollectedBy($model),
65 4
            'builder' => $this->getBuilder($model),
66 4
        ];
67
    }
68
69
    /**
70
     * Get the column attributes for the given model.
71
     *
72
     * @param  \Illuminate\Database\Eloquent\Model  $model
73
     * @return Collection<int, array<string, mixed>>
74
     */
75 4
    protected function getAttributes($model)
76
    {
77 4
        $connection = $model->getConnection();
78
        assert($connection instanceof Connection);
79
80 4
        $schema = $connection->getSchemaBuilder();
81 4
        $table = $model->getTable();
82 4
        $tableData = $schema->getTable($table);
83 4
        $columns = $schema->getColumns($table);
84 4
        $indexes = $schema->getIndexes($table);
85
86 4
        $columns = $this->addSystemAttributes($columns, $tableData);
87
88
        /* @phpstan-ignore-next-line  */
89 4
        return collect($columns)
0 ignored issues
show
Bug introduced by
$columns of type array<mixed,mixed> is incompatible with the type Illuminate\Contracts\Support\Arrayable expected by parameter $value of collect(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

89
        return collect(/** @scrutinizer ignore-type */ $columns)
Loading history...
90 4
            ->map(fn($column) => [
91 4
                'name' => $column['name'],
92 4
                'type' => $column['type'],
93 4
                'increments' => $column['auto_increment'] ?? null,
94 4
                'nullable' => $column['nullable'] ?? null,
95 4
                'default' => $this->getColumnDefault($column, $model) ?? null,
96 4
                'unique' => $this->columnIsUnique($column['name'], $indexes),
97 4
                'fillable' => $model->isFillable($column['name']),
98 4
                'computed' => $this->columnIsComputed($column['name'], $tableData),
99 4
                'hidden' => $this->attributeIsHidden($column['name'], $model),
100 4
                'appended' => null,
101 4
                'cast' => $this->getCastType($column['name'], $model),
102 4
            ])
103 4
            ->merge($this->getVirtualAttributes($model, $columns));
104
    }
105
106
    /**
107
     * Get the default value for the given column.
108
     *
109
     * @param  array<string, mixed>  $column
110
     * @param  \Illuminate\Database\Eloquent\Model  $model
111
     * @return mixed|null
112
     */
113 4
    protected function getColumnDefault($column, $model)
114
    {
115 4
        $attributeDefault = $model->getAttributes()[$column['name']] ?? null;
116
117 4
        return enum_value($attributeDefault, $column['default'] ?? null);
118
    }
119
120
    /**
121
     * Determine if the given attribute is unique.
122
     *
123
     * @param  string  $column
124
     * @param  mixed[]  $indexes
125
     * @return bool
126
     */
127 4
    protected function columnIsUnique($column, $indexes)
128
    {
129 4
        return collect($indexes)->contains(
0 ignored issues
show
Bug introduced by
$indexes of type array<mixed,mixed> is incompatible with the type Illuminate\Contracts\Support\Arrayable expected by parameter $value of collect(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

129
        return collect(/** @scrutinizer ignore-type */ $indexes)->contains(
Loading history...
130 4
            fn($index) => count($index['fields']) === 1 && $index['fields'][0] === $column && $index['unique'],
131 4
        );
132
    }
133
134
    /**
135
     * @param string $name
136
     * @param array<string, mixed> $tableData
137
     * @return bool
138
     */
139 4
    protected function columnIsComputed($name, $tableData)
140
    {
141 4
        $computedValues = (new Collection($tableData['computedValues']))->pluck('name')->toArray();
142
143 4
        return in_array($name, $computedValues);
144
    }
145
146
    /**
147
     * @param mixed[] $columns
148
     * @param mixed[] $tableData
149
     * @return mixed[]
150
     */
151 4
    protected function addSystemAttributes(array $columns, $tableData)
152
    {
153
        // edges add _from, _to
154 4
        if ($tableData['type'] === 3) {
155 1
            array_unshift(
156 1
                $columns,
157 1
                [
158 1
                    'name' => '_to',
159 1
                    'type' => 'string',
160 1
                    'nullable' => false,
161 1
                ],
162 1
            );
163 1
            array_unshift(
164 1
                $columns,
165 1
                [
166 1
                    'name' => '_from',
167 1
                    'type' => 'string',
168 1
                    'nullable' => false,
169 1
                ],
170 1
            );
171
        }
172
173
        // Prepend id,
174 4
        array_unshift(
175 4
            $columns,
176 4
            [
177 4
                'name' => 'id',
178 4
                'type' => $tableData['keyOptions']->type,
179 4
                'nullable' => false,
180 4
                'allowUserKeys' => $tableData['keyOptions']->allowUserKeys,
181 4
                'unique' => true,
182 4
            ],
183 4
        );
184
185 4
        return $columns;
186
    }
187
}
188