Completed
Pull Request — master (#2)
by René
05:02 queued 02:37
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\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 mixed  $value Value to search for
96
     *
97
     * @throws InvalidEntityPropertyException If entity does not have that property
98
     *
99
     * @return Entity[] Entities
100
     */
101 4
    public function findBy(string $key, $value): array
102
    {
103
        /**
104
         * Check if entity have the property
105
         *
106
         * @var Entity $entity
107
         */
108 4
        $reflector = new \ReflectionClass($this->entityClass);
109
110 4
        $entity = $reflector->newInstanceWithoutConstructor();
111
112 4
        if (!isset($entity::getColumns()[$key])) {
113 1
            throw new InvalidEntityPropertyException([$this->entityClass, $key]);
114
        }
115
116
        /**
117
         * Validate value
118
         */
119 3
        $value = $entity->validatePropertyValueType($key, $value);
120
121
        /**
122
         * Execute with key-value condition
123
         */
124 2
        $stmt = $this->pdo->prepare($this->sqlCommand->selectFromWhere([$key]));
125 2
        $stmt->execute([":$key" => $value]);
126
127 2
        return $this->createEntitiesFromStatement($stmt);
128
    }
129
130
    /**
131
     * Insert entity into database
132
     *
133
     * @param Entity $entity Entity object
134
     *
135
     * @return Entity Inserted entity
136
     */
137 1
    public function insert(Entity $entity): Entity
138
    {
139 1
        $stmt = $this->pdo->prepare($this->sqlCommand->insertInto());
140
141 1
        $now = (new \DateTime())->format('Y-m-d H:i:s');
142
143 1
        $array = array_merge($entity->toArray(), [
144 1
            'modified' => $now,
145 1
            'created'  => $now
146
        ]);
147
148 1
        $stmt->execute($array);
149
150 1
        return $entity;
151
    }
152
153
    /**
154
     * Update entity in the database
155
     *
156
     * @param Entity $entity Entity object
157
     *
158
     * @return bool True if row was affected, otherwise false
159
     */
160 1
    public function update(Entity $entity): bool
161
    {
162 1
        if ($entity->isAltered()) {
163
            /**
164
             * Set modified to now
165
             */
166 1
            $entity->set('modified', new \DateTime());
167
168
            /**
169
             * Get altered columns for SQL command
170
             */
171 1
            $alteredColumns = array_keys($entity->getAlteredColumns());
172
173 1
            $stmt = $this->pdo->prepare($this->sqlCommand->updateSetWhere($alteredColumns));
174
175
            /**
176
             * Execute with altered array
177
             */
178 1
            $stmt->execute($entity->alteredToArray(true));
179
180
            // @todo return true if row is altered
181
        }
182
183 1
        return false;
184
    }
185
186
    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...
187
    {
188
        // @todo Implement
189
    }
190
191
    /**
192
     * Creates an array of Entity objects from statement
193
     *
194
     * @param \PDOStatement $statement
195
     *
196
     * @return Entity[] Entities from statement
197
     */
198
    protected function createEntitiesFromStatement(\PDOStatement $statement): array
199
    {
200
        $entities = [];
201
202
        $entityFactory = new EntityFactory($this->entityClass);
203
204
        foreach ($statement as $row) {
205
            $entities[] = $entityFactory->createFromArray($row);
206
        }
207
208
        return $entities;
209
    }
210
211
    /**
212
     * Create SQLCommand for this Table with provided Entity
213
     *
214
     * @return SQLCommand
215
     */
216
    protected function createCommand(): SQLCommand
217
    {
218
        $reflector = new \ReflectionClass($this->entityClass);
219
220
        $entity = $reflector->newInstanceWithoutConstructor();
221
222
        $columns = $entity::getColumns();
223
224
        return new SQLCommand($this->tableName, $columns);
225
    }
226
}
227