Issues (65)

src/Schema/Schema.php (2 issues)

Labels
Severity
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
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...
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 database(): string
29
    {
30
        return $this->database;
31
    }
32
33
    public function hasTable(string $table): bool
34
    {
35
        return isset($this->tables[$table]);
36
    }
37
38
    public function tables(): array
39
    {
40
        return array_keys($this->tables);
41
    }
42
43
    public function hasColumn(string $table, string $column): bool
44
    {
45
        return $this->hasTable($table) && !empty($this->tables[$table]['columns'][$column]);
46
    }
47
48
    public function columns(string $table): array
49
    {
50
        return $this->hasTable($table) ? array_keys($this->tables[$table]['columns']) : [];
51
    }
52
53
    public function column(string $table, string $column): array
54
    {
55
        if (!$this->hasColumn($table, $column)) {
56
            throw new \InvalidArgumentException('CANNOT FIND COLUMN ' . $column . ' IN TABLE ' . $table);
57
        }
58
59
        if (!isset($this->tables[$table]['columns'][$column]['schema'])) {
60
            throw new \InvalidArgumentException("ERR_MISSING_COLUMN_SCHEMA");
61
        }
62
63
        return $this->tables[$table]['columns'][$column]['schema'];
64
    }
65
66
    public function attributes(string $table, string $column): SchemaAttributeInterface
67
    {
68
        return new SchemaAttribute($this, $table, $column);
69
    }
70
71
    public function autoIncrementedPrimaryKey(string $table): ?string
72
    {
73
        foreach ($this->primaryKeys($table) as $column) {
74
            return $this->attributes($table, $column)->isAuto() ? $column : null;
75
        }
76
77
        return null;
78
    }
79
    public function primaryKeys(string $table): array
80
    {
81
        return $this->hasTable($table) ? $this->tables[$table]['primary'] : [];
82
    }
83
84
    public function foreignKeys(string $table): array
85
    {
86
        return $this->hasTable($table) ? $this->tables[$table]['foreign'] : [];
87
    }
88
89
    public function foreignKey(string $table, string $column): array
90
    {
91
        return $this->hasTable($table) ? ($this->tables[$table]['foreign'][$column] ?? []) : [];
92
    }
93
94
    public function uniqueKeys(string $table): array
95
    {
96
        return $this->hasTable($table) ? $this->tables[$table]['unique'] : [];
97
    }
98
99
    public function uniqueColumnsByName(string $table, string $constraint): array
100
    {
101
        return $this->hasTable($table) ? $this->tables[$table]['unique'][$constraint] : [];
102
    }
103
104
    public function uniqueColumnsFor(string $table, string $column): array
105
    {
106
        $ret = [];
107
108
        if ($this->hasColumn($table, $column)) {
109
            foreach ($this->tables[$table]['columns'][$column]['unique'] as $constraint_name) {
110
                $ret[$constraint_name] = $this->uniqueColumnsByName($table, $constraint_name);
111
            }
112
        }
113
114
        return $ret;
115
    }
116
117
118
    public function matchUniqueness(string $table, array $dat_ass): array
119
    {
120
        return $this->matchPrimaryKeys($table, $dat_ass) ?? $this->matchUniqueKeys($table, $dat_ass) ?? [];
121
    }
122
123
    public function matchPrimaryKeys(string $table, array $dat_ass): ?array
124
    {
125
        $primaryKeys = $this->primaryKeys($table);
126
        $match = array_intersect_key($dat_ass, array_flip($primaryKeys));
127
128
        return count($match) === count($primaryKeys) ? $match : null;
129
    }
130
131
    public function matchUniqueKeys(string $table, array $dat_ass): ?array
132
    {
133
        foreach ($this->uniqueKeys($table) as $columns) {
134
            $match = array_intersect_key($dat_ass, array_flip($columns));
135
136
            if (count($match) === count($columns)) {
137
                return $match;
138
            }
139
        }
140
141
        return null;
142
    }
143
144
145
    public function insert(string $table, array $dat_ass): QueryInterface
146
    {
147
        return new Insert($table, $this->filterData($table, $dat_ass));
148
    }
149
150
    public function update(string $table, array $alterations = [], array $conditions = []): QueryInterface
151
    {
152
        return new Update($table, $this->filterData($table, $alterations), $this->filterData($table, $conditions));
153
    }
154
155
    public function delete(string $table, array $conditions): QueryInterface
156
    {
157
        return new Delete($table, $this->filterData($table, $conditions));
158
    }
159
160
    public function select(string $table, array $columns = null, string $table_alias = null): QueryInterface
161
    {
162
        $filtered_columns = [];
163
        // if $columns is an empty array or null or an array containing *
164
        if (empty($columns) || in_array('*', $columns)) {
165
            $filtered_columns = ['*'];
166
        } else {
167
            $filtered_columns = array_intersect($columns, $this->columns($table));
168
        }
169
170
        return new Select($filtered_columns, $table, $table_alias);
171
    }
172
173
    /**
174
     * Filters the given data to only include columns that exist in the specified table.
175
     *
176
     * @param string $table The name of the table.
177
     * @param array $dat_ass The data to filter.
178
     * @return array The filtered data.
179
     */
180
    private function filterData(string $table, array $dat_ass)
181
    {
182
        return array_intersect_key($dat_ass, array_flip($this->columns($table)));
183
    }
184
}
185