Passed
Push — main ( 303b6c...b49db2 )
by Sammy
01:47 queued 15s
created

Schema::database()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 1
nc 1
nop 0
dl 0
loc 3
rs 10
c 0
b 0
f 0
1
<?php
2
3
namespace HexMakina\Crudites\Schema;
4
5
use HexMakina\BlackBox\Database\QueryInterface;
6
use HexMakina\BlackBox\Database\{SchemaInterface, SchemaAttributeInterface};
0 ignored issues
show
Bug introduced by
The type HexMakina\BlackBox\Database\SchemaInterface was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
Bug introduced by
The type HexMakina\BlackBox\Datab...chemaAttributeInterface was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
7
use HexMakina\Crudites\Grammar\Query\Select;
8
use HexMakina\Crudites\Grammar\Query\Insert;
9
use HexMakina\Crudites\Grammar\Query\Update;
10
use HexMakina\Crudites\Grammar\Query\Delete;
11
12
/**
13
 * The class provides an abstraction for database schema information.
14
 * It is built using the INFORMATION_SCHEMA database.
15
 */
16
class Schema implements SchemaInterface
17
{
18
    private string $database;
19
    private array $tables = [];
20
21
    // use a SchemaLoader to get the proper table structure
22
    public function __construct(string $database, array $tables = [])
23
    {
24
        $this->database = $database;
25
        $this->tables = $tables;
26
    }
27
28
    public function hasTable(string $table): bool
29
    {
30
        return isset($this->tables[$table]);
31
    }
32
    public function database(): string
33
    {
34
        return $this->database;
35
    }
36
37
    public function tables(): array
38
    {
39
        return array_keys($this->tables);
40
    }
41
42
    public function hasColumn(string $table, string $column): bool
43
    {
44
        return $this->hasTable($table) && !empty($this->tables[$table]['columns'][$column]);
45
    }
46
47
    public function columns(string $table): array
48
    {
49
        return $this->hasTable($table) ? array_keys($this->tables[$table]['columns']) : [];
50
    }
51
52
    public function column(string $table, string $column): array
53
    {
54
        if (!$this->hasColumn($table, $column)) {
55
            throw new \InvalidArgumentException('CANNOT FIND COLUMN ' . $column . ' IN TABLE ' . $table);
56
        }
57
58
        if(!isset($this->tables[$table]['columns'][$column]['schema'])){
59
            throw new \InvalidArgumentException("ERR_MISSING_COLUMN_SCHEMA");
60
        }
61
62
        return $this->tables[$table]['columns'][$column]['schema'];
63
    }
64
65
    public function attributes(string $table, string $column): SchemaAttributeInterface
66
    {
67
        return new SchemaAttribute($this, $table, $column);
68
    }
69
70
    public function autoIncrementedPrimaryKey(string $table): ?string
71
    {
72
        foreach ($this->primaryKeys($table) as $column) {
73
            return $this->attributes($table, $column)->isAuto() ? $column : null;
74
        }
75
76
        return null;
77
    }
78
    public function primaryKeys(string $table): array
79
    {
80
        return $this->hasTable($table) ? $this->tables[$table]['primary'] : [];
81
    }
82
83
    public function foreignKeys(string $table): array
84
    {
85
        return $this->hasTable($table) ? $this->tables[$table]['foreign'] : [];
86
    }
87
88
    public function foreignKey(string $table, string $column): array
89
    {
90
        return $this->hasTable($table) ? ($this->tables[$table]['foreign'][$column] ?? []) : [];
91
    }
92
93
    public function uniqueKeys(string $table): array
94
    {
95
        return $this->hasTable($table) ? $this->tables[$table]['unique'] : [];
96
    }
97
98
    public function uniqueColumnsByName(string $table, string $constraint): array
99
    {
100
        return $this->hasTable($table) ? $this->tables[$table]['unique'][$constraint] : [];
101
    }
102
103
    public function uniqueColumnsFor(string $table, string $column): array
104
    {
105
        $ret = [];
106
107
        if ($this->hasColumn($table, $column)) {
108
            foreach ($this->tables[$table]['columns'][$column]['unique'] as $constraint_name) {
109
                $ret[$constraint_name] = $this->uniqueColumnsByName($table, $constraint_name);
110
            }
111
        }
112
113
        return $ret;
114
    }
115
116
117
    public function matchUniqueness(string $table, array $dat_ass): array
118
    {
119
        return $this->matchPrimaryKeys($table, $dat_ass) ?? $this->matchUniqueKeys($table, $dat_ass) ?? [];
120
    }
121
122
    public function matchPrimaryKeys(string $table, array $dat_ass): ?array
123
    {
124
        $primaryKeys = $this->primaryKeys($table);
125
        $match = array_intersect_key($dat_ass, array_flip($primaryKeys));
126
127
        return count($match) === count($primaryKeys) ? $match : null;
128
    }
129
130
    public function matchUniqueKeys(string $table, array $dat_ass): ?array
131
    {
132
        foreach ($this->uniqueKeys($table) as $columns) {
133
            $match = array_intersect_key($dat_ass, array_flip($columns));
134
135
            if (count($match) === count($columns)) {
136
                return $match;
137
            }
138
        }
139
140
        return null;
141
    }
142
143
144
    public function insert(string $table, array $dat_ass): QueryInterface
145
    {
146
        return new Insert($table, $this->filterData($table, $dat_ass));
147
    }
148
149
    public function update(string $table, array $alterations = [], array $conditions = []): QueryInterface
150
    {
151
        return new Update($table, $this->filterData($table, $alterations), $this->filterData($table, $conditions));
152
    }
153
154
    public function delete(string $table, array $conditions): QueryInterface
155
    {
156
        return new Delete($table, $this->filterData($table, $conditions));
157
    }
158
159
    public function select(string $table, array $columns = null, string $table_alias = null): QueryInterface
160
    {
161
        if(in_array('*', $columns)){
0 ignored issues
show
Bug introduced by
It seems like $columns can also be of type null; however, parameter $haystack of in_array() does only seem to accept array, maybe add an additional type check? ( Ignorable by Annotation )

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

161
        if(in_array('*', /** @scrutinizer ignore-type */ $columns)){
Loading history...
162
            $filtered_columns = ['*'];
163
        }
164
        else{
165
            $filtered_columns = array_intersect($columns, $this->columns($table));
0 ignored issues
show
Bug introduced by
It seems like $columns can also be of type null; however, parameter $array of array_intersect() does only seem to accept array, maybe add an additional type check? ( Ignorable by Annotation )

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

165
            $filtered_columns = array_intersect(/** @scrutinizer ignore-type */ $columns, $this->columns($table));
Loading history...
166
        } 
167
        
168
        return new Select($filtered_columns, $table, $table_alias);
169
    }
170
171
    /**
172
     * Filters the given data to only include columns that exist in the specified table.
173
     *
174
     * @param string $table The name of the table.
175
     * @param array $dat_ass The data to filter.
176
     * @return array The filtered data.
177
     */
178
    private function filterData(string $table, array $dat_ass)
179
    {
180
        return array_intersect_key($dat_ass, array_flip($this->columns($table)));
181
    }
182
}
183