Completed
Push — master ( 22d7bb...dd90a8 )
by Ori
03:00
created

BaseResource::getFileExtension()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 2
nc 1
nop 0
dl 0
loc 4
rs 10
c 0
b 0
f 0
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($options = null)
0 ignored issues
show
Unused Code introduced by
The parameter $options is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
41
    {
42
        $rows = [];
43
        foreach ($this as $row) {
44
            $rows[] = $row;
45
        }
46
47
        return $rows;
48
    }
49
50
    public function dataStreams()
51
    {
52
        if (is_null($this->dataStreams)) {
53
            $this->dataStreams = [];
54
            foreach ($this->path() as $path) {
55
                $this->dataStreams[] = $this->getDataStream($path);
56
            }
57
            $data = $this->data();
58
            if ($data) {
59
                $this->dataStreams[] = $this->getInlineDataStream($data);
60
            }
61
        }
62
63
        return $this->dataStreams;
64
    }
65
66
    /**
67
     * @return object
68
     */
69
    public function descriptor()
70
    {
71
        return $this->descriptor;
72
    }
73
74
    /**
75
     * @return string
76
     */
77
    public function name()
78
    {
79
        return $this->descriptor()->name;
80
    }
81
82
    public function path()
83
    {
84
        if (isset($this->descriptor()->path)) {
85
            $path = $this->descriptor()->path;
86
            if (!is_array($path)) {
87
                $path = [$path];
88
            }
89
90
            return $path;
91
        } else {
92
            return [];
93
        }
94
    }
95
96
    public function data()
97
    {
98
        return isset($this->descriptor()->data) ? $this->descriptor()->data : null;
99
    }
100
101
    // standard iterator functions - to iterate over the data sources
102
    public function rewind()
103
    {
104
        $this->dataStreams = null;
105
        $this->currentDataStream = 0;
106
        foreach ($this->dataStreams() as $dataStream) {
107
            $dataStream->rewind();
108
        }
109
    }
110
111
    public function current()
112
    {
113
        return $this->dataStreams()[$this->currentDataStream]->current();
114
    }
115
116
    public function key()
117
    {
118
        return $this->dataStreams()[$this->currentDataStream]->key();
119
    }
120
121
    public function next()
122
    {
123
        return $this->dataStreams()[$this->currentDataStream]->next();
124
    }
125
126
    public function valid()
127
    {
128
        $dataStreams = $this->dataStreams();
129
        if ($dataStreams[$this->currentDataStream]->valid()) {
130
            // current data stream is still valid
131
            return true;
132
        } else {
133
            ++$this->currentDataStream;
134
            if (isset($dataStreams[$this->currentDataStream])) {
135
                // current data stream is done, but we have another data stream
136
                return true;
137
            } else {
138
                // no more data and no more data streams
139
                return false;
140
            }
141
        }
142
    }
143
144
    public function getFileExtension()
145
    {
146
        return "";
147
    }
148
149
    public function save($baseFilename)
150
    {
151
        $dataStreams = $this->dataStreams();
152
        $numDataStreams = count($dataStreams);
153
        $fileNames = [];
154
        $i = 0;
155
        foreach ($dataStreams as $dataStream) {
156
            if ($numDataStreams == 1) {
157
                $filename = $baseFilename.$this->getFileExtension();
158
            } else {
159
                $filename = $baseFilename."-data-".$i.$this->getFileExtension();
160
            }
161
            $fileNames[] = $filename;
162
            $dataStream->save($filename);
163
            $i++;
164
        }
165
        return $fileNames;
166
    }
167
168
    public static function validateDataSource($dataSource, $basePath = null)
169
    {
170
        $errors = [];
171
        $dataSource = static::normalizeDataSource($dataSource, $basePath);
172
        if (!Utils::isHttpSource($dataSource) && !file_exists($dataSource)) {
173
            $errors[] = new ResourceValidationError(
174
                ResourceValidationError::SCHEMA_VIOLATION,
175
                "data source file does not exist or is not readable: {$dataSource}"
176
            );
177
        }
178
179
        return $errors;
180
    }
181
182
    /**
183
     * allows extending classes to add custom sources
184
     * used by unit tests to add a mock http source.
185
     *
186
     * @param string $dataSource
187
     * @param string $basePath
188
     *
189
     * @return string
190
     */
191
    public static function normalizeDataSource($dataSource, $basePath = null)
192
    {
193
        if (!empty($basePath) && !Utils::isHttpSource($dataSource)) {
194
            // TODO: support JSON pointers
195
            $absPath = $basePath.DIRECTORY_SEPARATOR.$dataSource;
196
            if (file_exists($absPath)) {
197
                $dataSource = $absPath;
198
            }
199
        }
200
201
        return $dataSource;
202
    }
203
204
    protected $descriptor;
205
    protected $basePath;
206
    protected $skipValidations = false;
207
    protected $currentDataPosition = 0;
208
    protected $currentDataStream = 0;
209
    protected $dataStreams = null;
210
211
    protected function validateResource()
212
    {
213
        return ResourceValidator::validate($this->descriptor(), $this->basePath);
214
    }
215
216
    /**
217
     * @param string $dataSource
218
     *
219
     * @return BaseDataStream
220
     */
221
    abstract protected function getDataStream($dataSource);
222
223
    abstract protected function getInlineDataStream($data);
224
225
    protected static function handlesProfile($profile)
226
    {
227
        return false;
228
    }
229
}
230