Completed
Pull Request — master (#2)
by René
02:13
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 0
Metric Value
dl 0
loc 7
ccs 4
cts 4
cp 1
rs 9.4285
c 0
b 0
f 0
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\EntityProperty;
10
use Zortje\MVC\Model\Table\Entity\Exception\EntityClassNonexistentException;
11
use Zortje\MVC\Model\Table\Entity\Exception\EntityClassNotDefinedException;
12
use Zortje\MVC\Model\Table\Entity\Exception\InvalidEntityPropertyException;
13
use Zortje\MVC\Model\Table\Exception\TableNameNotDefinedException;
14
15
/**
16
 * Class Table
17
 *
18
 * @package Zortje\MVC\Model\Table
19
 */
20
abstract class Table
21
{
22
23
    /**
24
     * @var \PDO Connection
25
     */
26
    protected $pdo;
27
28
    /**
29
     * @var string Table name
30
     */
31
    protected $tableName;
32
33
    /**
34
     * @var String Entity class
35
     */
36
    protected $entityClass;
37
38
    /**
39
     * @var SQLCommand SQL Command
40
     */
41
    protected $sqlCommand;
42
43
    /**
44
     * @param \PDO $pdo
45
     *
46
     * @throws TableNameNotDefinedException If table name is not defined in subclass
47
     * @throws EntityClassNotDefinedException If entity class is not defined in subclass
48
     * @throws EntityClassNonexistentException If entity class is nonexistent
49
     */
50 1
    public function __construct(\PDO $pdo)
51
    {
52 1
        if ($this->tableName === null) {
53
            throw new TableNameNotDefinedException([get_class($this)]);
54
        }
55
56 1
        if ($this->entityClass === null) {
57
            throw new EntityClassNotDefinedException([get_class($this)]);
58 1
        } elseif (!class_exists($this->entityClass)) {
59
            throw new EntityClassNonexistentException([get_class($this), $this->entityClass]);
60
        }
61
62
        // @todo should check if `$this->entityClass` is subclass of Entity class
63
64 1
        $this->pdo = $pdo;
65
66 1
        $this->sqlCommand = $this->createCommand();
67 1
    }
68
69
    /**
70
     * Get table name
71
     *
72
     * @return string Table name
73
     */
74 1
    public function getTableName(): string
75
    {
76 1
        return $this->tableName;
77
    }
78
79
    /**
80
     * Find all entities
81
     *
82
     * @return Entity[] Entities
83
     */
84 1
    public function findAll(): array
85
    {
86 1
        $stmt = $this->pdo->prepare($this->sqlCommand->selectFrom());
87 1
        $stmt->execute();
88
89 1
        return $this->createEntitiesFromStatement($stmt);
90
    }
91
92
    /**
93
     * Find all entities where key is equal to the given value
94
     *
95
     * @param string $key   Entity key
96
     * @param mixed  $value Value to search for
97
     *
98
     * @throws InvalidEntityPropertyException If entity does not have that property
99
     *
100
     * @return Entity[] Entities
101
     */
102 4
    public function findBy(string $key, $value): array
103
    {
104
        /**
105
         * Check if entity have the property
106
         *
107
         * @var Entity $entity
108
         */
109 4
        $reflector = new \ReflectionClass($this->entityClass);
110
111 4
        $entity = $reflector->newInstanceWithoutConstructor();
112
113 4
        if (!isset($entity::getColumns()[$key])) {
114 1
            throw new InvalidEntityPropertyException([$this->entityClass, $key]);
115
        }
116
117
        /**
118
         * Validate value
119
         */
120 3
        $entityProperty = new EntityProperty($entity::getColumns()[$key]);
121
122 3
        if ($entityProperty->validateValue($value)) {
123
            /**
124
             * Execute with key-value condition
125
             */
126 2
            $stmt = $this->pdo->prepare($this->sqlCommand->selectFromWhere([$key]));
127 2
            $stmt->execute([":$key" => $value]);
128
129 2
            return $this->createEntitiesFromStatement($stmt);
130
        }
131
132
        return [];
133
    }
134
135
    /**
136
     * Insert entity into database
137
     *
138
     * @param Entity $entity Entity object
139
     *
140
     * @return Entity Inserted entity
141
     */
142 1
    public function insert(Entity $entity): Entity
143
    {
144 1
        $stmt = $this->pdo->prepare($this->sqlCommand->insertInto());
145
146 1
        $now = (new \DateTime())->format('Y-m-d H:i:s');
147
148 1
        $array = array_merge($entity->toArray(), [
149 1
            'modified' => $now,
150 1
            'created'  => $now
151
        ]);
152
153 1
        $stmt->execute($array);
154
155 1
        return $entity;
156
    }
157
158
    /**
159
     * Update entity in the database
160
     *
161
     * @param Entity $entity Entity object
162
     *
163
     * @return bool True if row was affected, otherwise false
164
     */
165 1
    public function update(Entity $entity): bool
166
    {
167 1
        if ($entity->isAltered()) {
168
            /**
169
             * Set modified to now
170
             */
171 1
            $entity->set('modified', new \DateTime());
172
173
            /**
174
             * Get altered columns for SQL command
175
             */
176 1
            $alteredColumns = array_keys($entity->getAlteredColumns());
177
178 1
            $stmt = $this->pdo->prepare($this->sqlCommand->updateSetWhere($alteredColumns));
179
180
            /**
181
             * Execute with altered array
182
             */
183 1
            $stmt->execute($entity->alteredToArray(true));
184
185
            // @todo return true if row is altered
186
        }
187
188 1
        return false;
189
    }
190
191
    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...
192
    {
193
        // @todo Implement
194
    }
195
196
    /**
197
     * Creates an array of Entity objects from statement
198
     *
199
     * @param \PDOStatement $statement
200
     *
201
     * @return Entity[] Entities from statement
202
     */
203
    protected function createEntitiesFromStatement(\PDOStatement $statement): array
204
    {
205
        $entities = [];
206
207
        $entityFactory = new EntityFactory($this->entityClass);
208
209
        foreach ($statement as $row) {
210
            $entities[] = $entityFactory->createFromArray($row);
211
        }
212
213
        return $entities;
214
    }
215
216
    /**
217
     * Create SQLCommand for this Table with provided Entity
218
     *
219
     * @return SQLCommand
220
     */
221
    protected function createCommand(): SQLCommand
222
    {
223
        $reflector = new \ReflectionClass($this->entityClass);
224
225
        $entity = $reflector->newInstanceWithoutConstructor();
226
227
        $columns = $entity::getColumns();
228
229
        return new SQLCommand($this->tableName, $columns);
230
    }
231
}
232