Passed
Push — main ( 197711...a7baa5 )
by Sammy
07:12 queued 14s
created

TableModel::relationalMappingName()   A

Complexity

Conditions 5
Paths 3

Size

Total Lines 23
Code Lines 14

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 1
Metric Value
eloc 14
c 1
b 0
f 1
dl 0
loc 23
rs 9.4888
cc 5
nc 3
nop 0
1
<?php
2
3
namespace HexMakina\TightORM;
4
5
use HexMakina\BlackBox\Database\SchemaInterface;
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...
6
use HexMakina\Crudites\Crudites;
7
use HexMakina\Crudites\CruditesException;
8
use HexMakina\Crudites\Row;
0 ignored issues
show
Bug introduced by
The type HexMakina\Crudites\Row 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...
9
use HexMakina\BlackBox\Database\SelectInterface;
10
11
abstract class TableModel extends Crudites
12
{
13
14
    private SchemaInterface $schema;
15
    private string $table;
16
17
    
18
    //check all primary keys are set (FIXME that doesn't work unles AIPK.. nice try)
19
    public function isNew(): bool
20
    {
21
        $match = static::table()->primaryKeysMatch(get_object_vars($this));
22
        return empty($match);
23
    }
24
25
    public function getId($mode = null)
26
    {
27
        $primary_key = $this->schema->autoIncrementedPrimaryKey(static::table());
28
        if (is_null($primary_key) && count($pks = static::table()->primaryKeys()) == 1) {
29
            $primary_key = current($pks);
30
        }
31
32
        return $mode === 'name' ? $primary_key->name() : $this->get($primary_key->name());
33
    }
34
35
    public function pk()
36
    {
37
        $primary_key = static::table()->autoIncrementedPrimaryKey();
38
        if (is_null($primary_key) && count($pks = static::table()->primaryKeys()) == 1) {
39
            $primary_key = current($pks);
40
        }
41
42
        return $this->get($primary_key->name());
43
    }
44
45
    public function id()
46
    {
47
        return $this->get('id');
48
    }
49
50
    public function get($prop_name)
51
    {
52
        if (property_exists($this, $prop_name)) {
53
            return $this->$prop_name;
54
        }
55
56
        return null;
57
    }
58
59
    public function set($prop_name, $value): void
60
    {
61
        $this->$prop_name = $value;
62
    }
63
64
    public function import($assoc_data): self
65
    {
66
        if (!is_array($assoc_data)) {
67
            throw new \Exception(__FUNCTION__ . '(assoc_data) parm is not an array');
68
        }
69
70
        // shove it all up in model, god will sort them out
71
        foreach ($assoc_data as $field => $value) {
72
            $this->set($field, $value);
73
        }
74
75
        return $this;
76
    }
77
78
79
80
    // relational mapping
81
    public static function table(): string
82
    {
83
        $reflectionClass = new \ReflectionClass(get_called_class());
84
        $called_class = new \ReflectionClass(get_called_class());
0 ignored issues
show
Unused Code introduced by
The assignment to $called_class is dead and can be removed.
Loading history...
85
86
        $table_name = $reflectionClass->getConstant('TABLE_NAME');
87
88
        if ($table_name === false) {
89
            $shortName = $reflectionClass->getShortName();
90
            $table_name = defined($const_name = 'TABLE_' . strtoupper($shortName)) ? constant($const_name) : strtolower($shortName);
91
        }
92
93
        return $table_name;
94
        $table_name = $called_class->getConstant('TABLE_NAME');
0 ignored issues
show
Unused Code introduced by
$table_name = $called_cl...tConstant('TABLE_NAME') is not reachable.

This check looks for unreachable code. It uses sophisticated control flow analysis techniques to find statements which will never be executed.

Unreachable code is most often the result of return, die or exit statements that have been added for debug purposes.

function fx() {
    try {
        doSomething();
        return true;
    }
    catch (\Exception $e) {
        return false;
    }

    return false;
}

In the above example, the last return false will never be executed, because a return statement has already been met in every possible execution path.

Loading history...
95
        if($table_name !== false)
96
            return $table_name;
97
98
        $class_name = $called_class->getShortName();
99
        
100
        if (defined($const_name = 'TABLE_' . strtoupper($class_name)))
101
            return constant($const_name);
102
        
103
        return strtolower($class_name);
104
    }
105
106
    public function to_table_row($operator_id = null)
107
    {
108
        if (!is_null($operator_id) && $this->isNew() && is_null($this->get('created_by'))) {
109
            $this->set('created_by', $operator_id);
110
        }
111
112
        $model_data = get_object_vars($this);
113
114
        if($this->isNew()){
115
            // $table_row = new Row($this, $model_data);
116
            $table_row = new Row($this->schema, static::table(), $model_data);
117
        }
118
        else{
119
            $table_row = new Row($this->schema);
120
            $table_row->load($model_data);
121
        }
122
        // 1. Produce OR restore a row
123
124
        // 2. Apply alterations from form_model data
125
        $table_row->alter($model_data);
126
127
        return $table_row;
128
    }
129
130
    // success: return PK-indexed array of results (associative array or object)
131
    public static function retrieve(SelectInterface $select): array
132
    {
133
        $ret = [];
134
        $pk_name = implode('_', array_keys($select->table()->primaryKeys()));
135
136
        if (count($pks = $select->table()->primaryKeys()) > 1) {
137
            $concat_pk = sprintf('CONCAT(%s) as %s', implode(',', $pks), $pk_name);
138
            $select->selectAlso([$concat_pk]);
139
        }
140
141
        try {
142
            $select->run();
143
        } catch (CruditesException $e) {
144
            return [];
145
        }
146
147
        if ($select->isSuccess()) {
148
            foreach ($select->retObj(get_called_class()) as $rec) {
149
                $ret[$rec->get($pk_name)] = $rec;
150
            }
151
        }
152
153
        return $ret;
154
    }
155
156
157
    private static function actionnableParams($arg1, $arg2 = null): array
158
    {
159
        $unique_identifiers = null;
160
        
161
        $table = get_called_class()::table();
162
163
        // case 3
164
        if(is_array($arg1) && !empty($arg1))
165
        {
166
            $unique_identifiers = $arg1;
167
        }
168
169
        // case 2
170
        else if (is_string($arg1) && is_scalar($arg2))
171
        {   
172
            $unique_identifiers = [$arg1 => $arg2];
173
        }
174
175
        // case 1
176
        else if (is_scalar($arg1) && count($table->primaryKeys()) === 1)
177
        {   
178
            $pk = current($table->primaryKeys())->name();
179
            $unique_identifiers = [$pk => $arg1];
180
        } 
181
        else
182
            throw new CruditesException('ARGUMENTS_ARE_NOT_ACTIONNABLE');
183
184
185
        // Find the unique identifier(s) in the database.
186
        $unique_identifiers = $table->matchUniqueness($unique_identifiers);
187
        if (empty($unique_identifiers)) {
188
            throw new CruditesException('UNIQUE_IDENTIFIER_NOT_FOUND');
189
        }
190
191
        return $unique_identifiers;
192
    }
193
194
195
    /**
196
     * Retrieve a single instance of the model by its unique identifier(s).
197
     * Throws CruditesException if the unique identifier yields no or multiple instances.
198
     *
199
     * @param mixed $arg1 The value of the primary key or an array of column-value pairs.
200
     * @param mixed|null $arg2 The value of the primary key if $arg1 is a string, otherwise null.
201
     * 
202
     * @return mixed The retrieved instance of the model.
203
     * 
204
     * @throws CruditesException If the arguments are not actionable, the unique identifier is not found, or multiple instances are found.
205
     * 
206
     * USAGE
207
     *  Case 1:  Class::one($primary_key_value)
208
     *  Case 2:  Class::one($unique_column, $value)
209
     *  Case 3:  Class::one([$unique_column => $value, $unique_column2 => $value2])
210
     * 
211
     */
212
    public static function one($arg1, $arg2 = null): self
213
    {
214
        $unique_identifiers = static::actionnableParams($arg1, $arg2);
215
        // vd($arg1, 'arg1');
216
        // vd($arg2, 'arg2');
217
        // vd($unique_identifiers, static::class);
218
219
        $records = static::any($unique_identifiers);
220
        switch (count($records)) {
221
            case 0:
222
                throw new CruditesException('NO_INSTANCE_MATCH_UNIQUE_IDENTIFIERS');
223
224
            case 1:
225
                return current($records);
226
227
            default:
228
                throw new CruditesException('MULTIPLE_INSTANCES_MATCH_UNIQUE_IDENTIFIERS');
229
        }
230
    }
231
232
    /**
233
     * Attempts to retrieve a single instance of the model by its unique identifier(s).
234
     * If no instance is found, returns null.
235
     */
236
237
    public static function exists($arg1, $arg2 = null): ?self
238
    {
239
        try {
240
            return self::one($arg1, $arg2);
241
        } 
242
        catch (CruditesException $e) {
243
            return null;
244
        }
245
    }
246
247
    public static function any($field_exact_values=[], $options = [])
248
    {
249
        $select = static::filter($field_exact_values, $options);
250
        return static::retrieve($select);
251
    }
252
253
    
254
    public static function filter($filters = [], $options = []): SelectInterface
255
    {
256
        $query = (new TableModelSelector(get_called_class()))->select($filters, $options);
257
        return $query;
258
259
        // $query = static::query_retrieve($filters, $options);
260
        // return static::retrieve($query);
261
    }
262
263
    public static function count($filters = [], $options = []): int
0 ignored issues
show
Unused Code introduced by
The parameter $options is not used and could be removed. ( Ignorable by Annotation )

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

263
    public static function count($filters = [], /** @scrutinizer ignore-unused */ $options = []): int

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
264
    {
265
        $query = static::filter($filters, ['eager' => false]);
266
        $query->columns(['COUNT(*) as counter']);
267
        $res = static::retrieve($query);
268
        $res = array_pop($res);
269
        return (int)$res->counter;
270
    }
271
272
    public static function listing($filters = [], $options = []): array
273
    {
274
        return static::retrieve(static::filter($filters, $options)); // listing as arrays for templates
275
    }
276
277
278
279
    public static function get_many_by_AIPK($aipk_values): ?array
280
    {
281
        if (empty($aipk_values)) {
282
            return null;
283
        }
284
        if (is_null($AIPK = static::table()->autoIncrementedPrimaryKey())) {
285
            return null;
286
        }
287
        return static::retrieve(static::table()->select()->whereNumericIn($AIPK, $aipk_values));
288
    }
289
}
290