PreparedQuery::execute()   A
last analyzed

Complexity

Conditions 2
Paths 2

Size

Total Lines 36

Duplication

Lines 0
Ratio 0 %

Importance

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