Completed
Push — master ( 6738b5...e02aed )
by Iqbal
02:36
created

PdoFinder::count()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 10
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 1
Metric Value
c 1
b 0
f 1
dl 0
loc 10
rs 9.4285
cc 2
eloc 5
nc 2
nop 0
1
<?php
2
/*
3
 * This file is part of the Borobudur-Cqrs package.
4
 *
5
 * (c) Hexacodelabs <http://hexacodelabs.com>
6
 *
7
 * For the full copyright and license information, please view the LICENSE
8
 * file that was distributed with this source code.
9
 */
10
11
namespace Borobudur\Cqrs\ReadModel\Storage\Pdo;
12
13
use Borobudur\Cqrs\Collection;
14
use Borobudur\Cqrs\ParameterBag;
15
use Borobudur\Cqrs\ReadModel\ReadModelInterface;
16
use Borobudur\Cqrs\ReadModel\Storage\Finder\Expression\CompositeExpressionInterface;
17
use Borobudur\Cqrs\ReadModel\Storage\Finder\FinderInterface;
18
use Borobudur\Cqrs\ReadModel\Storage\Pdo\Expression\PdoCompositeExpression;
19
use Borobudur\Cqrs\ReadModel\Storage\Pdo\Expression\PdoExpression;
20
use Borobudur\Cqrs\ReadModel\Storage\Pdo\Parser\ParserInterface;
21
use PDO as PhpPdo;
22
23
/**
24
 * @author      Iqbal Maulana <[email protected]>
25
 * @created     8/18/15
26
 */
27
class PdoFinder implements FinderInterface
28
{
29
    /**
30
     * @var Pdo
31
     */
32
    private $conn;
33
34
    /**
35
     * @var string
36
     */
37
    private $table;
38
39
    /**
40
     * @var string
41
     */
42
    private $class;
43
44
    /**
45
     * @var array
46
     */
47
    private $sorts = array();
48
49
    /**
50
     * @var int
51
     */
52
    private $limit;
53
54
    /**
55
     * @var int
56
     */
57
    private $offset = 0;
58
59
    /**
60
     * @var CompositeExpressionInterface[]
61
     */
62
    private $conditions = array();
63
64
    /**
65
     * @var ParserInterface
66
     */
67
    private $parser;
68
69
    /**
70
     * @var string
71
     */
72
    private $quote;
73
74
    /**
75
     * Constructor.
76
     *
77
     * @param Pdo             $conn
78
     * @param string          $table
79
     * @param string          $class
80
     * @param ParserInterface $parser
81
     * @param string          $quote
82
     */
83
    public function __construct(Pdo &$conn, $table, $class, $parser, $quote)
84
    {
85
        $this->conn = $conn;
86
        $this->table = $table;
87
        $this->class = $class;
88
        $this->parser = $parser;
89
        $this->parser->setQuote($quote);
90
        $this->quote = $quote;
91
    }
92
93
    /**
94
     * {@inheritdoc}
95
     */
96
    public function sort(array $sorts)
97
    {
98
        $this->sorts = $sorts;
99
100
        return $this;
101
    }
102
103
    /**
104
     * {@inheritdoc}
105
     */
106
    public function limit($limit, $offset = 0)
107
    {
108
        $this->limit = $limit;
109
        $this->offset = $offset;
110
111
        return $this;
112
    }
113
114
    /**
115
     * {@inheritdoc}
116
     */
117
    public function expr()
118
    {
119
        return new PdoExpression($this->parser);
120
    }
121
122
    /**
123
     * {@inheritdoc}
124
     */
125
    public function where($expr)
126
    {
127
        if (!(1 === func_num_args() && $expr instanceof CompositeExpressionInterface)) {
128
            $expr = new PdoCompositeExpression(CompositeExpressionInterface::LOGICAL_AND, func_get_args());
129
        }
130
131
        $this->conditions[] = $expr;
132
133
        return $this;
134
    }
135
136
    /**
137
     * {@inheritdoc}
138
     */
139
    public function count()
140
    {
141
        $stmt = $this->conn->query($this->computeQuery('COUNT(*) AS num'), PhpPdo::FETCH_ASSOC);
142
143
        if ($result = $stmt->fetch()) {
144
            return (int) $result['num'];
145
        }
146
147
        return 0;
148
    }
149
150
    /**
151
     * {@inheritdoc}
152
     */
153
    public function first()
154
    {
155
        $this->limit(1);
156
        $stmt = $this->conn->query($this->computeQuery(), PhpPdo::FETCH_ASSOC);
157
158
        if ($record = $stmt->fetch()) {
159
            return $this->deserialize($record);
160
        }
161
162
        return null;
163
    }
164
165
    /**
166
     * Fetch sets of data.
167
     *
168
     * @return Collection
169
     */
170
    public function get()
171
    {
172
        $stmt = $this->conn->query($this->computeQuery(), PhpPdo::FETCH_ASSOC);
173
174
        return new Collection($stmt->fetchAll(), $this->class);
175
    }
176
177
    /**
178
     * Cast finder to string representation.
179
     *
180
     * @return string
181
     */
182
    public function __toString()
183
    {
184
        return $this->computeQuery();
185
    }
186
187
    /**
188
     * Deserialize record to read model.
189
     *
190
     * @param array $record
191
     *
192
     * @return ReadModelInterface
193
     */
194
    protected function deserialize(array $record)
195
    {
196
        $class = $this->class;
197
198
        return $class::{'deserialize'}(new ParameterBag($record));
199
    }
200
201
    /**
202
     * Compute query language.
203
     *
204
     * @param string $fields
205
     *
206
     * @return string
207
     */
208
    protected function computeQuery($fields = '*')
209
    {
210
        $parts = array(
211
            'SELECT ' . $fields,
212
            'FROM ' . $this->quote($this->table),
213
        );
214
215
        if (!empty($this->conditions)) {
216
            $parts[] = 'WHERE ' . $this->normalizeConditions();
217
        }
218
219
        if (!empty($this->sorts)) {
220
            $parts[] = 'ORDER BY ' . $this->normalizeSorts();
221
        }
222
223
        if (null !== $this->limit) {
224
            $parts[] = sprintf('LIMIT %d OFFSET %d', $this->limit, $this->offset);
225
        }
226
227
        return implode(' ', $parts);
228
    }
229
230
    /**
231
     * Normalize conditions.
232
     *
233
     * @return string
234
     */
235
    protected function normalizeConditions()
236
    {
237
        $joiner = ' ' . CompositeExpressionInterface::LOGICAL_AND . ' ';
238
239
        return implode($joiner, array_map(function ($item) {
240
            return (string) $item;
241
        }, $this->conditions));
242
    }
243
244
    /**
245
     * Normalize sorts.
246
     *
247
     * @return string
248
     */
249
    protected function normalizeSorts()
250
    {
251
        $sorts = array();
252
        foreach ($this->sorts as $field => $direction) {
253
            $sorts[] = $this->quote($field) . ' ' . $direction;
254
        }
255
256
        return implode(', ', $sorts);
257
    }
258
259
    /**
260
     * Quote field.
261
     *
262
     * @param string $field
263
     *
264
     * @return string
265
     */
266
    protected function quote($field)
267
    {
268
        return $this->quote . $field . $this->quote;
269
    }
270
}
271