Completed
Push — master ( 9f8cbf...ebe6f0 )
by Sébastien
16:49 queued 08:42
created

SqlSource   B

Complexity

Total Complexity 28

Size/Duplication

Total Lines 251
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 17

Test Coverage

Coverage 91.4%

Importance

Changes 3
Bugs 1 Features 0
Metric Value
wmc 28
c 3
b 1
f 0
lcom 1
cbo 17
dl 0
loc 251
ccs 85
cts 93
cp 0.914
rs 7.8571

11 Methods

Rating   Name   Duplication   Size   Complexity  
A setSelect() 0 5 1
A getSelect() 0 4 1
A select() 0 7 2
A __construct() 0 8 2
B assignOptions() 0 26 6
B getData() 0 42 5
A loadDefaultColumnModel() 0 9 1
A getMetadataReader() 0 7 2
A getDefaultMetadataReader() 0 13 3
A getQueryString() 0 7 2
A __toString() 0 11 3
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
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
             * For mysql queries, to allow counting rows we must prepend
134
             * SQL_CALC_FOUND_ROWS to the select quantifiers
135
             */
136 7
            $calc_found_rows = 'SQL_CALC_FOUND_ROWS';
137 7
            $quant_state = $select->getRawState($select::QUANTIFIER);
138 7
            if ($quant_state !== null) {
139 1
                if ($quant_state instanceof Expression) {
140 1
                    $quant_state->setExpression($calc_found_rows . ' ' . $quant_state->getExpression());
141 1
                } elseif (is_string($quant_state)) {
142 1
                    $quant_state = $calc_found_rows . ' ' . $quant_state;
143 2
                }
144 1
                $select->quantifier($quant_state);
145 1
            } else {
146 7
                $select->quantifier(new Expression($calc_found_rows));
147
            }
148 7
        }
149 37
        return $select;
150
    }
151
152
    /**
153
     *
154
     * @param Options $options
155
     * @throws Exception\EmptyQueryException
156
     * @throws Exception\ErrorException
157
     * @return ResultSet
158
     */
159 37
    public function getData(Options $options = null)
160
    {
161 37
        if ($options === null) {
162 21
            $options = $this->getOptions();
163 21
        }
164
165 37
        $select = $this->assignOptions(clone $this->getSelect(), $options);
166
167
168 37
        $sql = new Sql($this->adapter);
169 37
        $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...
170
        //echo $this->select->getSqlString($this->adapter->getPlatform());
171
        //echo "----" . var_dump($sql_string) . "----\n";
172
        // In ZF 2.3.0 an empty query will return SELECT .*
173
        // In ZF 2.4.0 and empty query will return SELECT *
174 37
        if (in_array($sql_string, ['', 'SELECT .*', 'SELECT *'])) {
175 2
            throw new Exception\EmptyQueryException(__METHOD__ . ': Cannot return data of an empty query');
176
        }
177 35
        $this->query_string = $sql_string;
178
179
        try {
180 35
            $results = $this->adapter->query($sql_string, Adapter::QUERY_MODE_EXECUTE);
181
            //$stmt = $sql->prepareStatementForSqlObject( $select );
182
            //$results = $stmt->execute();
183
            //var_dump(get_class($results));
184
185 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\ResultSet>.

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...
186 35
            $r->setSource($this);
187 35
            $r->setHydrationOptions($options->getHydrationOptions());
188
189 35
            if ($options->hasLimit()) {
190
                //$row = $this->adapter->query('select FOUND_ROWS() as total_count')->execute()->current();
191 7
                $row = $this->adapter->createStatement('select FOUND_ROWS() as total_count')->execute()->current();
192 7
                $r->setTotalRows($row['total_count']);
193 7
            } else {
194 30
                $r->setTotalRows($r->count());
195
            }
196 35
        } catch (\Exception $e) {
197
            throw new Exception\ErrorException(__METHOD__ . ': Cannot retrieve data (' . $e->getMessage() . ')');
198
        }
199 35
        return $r;
200
    }
201
202
    /**
203
     *
204
     */
205 31
    public function loadDefaultColumnModel()
206
    {
207 30
        $sql = new Sql($this->adapter);
208 30
        $select = clone $this->select;
209 30
        $select->limit(0);
210 30
        $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...
211 30
        $metadata_columns = $this->getMetadataReader()->getColumnsMetadata($sql_string);
212 30
        $this->setColumnModel(MetadataMapper::getColumnModelFromMetadata($metadata_columns));
213 31
    }
214
215
    /**
216
     * {@inheritdoc}
217
     * @throws Exception\UnsupportedFeatureException
218
     */
219 32
    public function getMetadataReader()
220
    {
221 32
        if ($this->metadataReader === null) {
222 32
            $this->setMetadataReader($this->getDefaultMetadataReader());
223 32
        }
224 32
        return $this->metadataReader;
225
    }
226
227
    /**
228
     * @throws Exception\UnsupportedFeatureException
229
     */
230 32
    protected function getDefaultMetadataReader()
231
    {
232 32
        $conn = $this->adapter->getDriver()->getConnection()->getResource();
233 32
        $class = strtolower(get_class($conn));
234
        switch ($class) {
235 32
            case 'pdo':
236
                return new MetadataReader\PdoMysqlMetadataReader($conn);
237 32
            case 'mysqli':
238 32
                return new MetadataReader\MysqliMetadataReader($conn);
239
            default:
240
                throw new Exception\UnsupportedFeatureException(__METHOD__ . " Does not support default metadata reader for driver '$class'");
241
        }
242
    }
243
244
    /**
245
     * Return the query string that was executed
246
     * @throws Exception\InvalidUsageException
247
     * @return string
248
     */
249 4
    public function getQueryString()
250
    {
251 4
        if ($this->query_string == '') {
252 1
            throw new Exception\InvalidUsageException(__METHOD__ . ": Invalid usage, getQueryString must be called after data has been loaded (performance reason).");
253
        }
254 3
        return str_replace("\n", ' ', $this->query_string);
255
    }
256
257
    /**
258
     * Return the query string
259
     *
260
     * @throws Exception\InvalidUsageException
261
     * @return string
262
     */
263 1
    public function __toString()
264
    {
265 1
        if ($this->query_string != '') {
266 1
            $sql = str_replace("\n", ' ', $this->query_string);
267 1
        } elseif ($this->select !== null) {
268
            $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...
269
        } else {
270
            throw new Exception\InvalidUsageException(__METHOD__ . ": No select given.");
271
        }
272 1
        return $sql;
273
    }
274
}
275