Completed
Push — master ( c82e60...68cb49 )
by Sébastien
05:32
created

ResultSet   A

Complexity

Total Complexity 35

Size/Duplication

Total Lines 282
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 8

Test Coverage

Coverage 94.34%

Importance

Changes 3
Bugs 0 Features 0
Metric Value
wmc 35
c 3
b 0
f 0
lcom 1
cbo 8
dl 0
loc 282
ccs 100
cts 106
cp 0.9434
rs 9

13 Methods

Rating   Name   Duplication   Size   Complexity  
A getColumnModel() 0 8 2
A setSource() 0 5 1
A getSource() 0 4 1
A setHydrationOptions() 0 5 1
A getPaginator() 0 11 2
A setTotalRows() 0 5 1
A getTotalRows() 0 4 1
A getHydrationOptions() 0 4 1
C initColumnModelHydration() 0 39 7
D current() 0 38 10
B toArray() 0 18 5
A valid() 0 8 2
A rewind() 0 5 1
1
<?php
2
3
namespace Soluble\FlexStore\ResultSet;
4
5
use Soluble\FlexStore\Source\AbstractSource;
6
use Soluble\FlexStore\Helper\Paginator;
7
use Soluble\FlexStore\Options\HydrationOptions;
8
use Soluble\FlexStore\Column\ColumnModel;
9
use ArrayObject;
10
11
class ResultSet extends AbstractResultSet
12
{
13
    /**
14
     *
15
     * @var Paginator
16
     */
17
    protected $paginator;
18
19
    /**
20
     *
21
     * @var integer
22
     */
23
    protected $totalRows;
24
25
    /**
26
     * @var AbstractSource
27
     */
28
    protected $source;
29
30
    /**
31
     *
32
     * @var HydrationOptions
33
     */
34
    protected $hydrationOptions;
35
36
    /**
37
     *
38
     * @var boolean
39
     */
40
    protected $hydrate_options_initialized = false;
41
42
    /**
43
     * @var ArrayObject
44
     */
45
    protected $hydration_formatters;
46
47
    /**
48
     * @var ArrayObject
49
     */
50
    protected $hydration_renderers;
51
52
    /**
53
     * @var ArrayObject|null
54
     */
55
    protected $hydrated_columns;
56
57
58
59
    /**
60
     * Return source column model
61
     *
62
     * @throws Exception\RuntimeException
63
     * @return ColumnModel
64
     */
65 10
    public function getColumnModel()
66
    {
67 10
        if ($this->source === null) {
68 1
            throw new Exception\RuntimeException(__METHOD__ . " Prior to get column model, a source must be set.");
69
        }
70 9
        $this->hydrate_options_initialized = false;
71 9
        return $this->source->getColumnModel();
72
    }
73
74
    /**
75
     *
76
     * @param AbstractSource $source
77
     * @return ResultSet
78
     */
79 39
    public function setSource(AbstractSource $source)
80
    {
81 39
        $this->source = $source;
82 39
        return $this;
83
    }
84
85
    /**
86
     *
87
     * @return AbstractSource
88
     */
89 9
    public function getSource()
90
    {
91 9
        return $this->source;
92
    }
93
94
    /**
95
     *
96
     * @param HydrationOptions $hydrationOptions
97
     * @return ResultSet
98
     */
99 39
    public function setHydrationOptions(HydrationOptions $hydrationOptions)
100
    {
101 39
        $this->hydrationOptions = $hydrationOptions;
102 39
        return $this;
103
    }
104
105
    /**
106
     *
107
     * @return HydrationOptions
108
     */
109 9
    public function getHydrationOptions()
110 9
    {
111 9
        return $this->hydrationOptions;
112
    }
113
114
115
    /**
116
     *
117
     * @return Paginator
118
     */
119 2
    public function getPaginator()
120
    {
121 2
        if ($this->paginator === null) {
122 2
            $this->paginator = new Paginator(
123 2
                $this->getTotalRows(),
124 2
                $this->getSource()->getOptions()->getLimit(),
125 2
                $this->getSource()->getOptions()->getOffset()
126 2
            );
127 1
        }
128 1
        return $this->paginator;
129
    }
130
131
    /**
132
     * Set the total rows
133
     * @param int $totalRows
134
     * @return ResultSet
135
     */
136 39
    public function setTotalRows($totalRows)
137
    {
138 39
        $this->totalRows = (int) $totalRows;
139 39
        return $this;
140
    }
141
142
    /**
143
     * @return int
144
     */
145 13
    public function getTotalRows()
146
    {
147 13
        return $this->totalRows;
148
    }
149
150
    /**
151
     *
152
     * @param ArrayObject|array $row
153
     * @return null
154
     */
155
//protected function initColumnModelHydration(ArrayObject $row)    
156 26
    protected function initColumnModelHydration(&$row)
157
    {
158 26
        $this->hydration_formatters = new ArrayObject();
159 26
        $this->hydration_renderers = new ArrayObject();
160 26
        $this->hydrated_columns = null;
161
162 26
        if ($this->source->hasColumnModel()) {
163 9
            $cm = $this->getColumnModel();
164
165
            // 1. Initialize columns hydrators
166 9
            if ($this->getHydrationOptions()->isFormattersEnabled()) {
167 9
                $formatters = $cm->getUniqueFormatters();
168 9
                if ($formatters->count() > 0) {
169 2
                    $this->hydration_formatters = $formatters;
170 2
                }
171 9
            }
172
173
            // 2. Initialize hydrated columns
174
175 9
            if ($this->getHydrationOptions()->isColumnExclusionEnabled()) {
176 9
                $columns = $cm->getColumns();
177
178
                // Performance:
179
                // Only if column model definition differs from originating
180
                // source row definition.
181 9
                $hydrated_columns = array_keys((array) $columns);
182 9
                $row_columns = array_keys((array) $row);
183 9
                if ($hydrated_columns != $row_columns) {
184 5
                    $this->hydrated_columns = new ArrayObject($hydrated_columns);
185 5
                }
186 9
            }
187
188
            // 3. Initialize row renderers
189 9
            if ($this->getHydrationOptions()->isRenderersEnabled()) {
190 9
                $this->hydration_renderers = $cm->getRowRenderers();
191 9
            }
192 9
        }
193 26
        $this->hydrate_options_initialized = true;
194 26
    }
195
196
    /**
197
     * Return the current row as an array|ArrayObject.
198
     * If setLimitColumns() have been set, will only return
199
     * the limited columns.
200
     *
201
     * @throws Exception\UnknownColumnException
202
     * @return array|ArrayObject|null
203
     */
204 26
    public function current()
205
    {
206 26
        $row = $this->zfResultSet->current();
207 26
        if ($row === null) {
208
            return;
209
        }
210
211 26
        if (!$this->hydrate_options_initialized) {
212 26
            $this->initColumnModelHydration($row);
213 26
        }
214
215
216
        // 1. Row renderers
217 26
        foreach ($this->hydration_renderers as $renderer) {
218 5
            $renderer->apply($row);
219 25
        }
220
221
        // 2. Formatters
222 25
        foreach ($this->hydration_formatters as $formatters) {
223 2
            foreach ($formatters['columns'] as $column) {
224 2
                $row[$column] = $formatters['formatter']->format($row[$column], $row);
225 2
            }
226 25
        }
227
228
        // 3. Process column hydration
229 25
        if ($this->hydrated_columns !== null) {
230 4
            $d = new ArrayObject();
231 4
            foreach ($this->hydrated_columns as $column) {
232 4
                $d->offsetSet($column, isset($row[$column]) ? $row[$column] : null);
233 4
            }
234 4
            $row->exchangeArray($d);
235 4
        }
236
237 25
        if ($this->returnType === self::TYPE_ARRAY) {
238
            return (array) $row;
239
        }
240 25
        return $row;
241
    }
242
243
    /**
244
     * Cast result set to array of arrays
245
     *
246
     * @return array
247
     * @throws Exception\RuntimeException if any row is not castable to an array
248
     */
249 25
    public function toArray()
250
    {
251 25
        $return = [];
252 25
        foreach ($this as $row) {
253 23
            if (is_array($row)) {
254 1
                $return[] = $row;
255 23
            } elseif (method_exists($row, 'toArray')) {
256
                $return[] = $row->toArray();
0 ignored issues
show
Bug introduced by
It seems like you code against a specific sub-type and not the parent class ArrayObject as the method toArray() does only exist in the following sub-classes of ArrayObject: Zend\Stdlib\Parameters. Maybe you want to instanceof check for one of these explicitly?

Let’s take a look at an example:

abstract class User
{
    /** @return string */
    abstract public function getPassword();
}

class MyUser extends User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different sub-classes of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the parent class:

    abstract class User
    {
        /** @return string */
        abstract public function getPassword();
    
        /** @return string */
        abstract public function getDisplayName();
    }
    
Loading history...
257 22
            } elseif (method_exists($row, 'getArrayCopy')) {
258 22
                $return[] = $row->getArrayCopy();
259 22
            } else {
260
                throw new Exception\RuntimeException(
261
                    __METHOD__ . ': Rows as part of this DataSource, with type ' . gettype($row) . ' cannot be cast to an array'
262
                );
263
            }
264 24
        }
265 24
        return $return;
266
    }
267
268
    /**
269
     * Iterator: is pointer valid?
270
     *
271
     * @return bool
272
     */
273 25
    public function valid()
274
    {
275 25
        $valid =  $this->zfResultSet->valid();
276 25
        if (!$valid) {
277 24
            $this->hydrate_options_initialized = false;
278 24
        }
279 25
        return $valid;
280
    }
281
282
    /**
283
     * Iterator: rewind
284
     *
285
     * @return void
286
     */
287 25
    public function rewind()
288
    {
289 25
        $this->hydrate_options_initialized = false;
290 25
        $this->zfResultSet->rewind();
291 25
    }
292
}
293