Completed
Push — master ( 1d37d4...bf8214 )
by Ori
01:34
created

BaseResource::read()   C

Complexity

Conditions 13
Paths 68

Size

Total Lines 27
Code Lines 19

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 13
eloc 19
nc 68
nop 1
dl 0
loc 27
rs 5.1234
c 0
b 0
f 0

How to fix   Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
namespace frictionlessdata\datapackage\Resources;
4
5
use frictionlessdata\datapackage\DataStreams\BaseDataStream;
6
use frictionlessdata\datapackage\Registry;
7
use frictionlessdata\datapackage\Validators\ResourceValidationError;
8
use frictionlessdata\datapackage\Validators\ResourceValidator;
9
use frictionlessdata\datapackage\Exceptions\ResourceValidationFailedException;
10
use frictionlessdata\datapackage\Utils;
11
12
abstract class BaseResource implements \Iterator
13
{
14
    /**
15
     * BaseResource constructor.
16
     *
17
     * @param object      $descriptor
18
     * @param null|string $basePath
19
     *
20
     * @throws ResourceValidationFailedException
21
     */
22
    public function __construct($descriptor, $basePath, $skipValidations = false)
23
    {
24
        $this->basePath = $basePath;
25
        $this->descriptor = Utils::objectify($descriptor);
26
        $this->skipValidations = $skipValidations;
27
        if (!$this->skipValidations) {
28
            $validationErrors = $this->validateResource();
29
            if (count($validationErrors) > 0) {
30
                throw new ResourceValidationFailedException($validationErrors);
31
            }
32
        }
33
    }
34
35
    public static function handlesDescriptor($descriptor)
36
    {
37
        return static::handlesProfile(Registry::getResourceValidationProfile($descriptor));
38
    }
39
40
    public function read($readOptions=null)
41
    {
42
        $limit = ($readOptions && isset($readOptions["limit"])) ? $readOptions["limit"] : null;
43
        $rows = [];
44
        foreach ($this->dataStreams() as $dataStream) {
45
            if (isset($dataStream->table)) {
46
                $readOptions["limit"] = $limit;
47
                foreach ($dataStream->table->read($readOptions) as $row) {
48
                    $rows[] = $row;
49
                    if ($limit !== null) {
50
                        $limit--;
51
                        if ($limit < 0) break;
52
                    }
53
                };
54
            } else {
55
                foreach ($dataStream as $row) {
56
                    $rows[] = $row;
57
                    if ($limit !== null) {
58
                        $limit--;
59
                        if ($limit < 0) break;
60
                    }
61
                }
62
            }
63
            if ($limit !== null && $limit < 0) break;
64
        }
65
        return $rows;
66
    }
67
68
    public function dataStreams()
69
    {
70
        if (is_null($this->dataStreams)) {
71
            $this->dataStreams = [];
72
            foreach ($this->path() as $path) {
73
                $this->dataStreams[] = $this->getDataStream($path);
74
            }
75
            $data = $this->data();
76
            if ($data) {
77
                $this->dataStreams[] = $this->getInlineDataStream($data);
78
            }
79
        }
80
81
        return $this->dataStreams;
82
    }
83
84
    /**
85
     * @return object
86
     */
87
    public function descriptor()
88
    {
89
        return $this->descriptor;
90
    }
91
92
    /**
93
     * @return string
94
     */
95
    public function name()
96
    {
97
        return $this->descriptor()->name;
98
    }
99
100
    public function path()
101
    {
102
        if (isset($this->descriptor()->path)) {
103
            $path = $this->descriptor()->path;
104
            if (!is_array($path)) {
105
                $path = [$path];
106
            }
107
108
            return $path;
109
        } else {
110
            return [];
111
        }
112
    }
113
114
    public function data()
115
    {
116
        return isset($this->descriptor()->data) ? $this->descriptor()->data : null;
117
    }
118
119
    // standard iterator functions - to iterate over the data sources
120
    public function rewind()
121
    {
122
        $this->dataStreams = null;
123
        $this->currentDataStream = 0;
124
        foreach ($this->dataStreams() as $dataStream) {
125
            $dataStream->rewind();
126
        }
127
    }
128
129
    public function current()
130
    {
131
        return $this->dataStreams()[$this->currentDataStream]->current();
132
    }
133
134
    public function key()
135
    {
136
        return $this->dataStreams()[$this->currentDataStream]->key();
137
    }
138
139
    public function next()
140
    {
141
        return $this->dataStreams()[$this->currentDataStream]->next();
142
    }
143
144
    public function valid()
145
    {
146
        $dataStreams = $this->dataStreams();
147
        if ($dataStreams[$this->currentDataStream]->valid()) {
148
            // current data stream is still valid
149
            return true;
150
        } else {
151
            ++$this->currentDataStream;
152
            if (isset($dataStreams[$this->currentDataStream])) {
153
                // current data stream is done, but we have another data stream
154
                return true;
155
            } else {
156
                // no more data and no more data streams
157
                return false;
158
            }
159
        }
160
    }
161
162
    public function getFileExtension()
163
    {
164
        return '';
165
    }
166
167
    public function save($baseFilename)
168
    {
169
        $dataStreams = $this->dataStreams();
170
        $numDataStreams = count($dataStreams);
171
        $fileNames = [];
172
        $i = 0;
173
        foreach ($dataStreams as $dataStream) {
174
            if ($numDataStreams == 1) {
175
                $filename = $baseFilename.$this->getFileExtension();
176
            } else {
177
                $filename = $baseFilename.'-data-'.$i.$this->getFileExtension();
178
            }
179
            $fileNames[] = $filename;
180
            $dataStream->save($filename);
181
            ++$i;
182
        }
183
184
        return $fileNames;
185
    }
186
187
    public static function validateDataSource($dataSource, $basePath = null)
188
    {
189
        $errors = [];
190
        $dataSource = static::normalizeDataSource($dataSource, $basePath);
191
        if (!Utils::isHttpSource($dataSource) && !file_exists($dataSource)) {
192
            $errors[] = new ResourceValidationError(
193
                ResourceValidationError::SCHEMA_VIOLATION,
194
                "data source file does not exist or is not readable: {$dataSource}"
195
            );
196
        }
197
198
        return $errors;
199
    }
200
201
    /**
202
     * allows extending classes to add custom sources
203
     * used by unit tests to add a mock http source.
204
     *
205
     * @param string $dataSource
206
     * @param string $basePath
207
     *
208
     * @return string
209
     */
210
    public static function normalizeDataSource($dataSource, $basePath = null)
211
    {
212
        if (!empty($basePath) && !Utils::isHttpSource($dataSource)) {
213
            // TODO: support JSON pointers
214
            $absPath = $basePath.DIRECTORY_SEPARATOR.$dataSource;
215
            if (file_exists($absPath)) {
216
                $dataSource = $absPath;
217
            }
218
        }
219
220
        return $dataSource;
221
    }
222
223
    protected $descriptor;
224
    protected $basePath;
225
    protected $skipValidations = false;
226
    protected $currentDataPosition = 0;
227
    protected $currentDataStream = 0;
228
    protected $dataStreams = null;
229
230
    protected function validateResource()
231
    {
232
        return ResourceValidator::validate($this->descriptor(), $this->basePath);
233
    }
234
235
    /**
236
     * @param string $dataSource
237
     *
238
     * @return BaseDataStream
239
     */
240
    abstract protected function getDataStream($dataSource);
241
242
    abstract protected function getInlineDataStream($data);
243
244
    protected static function handlesProfile($profile)
245
    {
246
        return false;
247
    }
248
}
249