Completed
Pull Request — 2.0 (#75)
by Julien
02:32
created

PreparedQuery   A

Complexity

Total Complexity 18

Size/Duplication

Total Lines 223
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 7

Importance

Changes 8
Bugs 2 Features 0
Metric Value
wmc 18
lcom 1
cbo 7
dl 0
loc 223
c 8
b 2
f 0
rs 10

10 Methods

Rating   Name   Duplication   Size   Complexity  
A prepareValues() 0 14 4
A __construct() 0 9 2
A shutdown() 0 14 2
B execute() 0 36 2
A prepareConverters() 0 20 3
A getSignatureFor() 0 4 1
A getClientType() 0 4 1
A getClientIdentifier() 0 4 1
A prepare() 0 13 1
A getSql() 0 4 1
1
<?php
2
/*
3
 * This file is part of the PommProject/Foundation package.
4
 *
5
 * (c) 2014 - 2015 Grégoire HUBERT <[email protected]>
6
 *
7
 * For the full copyright and license information, please view the LICENSE
8
 * file that was distributed with this source code.
9
 */
10
namespace PommProject\Foundation\PreparedQuery;
11
12
use PommProject\Foundation\QueryManager\QueryParameterParserTrait;
13
use PommProject\Foundation\Listener\SendNotificationTrait;
14
use PommProject\Foundation\Exception\FoundationException;
15
use PommProject\Foundation\Client\Client;
16
17
/**
18
 * PreparedQuery
19
 *
20
 * @package   Foundation
21
 * @copyright 2014 - 2015 Grégoire HUBERT
22
 * @author    Grégoire HUBERT <[email protected]>
23
 * @license   X11 {@link http://opensource.org/licenses/mit-license.php}
24
 */
25
class PreparedQuery extends Client
26
{
27
    use QueryParameterParserTrait;
28
    use SendNotificationTrait;
29
30
    protected $sql;
31
    private $is_prepared = false;
32
    private $identifier;
33
    private $converters;
34
35
    /**
36
     * getSignatureFor
37
     *
38
     * Returns a hash for a given sql query.
39
     *
40
     * @static
41
     * @access public
42
     * @param  string $sql Sql query
43
     * @return string
44
     */
45
    public static function getSignatureFor($sql)
46
    {
47
        return md5($sql);
48
    }
49
50
    /**
51
     * __construct
52
     *
53
     * Build the prepared query.
54
     *
55
     * @access public
56
     * @param  string $sql SQL query
57
     * @throws FoundationException
58
     */
59
    public function __construct($sql)
60
    {
61
        if (empty($sql)) {
62
            throw new FoundationException("Can not prepare an empty query.");
63
        }
64
65
        $this->sql        = $sql;
66
        $this->identifier = static::getSignatureFor($sql);
67
    }
68
69
    /**
70
     * @see ClientPoolerInterface
71
     */
72
    public function getClientType()
73
    {
74
        return 'prepared_query';
75
    }
76
77
    /**
78
     * getClientIdentifier
79
     *
80
     * Return the query identifier.
81
     *
82
     * @access public
83
     * @return string Query identifier.
84
     */
85
    public function getClientIdentifier()
86
    {
87
        return $this->identifier;
88
    }
89
90
    /**
91
     * shutdown
92
     *
93
     * Deallocate the statement in the database.
94
     *
95
     * @see ClientInterface
96
     */
97
    public function shutdown()
98
    {
99
        if ($this->is_prepared === true) {
100
            $this
101
                ->getSession()
102
                ->getConnection()
103
                ->executeAnonymousQuery(sprintf(
104
                    "deallocate %s",
105
                    $this->getSession()->getConnection()->escapeIdentifier($this->getClientIdentifier())
106
                ));
107
108
            $this->is_prepared = false;
109
        }
110
    }
111
112
    /**
113
     * execute
114
     *
115
     * Launch the query with the given parameters.
116
     *
117
     * @access public
118
     * @param  array    $values Query parameters
119
     * @return Resource
120
     */
121
    public function execute(array $values = [])
122
    {
123
        if ($this->is_prepared === false) {
124
            $this->prepare();
125
        }
126
127
        $values = $this->prepareValues($this->sql, $values);
128
        $this->sendNotification(
129
            'query:pre',
130
            [
131
                'sql'           => $this->sql,
132
                'parameters'    => $values,
133
                'session_stamp' => $this->getSession()->getStamp(),
134
            ]
135
        );
136
137
        $start    = microtime(true);
138
        $resource = $this
139
            ->getSession()
140
            ->getConnection()
141
            ->sendExecuteQuery(
142
                $this->getClientIdentifier(),
143
                $values,
144
                $this->sql
145
            );
146
        $end      = microtime(true);
147
        $this->sendNotification(
148
            'query:post',
149
            [
150
                'result_count' => $resource->countRows(),
151
                'time_ms'      => sprintf("%03.1f", ($end - $start) * 1000),
152
            ]
153
        );
154
155
        return $resource;
156
    }
157
158
    /**
159
     * prepare
160
     *
161
     * Send the query to be prepared by the server.
162
     *
163
     * @access protected
164
     * @return PreparedQuery $this
165
     */
166
    protected function prepare()
167
    {
168
        $this
169
            ->getSession()
170
            ->getConnection()
171
            ->sendPrepareQuery(
172
                $this->getClientIdentifier(),
173
                $this->orderParameters($this->sql)
174
            );
175
        $this->is_prepared = true;
176
177
        return $this;
178
    }
179
180
    /**
181
     * getSql
182
     *
183
     * Get the original SQL query
184
     *
185
     * @access public
186
     * @return string SQL query
187
     */
188
    public function getSql()
189
    {
190
        return $this->sql;
191
    }
192
193
    /**
194
     * prepareValues
195
     *
196
     * Prepare parameters to be sent.
197
     *
198
     * @access protected
199
     * @param  mixed    $sql
200
     * @param  array    $values
201
     * @return array    $prepared_values
202
     */
203
    protected function prepareValues($sql, array $values)
204
    {
205
        if ($this->converters === null) {
206
            $this->prepareConverters($sql);
207
        }
208
209
        foreach ($values as $index => $value) {
210
            if (isset($this->converters[$index])) {
211
                $values[$index] = call_user_func($this->converters[$index], $value);
212
            }
213
        }
214
215
        return $values;
216
    }
217
218
    /**
219
     * prepareConverters
220
     *
221
     * Store converters needed for the query parameters.
222
     *
223
     * @access protected
224
     * @param mixed             $sql
225
     * @return PreparedQuery    $this
226
     */
227
    protected function prepareConverters($sql)
228
    {
229
        foreach ($this->getParametersType($sql) as $index => $type) {
230
            if ($type === '') {
231
                $this->converters[$index] = null;
232
            } else {
233
                $converter = $this
234
                    ->getSession()
235
                    ->getClientUsingPooler('converter', $type)
236
                    ->getConverter()
237
                    ;
238
239
                $this->converters[$index] = function ($value) use ($converter, $type) {
240
                    return $converter->toPgStandardFormat($value, $type, $this->getSession());
241
                };
242
            }
243
        }
244
245
        return $this;
246
    }
247
}
248