Failed Conditions
Push — 184-support-wheredoesnthaverel... ( 76eefa...5b2c01 )
by Bas
03:19
created

HandlesAliases::registerTableAlias()   B

Complexity

Conditions 10
Paths 24

Size

Total Lines 29
Code Lines 14

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 11
CRAP Score 11.897

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 10
eloc 14
c 1
b 0
f 0
nc 24
nop 2
dl 0
loc 29
ccs 11
cts 15
cp 0.7332
crap 11.897
rs 7.6666

How to fix   Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
declare(strict_types=1);
4
5
namespace LaravelFreelancerNL\Aranguent\Query\Concerns;
6
7
use Exception;
8
use Illuminate\Database\Eloquent\Builder as IlluminateEloquentBuilder;
9
use Illuminate\Database\Eloquent\Relations\Relation;
10
use Illuminate\Database\Query\Expression;
11
use Illuminate\Support\Str;
12
use Illuminate\Database\Query\Builder as IlluminateQueryBuilder;
13
use LaravelFreelancerNL\Aranguent\Query\Builder;
14
15
trait HandlesAliases
16
{
17
    /**
18
     * @var array<string, Expression|string>
19
     */
20
    public array $tableAliases = [];
21
22
    /**
23
     * @var array<string, Expression|string>
24
     */
25
    public array $columnAliases = [];
26
27
    /**
28
     * @param  array<mixed>|string  $column
29
     * @return array<mixed>|string
30
     */
31
    public function convertColumnId(array|string|Expression $column): array|string|Expression
32
    {
33
34
        if ($column instanceof Expression) {
0 ignored issues
show
introduced by
$column is never a sub-type of Illuminate\Database\Query\Expression.
Loading history...
35
            return $column;
36
        }
37
38
        return $this->convertIdToKey($column);
0 ignored issues
show
Bug introduced by
It seems like convertIdToKey() must be provided by classes using this trait. How about adding it as abstract method to this trait? ( Ignorable by Annotation )

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

38
        return $this->/** @scrutinizer ignore-call */ convertIdToKey($column);
Loading history...
39
    }
40
41
    /**
42
     * Extract table and alias from sql alias notation (entity AS `alias`)
43
     *
44
     * @return array<int|string, Expression|string>
45
     *
46
     * @throws Exception
47
     */
48 151
    public function extractAlias(string $entity, int|null|string $key = null): array
49
    {
50 151
        $results = preg_split("/\sas\s/i", $entity);
51
52 151
        if ($results === false) {
53
            throw new Exception('Column splitting failed');
54
        }
55
56 151
        if (isset($results[1])) {
57 23
            $results[1] = trim($results[1], '`');
58
        }
59 151
        if (!isset($results[1]) && is_string($key)) {
60 2
            $results[1] = $key;
61
        }
62 151
        if (!isset($results[1])) {
63 134
            $results[1] = $results[0];
64
        }
65
66 151
        return $results;
67
    }
68
69 395
    public function generateTableAlias(string|Expression $table, string $postfix = 'Doc'): string
70
    {
71 395
        if ($table instanceof Expression) {
72
            return 'Expression' . spl_object_id($table);
73
        }
74 395
        return Str::camel(Str::singular($table)) . $postfix;
75
    }
76
77 388
    public function getTableAlias(string|Expression $table): float|int|null|string
78
    {
79 388
        if ($table instanceof Expression) {
80 2
            $table = 'Expression' . spl_object_id($table);
81
        }
82
83 388
        if ($this->isTableAlias($table)) {
84 17
            return $table;
85
        }
86
87 388
        if (!isset($this->tableAliases[$table])) {
88 310
            return null;
89
        }
90
91 318
        return $this->grammar->getValue($this->tableAliases[$table]);
92
    }
93
94
    public function getColumnAlias(string $column): Expression|null|string
95
    {
96
        if (isset($this->columnAliases[$column])) {
97
            return $this->columnAliases[$column];
98
        }
99
100
        return null;
101
    }
102
103
    /**
104
     * @return array<string, Expression|string>
105
     */
106 64
    public function getTableAliases(): array
107
    {
108 64
        return $this->tableAliases;
109
    }
110
111
    /**
112
     * @param array<string, Expression|string>|IlluminateQueryBuilder $aliases
113
     * @return void
114
     */
115 64
    public function importTableAliases(array|IlluminateQueryBuilder $aliases): void
116
    {
117 64
        if ($aliases instanceof IlluminateQueryBuilder) {
0 ignored issues
show
introduced by
$aliases is never a sub-type of Illuminate\Database\Query\Builder.
Loading history...
118
            assert($aliases instanceof Builder);
119 64
            $aliases = $aliases->getTableAliases();
120
        }
121
122 64
        $this->tableAliases = array_merge($this->tableAliases, $aliases);
123
    }
124
125
    /**
126
     * @param IlluminateEloquentBuilder|IlluminateQueryBuilder|Relation $query
127
     * @return void
128
     */
129 40
    public function exchangeTableAliases($query): void
130
    {
131
        assert($query instanceof Builder);
132
133 40
        $this->importTableAliases($query);
134 40
        $query->importTableAliases($this);
0 ignored issues
show
Bug introduced by
$this of type LaravelFreelancerNL\Aran...Concerns\HandlesAliases is incompatible with the type Illuminate\Database\Query\Builder|array expected by parameter $aliases of LaravelFreelancerNL\Aran...r::importTableAliases(). ( Ignorable by Annotation )

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

134
        $query->importTableAliases(/** @scrutinizer ignore-type */ $this);
Loading history...
135
    }
136
137 388
    public function isTableAlias(string $value): bool
138
    {
139 388
        return in_array($value, $this->tableAliases);
140
    }
141
142 8
    public function isTable(string $value): bool
143
    {
144 8
        return array_key_exists($value, $this->tableAliases);
145
    }
146
147
    public function prefixAlias(string $target, string $value): string
148
    {
149
        /** @phpstan-ignore-next-line */
150
        $alias =  $this->grammar->getValue($this->getTableAlias($target));
151
152
        if (Str::startsWith($value, $alias . '.')) {
153
            return $value;
154
        }
155
156
        return $alias . '.' . $value;
157
    }
158
159
    /**
160
     * @throws Exception
161
     */
162
    public function registerColumnAlias(string $column, ?string $alias = null): bool
163
    {
164
        if (preg_match("/\sas\s/i", $column)) {
165
            [$column, $alias] = $this->extractAlias($column);
166
        }
167
168
        if (isset($alias) && !$column instanceof Expression) {
169
            $this->columnAliases[$column] = $alias;
170
171
            return true;
172
        }
173
174
        return false;
175
    }
176
177
    /**
178
     * @SuppressWarnings(PHPMD.CyclomaticComplexity)
179
     */
180 395
    public function registerTableAlias(string|Expression $table, ?string $alias = null): string
181
    {
182 395
        if ($table instanceof Expression  && $alias !== null) {
183 5
            $table = 'Expression' . spl_object_id($table);
184
        }
185
186 395
        if ($table instanceof Expression && $alias === null) {
187 3
            $table = 'Expression' . spl_object_id($table);
188 3
            $alias = $table;
189
        }
190
191
        /** @phpstan-ignore-next-line  */
192 395
        if ($alias == null && is_string($table) && stripos($table, ' as ') !== false) {
0 ignored issues
show
Bug introduced by
It seems like you are loosely comparing $alias of type null|string against null; this is ambiguous if the string can be empty. Consider using a strict comparison === instead.
Loading history...
193
            $tableParts = [];
194
195
            if (preg_match("/(^.*) as (.*?)$/", $table, $tableParts)) {
196
                $table = $tableParts[1];
197
                $alias = $tableParts[2];
198
            }
199
        }
200
201 395
        if ($alias == null) {
202 395
            $alias = $this->generateTableAlias($table);
203
        }
204
205
        /** @phpstan-ignore-next-line  */
206 395
        $this->tableAliases[$table] = $alias;
207
208 395
        return $alias;
209
    }
210
211
    public function replaceTableForAlias(string $reference): string
212
    {
213
        $referenceParts = explode('.', $reference);
214
        $first = array_shift($referenceParts);
215
        /** @phpstan-ignore-next-line */
216
        $alias = $this->grammar->getValue($this->getTableAlias($first));
217
        if ($alias == null) {
218
            $alias = $first;
219
        }
220
        array_unshift($referenceParts, $alias);
221
222
        return implode('.', $referenceParts);
223
    }
224
}
225