Completed
Push — master ( c04903...bcc15f )
by Oscar
02:37
created

SimpleCrud::setAttribute()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 10
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

Changes 3
Bugs 1 Features 0
Metric Value
c 3
b 1
f 0
dl 0
loc 10
rs 9.4285
cc 2
eloc 6
nc 2
nop 2
1
<?php
2
3
namespace SimpleCrud;
4
5
use Exception;
6
use PDO;
7
8
class SimpleCrud
9
{
10
    const ATTR_LOCALE = 'simplecrud.language';
11
    const ATTR_UPLOADS = 'simplecrud.uploads';
12
13
    protected $connection;
14
    protected $scheme;
15
    protected $tables = [];
16
    protected $inTransaction = false;
17
    protected $attributes = [];
18
    protected $onExecute;
19
20
    protected $tableFactory;
21
    protected $queryFactory;
22
    protected $fieldFactory;
23
24
    /**
25
     * Set the connection and the tableFactory.
26
     *
27
     * @param PDO $connection
28
     */
29
    public function __construct(PDO $connection)
30
    {
31
        $this->connection = $connection;
32
        $this->connection->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
33
    }
34
35
    /**
36
     * Set the database scheme.
37
     * 
38
     * @param array $scheme
39
     * 
40
     * @return self
41
     */
42
    public function setScheme(array $scheme)
43
    {
44
        $this->scheme = $scheme;
45
46
        return $this;
47
    }
48
49
    /**
50
     * Returns the database scheme.
51
     * 
52
     * @return array
53
     */
54
    public function getScheme()
55
    {
56
        if ($this->scheme === null) {
57
            $class = 'SimpleCrud\\Scheme\\'.ucfirst($this->getAttribute(PDO::ATTR_DRIVER_NAME));
58
59
            if (!class_exists($class)) {
60
                throw new SimpleCrudException(sprintf('Scheme class "%s" not found', $class));
61
            }
62
63
            $factory = new $class($this);
64
65
            $this->setScheme($factory());
66
        }
67
68
        return $this->scheme;
69
    }
70
71
    /**
72
     * Define a callback executed for each query executed
73
     *
74
     * @param callable|null $callback
75
     */
76
    public function onExecute(callable $callback = null)
77
    {
78
        $this->onExecute = $callback;
79
    }
80
81
    /**
82
     * Set the TableFactory instance used to create all tables.
83
     *
84
     * @param TableFactory $tableFactory
85
     * 
86
     * @return self
87
     */
88
    public function setTableFactory(TableFactory $tableFactory)
89
    {
90
        $this->tableFactory = $tableFactory;
91
92
        return $this;
93
    }
94
95
    /**
96
     * Returns the TableFactory instance used.
97
     *
98
     * @return TableFactory
99
     */
100
    public function getTableFactory()
101
    {
102
        if ($this->tableFactory === null) {
103
            return $this->tableFactory = (new TableFactory())->setAutocreate();
104
        }
105
106
        return $this->tableFactory;
107
    }
108
109
    /**
110
     * Set the QueryFactory instance used by the tables.
111
     *
112
     * @param QueryFactory $queryFactory
113
     *
114
     * @return self
115
     */
116
    public function setQueryFactory(QueryFactory $queryFactory)
117
    {
118
        $this->queryFactory = $queryFactory;
119
120
        return $this;
121
    }
122
123
    /**
124
     * Returns the QueryFactory instance used by the tables.
125
     *
126
     * @return QueryFactory
127
     */
128
    public function getQueryFactory()
129
    {
130
        if ($this->queryFactory === null) {
131
            $queryFactory = new QueryFactory();
132
            $queryFactory->addNamespace('SimpleCrud\\Queries\\'.ucfirst($this->getAttribute(PDO::ATTR_DRIVER_NAME)).'\\');
133
134
            return $this->queryFactory = $queryFactory;
135
        }
136
137
        return $this->queryFactory;
138
    }
139
140
    /**
141
     * Set the FieldFactory instance used by the tables.
142
     *
143
     * @param FieldFactory $fieldFactory
144
     *
145
     * @return self
146
     */
147
    public function setFieldFactory(FieldFactory $fieldFactory)
148
    {
149
        $this->fieldFactory = $fieldFactory;
150
151
        return $this;
152
    }
153
154
    /**
155
     * Returns the FieldFactory instance used by the tables.
156
     *
157
     * @return FieldFactory
158
     */
159
    public function getFieldFactory()
160
    {
161
        if ($this->fieldFactory === null) {
162
            return $this->fieldFactory = new FieldFactory();
163
        }
164
165
        return $this->fieldFactory;
166
    }
167
168
    /**
169
     * Magic method to initialize the tables in lazy mode.
170
     *
171
     * @param string $name The table name
172
     *
173
     * @throws SimpleCrudException If the table cannot be instantiated
174
     *
175
     * @return Table
176
     */
177
    public function __get($name)
178
    {
179
        if (isset($this->tables[$name])) {
180
            return $this->tables[$name];
181
        }
182
183
        return $this->tables[$name] = $this->getTableFactory()->get($this, $name);
184
    }
185
186
    /**
187
     * Magic method to check if a table exists or not.
188
     *
189
     * @param string $name
190
     *
191
     * @return bool
192
     */
193
    public function __isset($name)
194
    {
195
        return isset($this->getScheme()[$name]);
196
    }
197
198
    /**
199
     * Execute a query and returns the statement object with the result.
200
     *
201
     * @param string $query The Mysql query to execute
202
     * @param array  $marks The marks passed to the statement
203
     *
204
     * @throws Exception On error preparing or executing the statement
205
     *
206
     * @return PDOStatement The result
207
     */
208
    public function execute($query, array $marks = null)
209
    {
210
        $query = (string) $query;
211
212
        if (!empty($marks)) {
213
            foreach ($marks as $name => $mark) {
214
                if (is_array($mark)) {
215
                    foreach ($mark as &$val) {
216
                        $val = $this->connection->quote($val);
217
                    }
218
219
                    $query = str_replace($name, implode(', ', $mark), $query);
220
                    unset($marks[$name]);
221
                }
222
            }
223
224
            if (empty($marks)) {
225
                $marks = null;
226
            }
227
        }
228
229
        $statement = $this->connection->prepare($query);
230
        $statement->execute($marks);
231
232
        if ($this->onExecute !== null) {
233
            call_user_func($this->onExecute, $this->connection, $statement, $marks);
234
        }
235
236
        return $statement;
237
    }
238
239
    /**
240
     * Execute a callable inside a transaction.
241
     *
242
     * @param callable $callable The function with all operations
243
     *
244
     * @return mixed The callable returned value
245
     */
246
    public function executeTransaction(callable $callable)
247
    {
248
        try {
249
            $transaction = $this->beginTransaction();
250
251
            $return = $callable($this);
252
253
            if ($transaction) {
254
                $this->commit();
255
            }
256
        } catch (Exception $exception) {
257
            if ($transaction) {
258
                $this->rollBack();
259
            }
260
261
            throw $exception;
262
        }
263
264
        return $return;
265
    }
266
267
    /**
268
     * Returns the last insert id.
269
     *
270
     * @return string
271
     */
272
    public function lastInsertId()
273
    {
274
        return $this->connection->lastInsertId();
275
    }
276
277
    /**
278
     * Starts a transaction if it's not started yet.
279
     *
280
     * @return bool True if a the transaction is started or false if don't
281
     */
282
    public function beginTransaction()
283
    {
284
        if (!$this->inTransaction()) {
285
            $this->connection->beginTransaction();
286
287
            return $this->inTransaction = true;
288
        }
289
290
        return false;
291
    }
292
293
    /**
294
     * Commits the changes of the transaction to the database.
295
     */
296
    public function commit()
297
    {
298
        if ($this->inTransaction()) {
299
            $this->connection->commit();
300
            $this->inTransaction = false;
301
        }
302
    }
303
304
    /**
305
     * RollBack a transaction.
306
     */
307
    public function rollBack()
308
    {
309
        if ($this->inTransaction()) {
310
            $this->connection->rollBack();
311
            $this->inTransaction = false;
312
        }
313
    }
314
315
    /**
316
     * Check if there is a transaction opened currently in this adapter.
317
     */
318
    public function inTransaction()
319
    {
320
        return ($this->inTransaction === true) && ($this->connection->inTransaction() === true);
321
    }
322
323
    /**
324
     * Saves a new attribute.
325
     *
326
     * @param string $name
327
     * @param mixed  $value
328
     *
329
     * @return $this
330
     */
331
    public function setAttribute($name, $value)
332
    {
333
        if (is_int($name)) {
334
            $this->connection->setAttribute($name, $value);
335
        } else {
336
            $this->attributes[$name] = $value;
337
        }
338
339
        return $this;
340
    }
341
342
    /**
343
     * Returns an attribute.
344
     *
345
     * @param string|int $name
346
     *
347
     * @return null|mixed
348
     */
349
    public function getAttribute($name)
350
    {
351
        if (is_int($name)) {
352
            return $this->connection->getAttribute($name);
353
        }
354
355
        return isset($this->attributes[$name]) ? $this->attributes[$name] : null;
356
    }
357
}
358