Failed Conditions
Push — 186-self-joins-fail-in-relatio... ( ba3e0e...5bcaaa )
by Bas
08:01 queued 40s
created

HandlesAliases::getTableAlias()   A

Complexity

Conditions 4
Paths 6

Size

Total Lines 17
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 9
CRAP Score 4.016

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 4
eloc 8
c 1
b 0
f 0
nc 6
nop 1
dl 0
loc 17
ccs 9
cts 10
cp 0.9
crap 4.016
rs 10
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
    use GeneratesTableAlias;
18
19
    /**
20
     * @var array<string, Expression|string>
21
     */
22
    public array $tableAliases = [];
23
24
    /**
25
     * @var array<string, Expression|string>
26
     */
27
    public array $columnAliases = [];
28
29
    /**
30
     * Extract table and alias from sql alias notation (entity AS `alias`)
31
     *
32
     * @return array<int|string, Expression|string>
33
     *
34
     * @throws Exception
35
     */
36
    public function extractAlias(string $entity, int|null|string $key = null): array
37
    {
38
        $results = preg_split("/\sas\s/i", $entity);
39
40
        if ($results === false) {
41
            throw new Exception('Column splitting failed');
42
        }
43
44
        if (isset($results[1])) {
45
            $results[1] = trim($results[1], '`');
46
        }
47
        if (!isset($results[1]) && is_string($key)) {
48 151
            $results[1] = $key;
49
        }
50 151
        if (!isset($results[1])) {
51
            $results[1] = $results[0];
52 151
        }
53
54
        return $results;
55
    }
56 151
    public function getTableAlias(string|Expression $table): string|null
57 23
    {
58
        if ($table instanceof Expression) {
59 151
            $table = 'laravel_expression_' . spl_object_id($table);
60 2
        }
61
62 151
        if ($this->isTableAlias($table)) {
63 134
            return $table;
64
        }
65
66 151
        $alias = array_search($table, $this->tableAliases, true);
67
68
        if (is_string($alias)) {
69 395
            return $alias;
70
        }
71 395
72
        return null;
73
    }
74 395
75
    public function getColumnAlias(string $column): Expression|null|string
76
    {
77 388
        if (isset($this->columnAliases[$column])) {
78
            return $this->columnAliases[$column];
79 388
        }
80 2
81
        return null;
82
    }
83 388
84 17
    /**
85
     * @return array<string, Expression|string>
86
     */
87 388
    public function getTableAliases(): array
88 310
    {
89
        return $this->tableAliases;
90
    }
91 318
92
    /**
93
     * @param array<string, Expression|string>|IlluminateQueryBuilder $aliases
94
     * @return void
95
     */
96
    public function importTableAliases(array|IlluminateQueryBuilder $aliases): void
97
    {
98
        if ($aliases instanceof IlluminateQueryBuilder) {
0 ignored issues
show
introduced by
$aliases is never a sub-type of Illuminate\Database\Query\Builder.
Loading history...
99
            assert($aliases instanceof Builder);
100
            $aliases = $aliases->getTableAliases();
101
        }
102
103
        $this->tableAliases = array_merge($this->tableAliases, $aliases);
104
    }
105
106 64
    /**
107
     * @param IlluminateEloquentBuilder|IlluminateQueryBuilder|Relation $query
108 64
     * @return void
109
     */
110
    public function exchangeTableAliases($query): void
111
    {
112
        assert($query instanceof Builder);
113
114
        $this->importTableAliases($query);
115 64
        $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

115
        $query->importTableAliases(/** @scrutinizer ignore-type */ $this);
Loading history...
116
    }
117 64
118
    public function isTableAlias(string $value): bool
119 64
    {
120
        return array_key_exists($value, $this->tableAliases);
121
    }
122 64
123
    public function isTable(string $value): bool
124
    {
125
        return !! array_search($value, $this->tableAliases);
126
    }
127
128
    public function prefixAlias(string $target, string $value): string
129 40
    {
130
        /** @phpstan-ignore-next-line */
131
        $alias = $this->grammar->getValue($this->getTableAlias($target));
132
133 40
        if (Str::startsWith($value, $alias . '.')) {
134 40
            return $value;
135
        }
136
137 388
        return $alias . '.' . $value;
138
    }
139 388
140
    /**
141
     * @SuppressWarnings(PHPMD.CyclomaticComplexity)
142 8
     * @param string|Expression $table
143
     * @param string|null $alias
144 8
     * @return array<string|Expression>
145
     */
146
    public function registerTableAlias(string|Expression $table, ?string $alias = null): array
147
    {
148
        if ($table instanceof Expression  && $alias !== null) {
149
            $table = 'laravel_expression_' . spl_object_id($table);
150
        }
151
152
        if ($table instanceof Expression && $alias === null) {
153
            $table = 'laravel_expression_' . spl_object_id($table);
154
            $alias = $table;
155
        }
156
157
        /** @phpstan-ignore-next-line  */
158
        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...
159
            $tableParts = [];
160
161
            if (preg_match("/(^.*) as (.*?)$/", $table, $tableParts)) {
162
                $table = $tableParts[1];
163
                $alias = $tableParts[2];
164
            }
165
        }
166
167
        if ($alias == null) {
168
            $alias = $this->generateTableAlias($table);
169
        }
170
171
        /** @phpstan-ignore-next-line  */
172
        $this->tableAliases[$alias] = $table;
173
174
        return [$table, $alias];
175
    }
176
177
    public function replaceTableForAlias(string $reference): string
178
    {
179
        $referenceParts = explode('.', $reference);
180 395
        $first = array_shift($referenceParts);
181
        /** @phpstan-ignore-next-line */
182 395
        $alias = $this->grammar->getValue($this->getTableAlias($first));
183 5
        if ($alias == null) {
184
            $alias = $first;
185
        }
186 395
        array_unshift($referenceParts, $alias);
187 3
188 3
        return implode('.', $referenceParts);
189
    }
190
191
    /**
192 395
     * @param  array<mixed>|string  $column
193
     * @return array<mixed>|string
194
     */
195
    public function convertColumnId(array|string|Expression $column): array|string|Expression
196
    {
197
198
        if ($column instanceof Expression) {
0 ignored issues
show
introduced by
$column is never a sub-type of Illuminate\Database\Query\Expression.
Loading history...
199
            return $column;
200
        }
201 395
202 395
        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

202
        return $this->/** @scrutinizer ignore-call */ convertIdToKey($column);
Loading history...
203
    }
204
205
    /**
206 395
     * @throws Exception
207
     */
208 395
    public function registerColumnAlias(string $column, ?string $alias = null): bool
209
    {
210
        if (preg_match("/\sas\s/i", $column)) {
211
            [$column, $alias] = $this->extractAlias($column);
212
        }
213
214
        if (isset($alias) && !$column instanceof Expression) {
215
            $this->columnAliases[$column] = $alias;
216
217
            return true;
218
        }
219
220
        return false;
221
    }
222
}
223