Completed
Push — master ( b281c2...8f0940 )
by Sébastien
12:12
created

QuerySource::__construct()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 8
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 8
rs 9.4285
cc 2
eloc 4
nc 2
nop 2
1
<?php
2
3
/**
4
 *
5
 * @author Vanvelthem Sébastien
6
 */
7
8
namespace Soluble\FlexStore\Source\DbWrapper;
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 ArrayObject;
16
use Soluble\DbWrapper\Adapter\AdapterInterface;
17
use Soluble\FlexStore\Column\ColumnModel;
18
use Soluble\FlexStore\Column\Type\MetadataMapper;
19
use Soluble\Metadata\Reader as MetadataReader;
20
21
class QuerySource extends AbstractSource implements QueryableSourceInterface
22
{
23
24
    /**
25
     *
26
     * @var string
27
     */
28
    protected $query;
29
30
    /**
31
     *
32
     * @var AdapterInterface
33
     */
34
    protected $adapter;
35
36
    /**
37
     * Initial params received in the constructor
38
     * @var ArrayObject
39
     */
40
    protected $params;
41
42
    /**
43
     *
44
     * @var string
45
     */
46
    protected $query_string;
47
48
49
50
    /**
51
     *
52
     * @var ColumnModel
53
     */
54
    protected $columnModel;
55
56
    /**
57
     *
58
     * @param AdapterInterface $adapter
59
     * @param string $query
60
     */
61
    public function __construct(AdapterInterface $adapter, $query = null)
62
    {
63
        $this->adapter = $adapter;
64
65
        if ($query !== null) {
66
            $this->setQuery($query);
67
        }
68
    }
69
70
    /**
71
     * @param string $query
72
     */
73
    public function setQuery($query)
74
    {
75
        $this->query = $query;
76
    }
77
78
    /**
79
     *
80
     * @return string
81
     */
82
    public function getQuery()
83
    {
84
        return $this->query;
85
    }
86
87
88
    /**
89
     *
90
     * @param Select $select
91
     * @param Options $options
92
     * @return Select
93
     */
94
    protected function assignOptions(Select $select, Options $options)
95
    {
96
        if ($options->hasLimit()) {
97
            $select->limit($options->getLimit());
98
            if ($options->hasOffset()) {
99
                $select->offset($options->getOffset());
100
            }
101
            /**
102
             * For mysql queries, to allow counting rows we must prepend
103
             * SQL_CALC_FOUND_ROWS to the select quantifiers
104
             */
105
            $calc_found_rows = 'SQL_CALC_FOUND_ROWS';
106
            $quant_state = $select->getRawState($select::QUANTIFIER);
107
            if ($quant_state !== null) {
108
                if ($quant_state instanceof Expression) {
0 ignored issues
show
Bug introduced by
The class Soluble\FlexStore\Source\DbWrapper\Expression does not exist. Did you forget a USE statement, or did you not list all dependencies?

This error could be the result of:

1. Missing dependencies

PHP Analyzer uses your composer.json file (if available) to determine the dependencies of your project and to determine all the available classes and functions. It expects the composer.json to be in the root folder of your repository.

Are you sure this class is defined by one of your dependencies, or did you maybe not list a dependency in either the require or require-dev section?

2. Missing use statement

PHP does not complain about undefined classes in ìnstanceof checks. For example, the following PHP code will work perfectly fine:

if ($x instanceof DoesNotExist) {
    // Do something.
}

If you have not tested against this specific condition, such errors might go unnoticed.

Loading history...
109
                    $quant_state->setExpression($calc_found_rows . ' ' . $quant_state->getExpression());
110
                } elseif (is_string($quant_state)) {
111
                    $quant_state = $calc_found_rows . ' ' . $quant_state;
112
                }
113
                $select->quantifier($quant_state);
114
            } else {
115
                $select->quantifier(new Expression($calc_found_rows));
116
            }
117
        }
118
        return $select;
119
    }
120
121
    /**
122
     *
123
     * @param Options $options
124
     * @throws Exception\EmptyQueryException
125
     * @throws Exception\ErrorException
126
     * @return ResultSet
127
     */
128
    public function getData(Options $options = null)
129
    {
130
        if ($options === null) {
131
            $options = $this->getOptions();
132
        }
133
134
        // todo
135
        //$query = $this->assignOptions(clone $this->query, $options);
136
137
138
        $sql_string = $this->query;
139
140
        try {
141
            $results = $this->adapter->query($sql_string);
142
143
144
145
            $r = new ResultSet($results);
0 ignored issues
show
Documentation introduced by
$results is of type object<Soluble\DbWrapper\Result\Resultset>, 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...
146
            $r->setSource($this);
147
            $r->setHydrationOptions($options->getHydrationOptions());
148
149
            if ($options->hasLimit()) {
150
                //$row = $this->adapter->query('select FOUND_ROWS() as total_count')->execute()->current();
151
                $row = $this->adapter->query('select FOUND_ROWS() as total_count')->current();
152
                $r->setTotalRows($row['total_count']);
153
            } else {
154
                $r->setTotalRows($r->count());
155
            }
156
        } catch (\Exception $e) {
157
            throw new Exception\ErrorException(__METHOD__ . ': Cannot retrieve data (' . $e->getMessage() . ')');
158
        }
159
        return $r;
160
    }
161
162
    /**
163
     *
164
     */
165
    public function loadDefaultColumnModel()
166
    {
167
        $metadata_columns = $this->getMetadataReader()->getColumnsMetadata($this->query);
168
        $this->setColumnModel(MetadataMapper::getColumnModelFromMetadata($metadata_columns));
169
    }
170
171
    /**
172
     * {@inheritdoc}
173
     * @throws Exception\UnsupportedFeatureException
174
     */
175
    public function getMetadataReader()
176
    {
177
        if ($this->metadataReader === null) {
178
            $this->setMetadataReader($this->getDefaultMetadataReader());
179
        }
180
        return $this->metadataReader;
181
    }
182
183
    /**
184
     * @throws Exception\UnsupportedFeatureException
185
     */
186
    protected function getDefaultMetadataReader()
187
    {
188
        $conn = $this->adapter->getConnection()->getResource();
189
        $class = strtolower(get_class($conn));
190
        switch ($class) {
191
            case 'pdo':
192
                return new MetadataReader\PdoMysqlMetadataReader($conn);
193
            case 'mysqli':
194
                return new MetadataReader\MysqliMetadataReader($conn);
195
            default:
196
                throw new Exception\UnsupportedFeatureException(__METHOD__ . " Does not support default metadata reader for driver '$class'");
197
        }
198
    }
199
200
    /**
201
     * Return the query string that was executed
202
     * @throws Exception\InvalidUsageException
203
     * @return string
204
     */
205
    public function getQueryString()
206
    {
207
        if ($this->query_string == '') {
208
            throw new Exception\InvalidUsageException(__METHOD__ . ": Invalid usage, getQueryString must be called after data has been loaded (performance reason).");
209
        }
210
        return str_replace("\n", ' ', $this->query_string);
211
    }
212
213
    /**
214
     * Return the query string
215
     *
216
     * @throws Exception\InvalidUsageException
217
     * @return string
218
     */
219
    public function __toString()
220
    {
221
        if ($this->query_string != '') {
222
            $sql = str_replace("\n", ' ', $this->query_string);
223
        } elseif ($this->select !== null) {
0 ignored issues
show
Bug introduced by
The property select does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
224
            $sql = $this->sql->getSqlStringForSqlObject($this->select);
0 ignored issues
show
Bug introduced by
The property sql does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
225
        } else {
226
            throw new Exception\InvalidUsageException(__METHOD__ . ": No select given.");
227
        }
228
        return $sql;
229
    }
230
}
231