Failed Conditions
Push — 186-self-joins-fail-in-relatio... ( c6ac1e )
by Bas
03:54
created

HandlesAliases::isTable()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 1
c 1
b 0
f 0
nc 1
nop 1
dl 0
loc 3
ccs 2
cts 2
cp 1
crap 1
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
    /**
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