Completed
Push — master ( 8f0940...9b49d6 )
by Sébastien
13:32
created

SqlSource::assignOptions()   C

Complexity

Conditions 7
Paths 11

Size

Total Lines 30
Code Lines 17

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 19
CRAP Score 7

Importance

Changes 4
Bugs 2 Features 0
Metric Value
c 4
b 2
f 0
dl 0
loc 30
rs 6.7272
ccs 19
cts 19
cp 1
cc 7
eloc 17
nc 11
nop 2
crap 7
1
<?php
2
3
/**
4
 *
5
 * @author Vanvelthem Sébastien
6
 */
7
8
namespace Soluble\FlexStore\Source\Zend;
9
10
use Soluble\FlexStore\Source\AbstractSource;
11
use Soluble\FlexStore\Source\QueryableSourceInterface;
12
use Soluble\FlexStore\ResultSet\ResultSet;
13
use Soluble\FlexStore\Exception;
14
use Soluble\FlexStore\Options;
15
use Zend\Db\Adapter\Adapter;
16
use Zend\Db\Sql\Sql;
17
use Zend\Db\Sql\Select;
18
use Zend\Db\Sql\Expression;
19
use ArrayObject;
20
use Soluble\FlexStore\Column\ColumnModel;
21
use Soluble\FlexStore\Column\Type\MetadataMapper;
22
use Soluble\Metadata\Reader as MetadataReader;
23
24
class SqlSource extends AbstractSource implements QueryableSourceInterface
25
{
26
    /**
27
     * @var Sql
28
     */
29
    protected $sql;
30
31
    /**
32
     *
33
     * @var Select
34
     */
35
    protected $select;
36
37
    /**
38
     *
39
     * @var Adapter
40
     */
41
    protected $adapter;
42
43
    /**
44
     * Initial params received in the constructor
45
     * @var ArrayObject
46
     */
47
    protected $params;
48
49
    /**
50
     *
51
     * @var string
52
     */
53
    protected $query_string;
54
55
    /**
56
     *
57
     * @var \Zend\Db\Adapter\Driver\Mysqli\Statement
58
     */
59
    protected static $cache_stmt_prototype;
60
61
    /**
62
     *
63
     * @var \Zend\Db\Adapter\Driver\ResultInterface
64
     */
65
    protected static $cache_result_prototype;
66
67
    /**
68
     *
69
     * @var ColumnModel
70
     */
71
    protected $columnModel;
72
73
    /**
74
     *
75
     * @param Adapter $adapter
76
     * @param Select $select
77
     */
78 65
    public function __construct(Adapter $adapter, Select $select = null)
79
    {
80 65
        $this->adapter = $adapter;
81 65
        $this->sql = new Sql($this->adapter);
82 65
        if ($select !== null) {
83 56
            $this->setSelect($select);
84 56
        }
85 65
    }
86
87
    /**
88
     * @param Select $select
89
     * @return SqlSource
90
     */
91 60
    public function setSelect(Select $select)
92
    {
93 60
        $this->select = $select;
94 60
        return $this;
95
    }
96
97
    /**
98
     *
99
     * @return Select
100
     */
101 37
    public function getSelect()
102
    {
103 37
        return $this->select();
104
    }
105
106
    /**
107
     *
108
     * @return Select
109
     */
110 42
    public function select()
111
    {
112 42
        if ($this->select === null) {
113 14
            $this->select = $this->sql->select();
114 14
        }
115 42
        return $this->select;
116
    }
117
118
119
    /**
120
     *
121
     * @param Select $select
122
     * @param Options $options
123
     * @return Select
124
     */
125 37
    protected function assignOptions(Select $select, Options $options)
126
    {
127 37
        if ($options->hasLimit()) {
128 7
            $select->limit($options->getLimit());
129 7
            if ($options->hasOffset()) {
130 2
                $select->offset($options->getOffset());
131 2
            }
132
133
            if ($options->getLimit() > 0) {
134
135
                /**
136 7
                 * For mysql queries, to allow counting rows we must prepend
137 7
                 * SQL_CALC_FOUND_ROWS to the select quantifiers
138 7
                 */
139 1
                $calc_found_rows = 'SQL_CALC_FOUND_ROWS';
140 1
                $quant_state = $select->getRawState($select::QUANTIFIER);
141 1
                if ($quant_state !== null) {
142 1
                    if ($quant_state instanceof Expression) {
143 2
                        $quant_state->setExpression($calc_found_rows . ' ' . $quant_state->getExpression());
144 1
                    } elseif (is_string($quant_state)) {
145 1
                        $quant_state = $calc_found_rows . ' ' . $quant_state;
146 7
                    }
147
                    $select->quantifier($quant_state);
148 7
                } else {
149 37
                    $select->quantifier(new Expression($calc_found_rows));
150
                }
151
            }
152
        }
153
        return $select;
154
    }
155
156
    /**
157
     *
158
     * @param Options $options
159 37
     * @throws Exception\EmptyQueryException
160
     * @throws Exception\ErrorException
161 37
     * @return ResultSet
162 21
     */
163 21
    public function getData(Options $options = null)
164
    {
165 37
        if ($options === null) {
166
            $options = $this->getOptions();
167
        }
168 37
169 37
        $select = $this->assignOptions(clone $this->getSelect(), $options);
170
171
172
        $sql = new Sql($this->adapter);
173
        $sql_string = (string) $sql->getSqlStringForSqlObject($select);
0 ignored issues
show
Deprecated Code introduced by
The method Zend\Db\Sql\Sql::getSqlStringForSqlObject() has been deprecated with message: Deprecated in 2.4. Use buildSqlString() instead

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
174 37
        //echo $this->select->getSqlString($this->adapter->getPlatform());
175 2
        //echo "----" . var_dump($sql_string) . "----\n";
176
        // In ZF 2.3.0 an empty query will return SELECT .*
177 35
        // In ZF 2.4.0 and empty query will return SELECT *
178
        if (in_array($sql_string, ['', 'SELECT .*', 'SELECT *'])) {
179
            throw new Exception\EmptyQueryException(__METHOD__ . ': Cannot return data of an empty query');
180 35
        }
181
        $this->query_string = $sql_string;
182
183
        try {
184
            $results = $this->adapter->query($sql_string, Adapter::QUERY_MODE_EXECUTE);
185 35
            //$stmt = $sql->prepareStatementForSqlObject( $select );
186 35
            //$results = $stmt->execute();
187 35
            //var_dump(get_class($results));
188
189 35
            $r = new ResultSet($results);
0 ignored issues
show
Documentation introduced by
$results is of type object<Zend\Db\Adapter\D...Driver\ResultInterface>, but the function expects a object<Zend\Db\ResultSet...ultSet\ResultInterface>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
190
            $r->setSource($this);
191 7
            $r->setHydrationOptions($options->getHydrationOptions());
192 7
193 7
            if ($options->hasLimit() && $options->getLimit() > 0) {
194 30
                //$row = $this->adapter->query('select FOUND_ROWS() as total_count')->execute()->current();
195
                $row = $this->adapter->createStatement('select FOUND_ROWS() as total_count')->execute()->current();
196 35
                $r->setTotalRows($row['total_count']);
197
            } else {
198
                $r->setTotalRows($r->count());
199 35
            }
200
        } catch (\Exception $e) {
201
            throw new Exception\ErrorException(__METHOD__ . ': Cannot retrieve data (' . $e->getMessage() . ')');
202
        }
203
        return $r;
204
    }
205 31
206
    /**
207 30
     *
208 30
     */
209 30
    public function loadDefaultColumnModel()
210 30
    {
211 30
        $sql = new Sql($this->adapter);
212 30
        $select = clone $this->select;
213 31
        $select->limit(0);
214
        $sql_string = $sql->getSqlStringForSqlObject($select);
0 ignored issues
show
Deprecated Code introduced by
The method Zend\Db\Sql\Sql::getSqlStringForSqlObject() has been deprecated with message: Deprecated in 2.4. Use buildSqlString() instead

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
215
        $metadata_columns = $this->getMetadataReader()->getColumnsMetadata($sql_string);
216
        $this->setColumnModel(MetadataMapper::getColumnModelFromMetadata($metadata_columns));
217
    }
218
219 32
    /**
220
     * {@inheritdoc}
221 32
     * @throws Exception\UnsupportedFeatureException
222 32
     */
223 32
    public function getMetadataReader()
224 32
    {
225
        if ($this->metadataReader === null) {
226
            $this->setMetadataReader($this->getDefaultMetadataReader());
227
        }
228
        return $this->metadataReader;
229
    }
230 32
231
    /**
232 32
     * @throws Exception\UnsupportedFeatureException
233 32
     */
234
    protected function getDefaultMetadataReader()
235 32
    {
236
        $conn = $this->adapter->getDriver()->getConnection()->getResource();
237 32
        $class = strtolower(get_class($conn));
238 32
        switch ($class) {
239
            case 'pdo':
240
                return new MetadataReader\PdoMysqlMetadataReader($conn);
241
            case 'mysqli':
242
                return new MetadataReader\MysqliMetadataReader($conn);
243
            default:
244
                throw new Exception\UnsupportedFeatureException(__METHOD__ . " Does not support default metadata reader for driver '$class'");
245
        }
246
    }
247
248
    /**
249 4
     * Return the query string that was executed
250
     * @throws Exception\InvalidUsageException
251 4
     * @return string
252 1
     */
253
    public function getQueryString()
254 3
    {
255
        if ($this->query_string == '') {
256
            throw new Exception\InvalidUsageException(__METHOD__ . ": Invalid usage, getQueryString must be called after data has been loaded (performance reason).");
257
        }
258
        return str_replace("\n", ' ', $this->query_string);
259
    }
260
261
    /**
262
     * Return the query string
263 1
     *
264
     * @throws Exception\InvalidUsageException
265 1
     * @return string
266 1
     */
267 1
    public function __toString()
268
    {
269
        if (trim($this->query_string) != '') {
270
            $sql = str_replace("\n", ' ', $this->query_string);
271
        } elseif ($this->select !== null) {
272 1
            $sql = $this->sql->getSqlStringForSqlObject($this->select);
0 ignored issues
show
Deprecated Code introduced by
The method Zend\Db\Sql\Sql::getSqlStringForSqlObject() has been deprecated with message: Deprecated in 2.4. Use buildSqlString() instead

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
273
        } else {
274
            throw new Exception\InvalidUsageException(__METHOD__ . ": No select given.");
275
        }
276
        return $sql;
277
    }
278
}
279