Test Failed
Push — master ( 43de38...354148 )
by Rafael
13:26 queued 10s
created

FlatTable::insertRecord()   A

Complexity

Conditions 4
Paths 6

Size

Total Lines 33
Code Lines 21

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 4
eloc 21
nc 6
nop 1
dl 0
loc 33
rs 9.584
c 0
b 0
f 0
1
<?php
2
/**
3
 * Alxarafe. Development of PHP applications in a flash!
4
 * Copyright (C) 2018-2019 Alxarafe <[email protected]>
5
 */
6
7
namespace Alxarafe\Core\Base;
8
9
use Alxarafe\Core\Providers\Database;
10
11
/**
12
 * Class SimpleTable has all the basic methods to access and manipulate information, but without modifying its
13
 * structure.
14
 */
15
class FlatTable extends Entity
16
{
17
    /**
18
     * It is the name of the table.
19
     *
20
     * @var string
21
     */
22
    public $tableName;
23
24
    /**
25
     * It's the name of the model associated with the table
26
     *
27
     * @var string
28
     */
29
    public $modelName;
30
31
    /**
32
     * Build a Table model. $table is the name of the table in the database.
33
     * $params is a parameters array:
34
     * - create is true if the table is to be created if it does not exist (false by default)
35
     * - idField is the name of the primary key (default id)
36
     * - nameField is the name of the descriptive field (name by default)
37
     *
38
     * @param string $tableName
39
     * @param array $params
40
     */
41
    public function __construct(string $tableName, array $params = [])
42
    {
43
        parent::__construct();
44
        $this->modelName = $this->shortName;
45
        $this->debugTool->startTimer($this->modelName . '.flat', $this->modelName . ' FlatTable Constructor');
46
        $this->tableName = $tableName;
47
        $this->idField = $params['idField'] ?? 'id';
48
        $this->nameField = $params['nameField'] ?? 'name';
49
        $this->debugTool->stopTimer($this->modelName . '.flat');
50
    }
51
52
    /**
53
     * This method is private. Use load instead.
54
     * Establishes a record as an active record.
55
     * If found, return true and the $id will be in $this->id and the data in $this->newData.
56
     * If it is not found, return false, and have not effect into the instance.
57
     *
58
     * @param string $id
59
     *
60
     * @return bool
61
     */
62
    private function getDataById(string $id): bool
63
    {
64
        $sql = "SELECT * FROM {$this->getQuotedTableName()} WHERE {$this->idField} = :id;";
65
        $data = Database::getInstance()->getDbEngine()->select($sql, ['id' => $id]);
66
        if (!isset($data) || count($data) === 0) {
67
            $this->exists = false;
68
            return false;
69
        }
70
        $this->exists = true;
71
        $this->newData = $data[0];
72
        $this->oldData = $this->newData;
73
        $this->id = $this->newData[$this->idField];
74
        return true;
75
    }
76
77
    /**
78
     * Get the name of the table (with prefix)
79
     *
80
     * @param bool $usePrefix
81
     *
82
     * @return string
83
     */
84
    public function getQuotedTableName(bool $usePrefix = true): string
85
    {
86
        return Database::getInstance()->getSqlHelper()->quoteTableName($this->tableName, $usePrefix);
87
    }
88
89
    public function defaultData()
90
    {
91
        return [];
92
    }
93
94
    /**
95
     * Sets the active record in a new record.
96
     * Note that changes made to the current active record will be lost.
97
     */
98
    public function newRecord(?string $id = null): void
99
    {
100
        if (isset($id) && $this->getDataById($id)) {
101
            return;
102
        }
103
        $this->exists = false;
104
        $this->newData = $this->defaultData();
105
        $this->oldData = $this->newData;
106
        $this->id = $id;
107
    }
108
109
    /**
110
     * Returns a new instance of the table with the requested record.
111
     * As a previous step, a getData of the current instance is made, so both will point to the same record.
112
     * Makes a getData and returns a new instance of the model.
113
     *
114
     * @param string $id
115
     *
116
     * @return SimpleTable
117
     */
118
    public function get(string $id): self
119
    {
120
        if (!$this->getDataById($id)) {
121
            $this->newRecord($id);
122
        }
123
        $this->id = $id;
124
        return $this;
125
    }
126
127
    /**
128
     * Get the name of the table (with prefix)
129
     *
130
     * @param bool $usePrefix
131
     *
132
     * @return string
133
     */
134
    public function getTableName(bool $usePrefix = true): string
135
    {
136
        return ($usePrefix ? Database::getInstance()->getConnectionData()['dbPrefix'] : '') . $this->tableName;
137
    }
138
139
    /**
140
     * Return an array with the current active record.
141
     * If an $id is indicated, it searches to change the active record before returning the value.
142
     * Warning: If an $id is set, any unsaved data will be lost when searching for the new record.
143
     *
144
     * @param string $id
145
     *
146
     * @return array
147
     */
148
    public function getDataArray(string $id = null): array
149
    {
150
        if (isset($id) && ($id !== $this->id)) {
151
            $this->getDataById($id);
152
        }
153
        return $this->newData;
154
    }
155
156
    /**
157
     * Establishes a record as an active record.
158
     * If found, the $id will be in $this->id and the data in $this->newData.
159
     * If it is not found, $this->id will contain '' and $this->newData will contain the data by default.
160
     *
161
     * @param string $id
162
     *
163
     * @return bool
164
     */
165
    public function load(string $id): bool
166
    {
167
        return $this->getDataById($id);
168
    }
169
170
    /**
171
     * Saves the changes made to the active record.
172
     *
173
     * @return bool
174
     */
175
    public function save(): bool
176
    {
177
        $values = [];
178
        // We create separate arrays with the modified fields
179
        foreach ($this->newData as $field => $data) {
180
            // The first condition is to prevent nulls from becoming empty strings
181
            if ((!isset($this->oldData[$field]) && isset($this->newData[$field])) || $this->newData[$field] !== $this->oldData[$field]) {
182
                $values[$field] = $data;
183
            }
184
        }
185
186
        // If there are no modifications, we leave without error.
187
        if (count($values) === 0) {
188
            return true;
189
        }
190
191
        // Insert or update the data as appropriate (insert if $this->id == '')
192
        $ret = ($this->exists) ? $this->updateRecord($values) : $this->insertRecord($values);
193
        if ($ret) {
194
            // $this->id = $this->newData[$this->idField] ?? null;
195
            $this->oldData = $this->newData;
196
        }
197
        return $ret;
198
    }
199
200
    /**
201
     * Insert a new record.
202
     * $fields is an array of fields and $values an array with the values for each field in the same order.
203
     *
204
     * @param array $values
205
     *
206
     * @return bool
207
     */
208
    private function insertRecord($values): bool
209
    {
210
        $fieldNames = [];
211
        $fieldVars = [];
212
        $vars = [];
213
214
        foreach ($values as $fieldName => $value) {
215
            $fieldNames[$fieldName] = Database::getInstance()->getSqlHelper()->quoteFieldName($fieldName);
216
            $fieldVars[$fieldName] = ':' . $fieldName;
217
            $vars[$fieldName] = $value;
218
        }
219
220
        if (isset($this->id)) {
221
            if ($this->id == '') {
222
                echo "<p><strong>Cuidado</strong>: Se está usando espacio en el id en FlatTable.insertRecord</p>";
223
                var_dump($this);
0 ignored issues
show
Security Debugging Code introduced by
var_dump($this) looks like debug code. Are you sure you do not want to remove it?
Loading history...
224
                die;
0 ignored issues
show
Bug Best Practice introduced by
In this branch, the function will implicitly return null which is incompatible with the type-hinted return boolean. Consider adding a return statement or allowing null as return value.

For hinted functions/methods where all return statements with the correct type are only reachable via conditions, ?null? gets implicitly returned which may be incompatible with the hinted type. Let?s take a look at an example:

interface ReturnsInt {
    public function returnsIntHinted(): int;
}

class MyClass implements ReturnsInt {
    public function returnsIntHinted(): int
    {
        if (foo()) {
            return 123;
        }
        // here: null is implicitly returned
    }
}
Loading history...
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
225
            }
226
            $fieldNames[] = $this->getIdField();
227
            $fieldVars[] = ':id';
228
            $vars['id'] = $this->id;
229
        }
230
231
        $fieldList = implode(', ', $fieldNames);
232
        $valueList = implode(', ', $fieldVars);
233
234
        $sql = "INSERT INTO {$this->getQuotedTableName()} ($fieldList) VALUES ($valueList);";
235
        $this->exists = Database::getInstance()->getDbEngine()->exec($sql, $vars);
236
237
        // Assign the value of the primary key of the newly inserted record
238
        $this->id = Database::getInstance()->getDbEngine()->getLastInserted();
239
240
        return $this->exists;
241
    }
242
243
    /**
244
     * Update the modified fields in the active record.
245
     * $data is an array of assignments of type field=value.
246
     *
247
     * @param array $data
248
     *
249
     * @return bool
250
     */
251
    private function updateRecord(array $data): bool
252
    {
253
        $fieldNames = [];
254
        $vars = [];
255
        foreach ($data as $fieldName => $value) {
256
            $fieldNames[] = Database::getInstance()->getSqlHelper()->quoteFieldName($fieldName) . " = :" . $fieldName;
257
            $vars[$fieldName] = $value;
258
        }
259
260
        $fieldList = implode(', ', $fieldNames);
261
262
        $idField = Database::getInstance()->getSqlHelper()->quoteFieldName($this->idField);
263
        $sql = "UPDATE {$this->getQuotedTableName()} SET {$fieldList} WHERE {$idField} = :id;";
264
265
        $vars['id'] = $this->id;
266
267
        return Database::getInstance()->getDbEngine()->exec($sql, $vars);
268
    }
269
270
    /**
271
     * Deletes the active record.
272
     *
273
     * @return bool
274
     */
275
    public function delete(): bool
276
    {
277
        if (empty($this->id)) {
278
            return false;
279
        }
280
        $idField = Database::getInstance()->getSqlHelper()->quoteFieldName($this->idField);
281
        $sql = "DELETE FROM {$this->getQuotedTableName()} WHERE {$idField} = :id;";
282
        $vars = [];
283
        $vars['id'] = $this->id;
284
        $result = Database::getInstance()->getDbEngine()->exec($sql, $vars);
285
        if ($result) {
286
            $this->id = null;
287
            $this->newData = null;
288
            $this->oldData = null;
289
        }
290
        return $result;
291
    }
292
293
}
294