Completed
Push — feature/controller ( a5988d...b3a825 )
by René
03:15
created

Table::findAll()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 7
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 1

Importance

Changes 2
Bugs 0 Features 0
Metric Value
c 2
b 0
f 0
dl 0
loc 7
ccs 4
cts 4
cp 1
rs 9.4285
cc 1
eloc 4
nc 1
nop 0
crap 1
1
<?php
2
declare(strict_types = 1);
3
4
namespace Zortje\MVC\Model\Table;
5
6
use Zortje\MVC\Model\SQLCommand;
7
use Zortje\MVC\Model\Table\Entity\Entity;
8
use Zortje\MVC\Model\Table\Entity\EntityFactory;
9
use Zortje\MVC\Model\Table\Entity\Exception\EntityClassNonexistentException;
10
use Zortje\MVC\Model\Table\Entity\Exception\EntityClassNotDefinedException;
11
use Zortje\MVC\Model\Table\Entity\Exception\InvalidEntityPropertyException;
12
use Zortje\MVC\Model\Table\Exception\TableNameNotDefinedException;
13
14
/**
15
 * Class Table
16
 *
17
 * @package Zortje\MVC\Model\Table
18
 */
19
abstract class Table
20
{
21
22
    /**
23
     * @var \PDO Connection
24
     */
25
    protected $pdo;
26
27
    /**
28
     * @var string Table name
29
     */
30
    protected $tableName;
31
32
    /**
33
     * @var String Entity class
34
     */
35
    protected $entityClass;
36
37
    /**
38
     * @var SQLCommand SQL Command
39
     */
40
    protected $sqlCommand;
41
42
    /**
43
     * @param \PDO $pdo
44
     *
45
     * @throws TableNameNotDefinedException If table name is not defined in subclass
46
     * @throws EntityClassNotDefinedException If entity class is not defined in subclass
47
     * @throws EntityClassNonexistentException If entity class is nonexistent
48
     */
49 1
    public function __construct(\PDO $pdo)
50
    {
51 1
        if ($this->tableName === null) {
52
            throw new TableNameNotDefinedException([get_class($this)]);
53
        }
54
55 1
        if ($this->entityClass === null) {
56
            throw new EntityClassNotDefinedException([get_class($this)]);
57 1
        } elseif (!class_exists($this->entityClass)) {
58
            throw new EntityClassNonexistentException([get_class($this), $this->entityClass]);
59
        }
60
61
        // @todo should check if `$this->entityClass` is subclass of Entity class
62
63 1
        $this->pdo = $pdo;
64
65 1
        $this->sqlCommand = $this->createCommand();
66 1
    }
67
68
    /**
69
     * Get table name
70
     *
71
     * @return string Table name
72
     */
73 1
    public function getTableName(): string
74
    {
75 1
        return $this->tableName;
76
    }
77
78
    /**
79
     * Find all entities
80
     *
81
     * @return Entity[] Entities
82
     */
83 1
    public function findAll(): array
84
    {
85 1
        $stmt = $this->pdo->prepare($this->sqlCommand->selectFrom());
86 1
        $stmt->execute();
87
88 1
        return $this->createEntitiesFromStatement($stmt);
89
    }
90
91
    /**
92
     * Find all entities where key is equal to the given value
93
     *
94
     * @param string $key   Entity key
95
     * @param string $value Value to search for
96
     *
97
     * @throws InvalidEntityPropertyException If entity does not have that property
98
     *
99
     * @return Entity[] Entities
100
     */
101 3
    public function findBy(string $key, string $value): array
102
    {
103
        /**
104
         * Check if entity have the property
105
         */
106 3
        $reflector = new \ReflectionClass($this->entityClass);
107
108 3
        $entity = $reflector->newInstanceWithoutConstructor();
109
110 3
        if (!isset($entity::getColumns()[$key])) {
111 1
            throw new InvalidEntityPropertyException([$this->entityClass, $key]);
112
        }
113
114
        /**
115
         * Execute with key-value condition
116
         */
117 2
        $stmt = $this->pdo->prepare($this->sqlCommand->selectFromWhere([$key]));
118 2
        $stmt->execute([":$key" => $value]);
119
120 2
        return $this->createEntitiesFromStatement($stmt);
121
    }
122
123
    /**
124
     * Insert entity into database
125
     *
126
     * @param Entity $entity Entity object
127
     *
128
     * @return int Inserted entity ID
129
     */
130 1
    public function insert(Entity $entity): int
131
    {
132 1
        $stmt = $this->pdo->prepare($this->sqlCommand->insertInto());
133
134 1
        $now = (new \DateTime())->format('Y-m-d H:i:s');
135
136 1
        $array = array_merge($entity->toArray(false), [
137 1
            'modified' => $now,
138 1
            'created'  => $now
139
        ]);
140
141 1
        $stmt->execute($array);
142
143 1
        return (int)$this->pdo->lastInsertId();
144
    }
145
146
    /**
147
     * Update entity in the database
148
     *
149
     * @param Entity $entity Entity object
150
     *
151
     * @return bool True if row was affected, otherwise false
152
     */
153 1
    public function update(Entity $entity): bool
154
    {
155 1
        if ($entity->isAltered()) {
156
            /**
157
             * Set modified to now
158
             */
159 1
            $entity->set('modified', new \DateTime());
160
161
            /**
162
             * Get altered columns for SQL command
163
             */
164 1
            $alteredColumns = array_keys($entity->getAlteredColumns());
165
166 1
            $stmt = $this->pdo->prepare($this->sqlCommand->updateSetWhere($alteredColumns));
167
168
            /**
169
             * Execute with altered array
170
             */
171 1
            $stmt->execute($entity->alteredToArray(true));
172
173
            // @todo return true if row is altered
174
        }
175
176 1
        return false;
177
    }
178
179
    public function delete(Entity $entity)
0 ignored issues
show
Unused Code introduced by
The parameter $entity is not used and could be removed.

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

Loading history...
180
    {
181
        // @todo Implement
182
    }
183
184
    /**
185
     * Creates an array of Entity objects from statement
186
     *
187
     * @param \PDOStatement $statement
188
     *
189
     * @return Entity[] Entities from statement
190
     */
191
    protected function createEntitiesFromStatement(\PDOStatement $statement): array
192
    {
193
        $entities = [];
194
195
        $entityFactory = new EntityFactory($this->entityClass);
196
197
        foreach ($statement as $row) {
198
            $entities[] = $entityFactory->createFromArray($row);
199
        }
200
201
        return $entities;
202
    }
203
204
    /**
205
     * Create SQLCommand for this Table with provided Entity
206
     *
207
     * @return SQLCommand
208
     */
209
    protected function createCommand(): SQLCommand
210
    {
211
        $reflector = new \ReflectionClass($this->entityClass);
212
213
        $entity = $reflector->newInstanceWithoutConstructor();
214
215
        $columns = $entity::getColumns();
216
217
        return new SQLCommand($this->tableName, $columns);
218
    }
219
}
220