Completed
Push — master ( 0c3e92...3c3b41 )
by Ori
01:47
created

BaseDatapackage::resource()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 8
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 5
nc 2
nop 2
dl 0
loc 8
rs 9.4285
c 0
b 0
f 0
1
<?php
2
3
namespace frictionlessdata\datapackage\Datapackages;
4
5
use frictionlessdata\datapackage\Factory;
6
use frictionlessdata\datapackage\Registry;
7
use frictionlessdata\datapackage\Utils;
8
use frictionlessdata\datapackage\Validators\DatapackageValidator;
9
use frictionlessdata\datapackage\Exceptions\DatapackageValidationFailedException;
10
use Alchemy\Zippy\Zippy;
11
12
abstract class BaseDatapackage implements \Iterator
13
{
14
    /**
15
     * BaseDatapackage constructor.
16
     *
17
     * @param object      $descriptor
18
     * @param null|string $basePath
19
     *
20
     * @throws DatapackageValidationFailedException
21
     */
22
    public function __construct($descriptor, $basePath = null, $skipValidations = false)
23
    {
24
        $this->descriptor = $descriptor;
25
        $this->basePath = $basePath;
26
        $this->skipValidations = $skipValidations;
27
        if (!$this->skipValidations) {
28
            $this->revalidate();
29
        }
30
    }
31
32
    public static function create($name, $resources, $basePath = null)
33
    {
34
        $datapackage = new static((object) [
35
            'name' => $name,
36
            'resources' => [],
37
        ], $basePath, true);
38
        foreach ($resources as $resource) {
39
            $datapackage->addResource($resource);
0 ignored issues
show
Bug introduced by
The call to addResource() misses a required argument $resource.

This check looks for function calls that miss required arguments.

Loading history...
40
        }
41
42
        return $datapackage;
43
    }
44
45
    public function revalidate()
46
    {
47
        $this->rewind();
48
        $validationErrors = $this->datapackageValidate();
49
        if (count($validationErrors) > 0) {
50
            throw new DatapackageValidationFailedException($validationErrors);
51
        }
52
    }
53
54
    public static function handlesDescriptor($descriptor)
55
    {
56
        return static::handlesProfile(Registry::getDatapackageValidationProfile($descriptor));
57
    }
58
59
    /**
60
     * returns the descriptor as-is, without adding default values or normalizing.
61
     *
62
     * @return object
63
     */
64
    public function descriptor()
65
    {
66
        return $this->descriptor;
67
    }
68
69
    public function resources()
70
    {
71
        $resources = [];
72
        foreach ($this->descriptor->resources as $resourceDescriptor) {
73
            $resources[$resourceDescriptor->name] = $this->initResource($resourceDescriptor);
74
        }
75
76
        return $resources;
77
    }
78
79
    public function getResource($name)
80
    {
81
        foreach ($this->descriptor->resources as $resourceDescriptor) {
82
            if ($resourceDescriptor->name == $name) {
83
                return $this->initResource($resourceDescriptor);
84
            }
85
        }
86
        throw new \Exception("couldn't find matching resource with name =  '{$name}'");
87
    }
88
89
    public function addResource($name, $resource)
90
    {
91
        if (is_a($resource, 'frictionlessdata\\datapackage\\Resources\\BaseResource')) {
92
            $resource = $resource->descriptor();
93
        } else {
94
            $resource = Utils::objectify($resource);
95
        }
96
        $resource->name = $name;
97
        $resourceDescriptors = [];
98
        $gotMatch = false;
99
        foreach ($this->descriptor->resources as $resourceDescriptor) {
100
            if ($resourceDescriptor->name == $resource->name) {
101
                $resourceDescriptors[] = $resource;
102
                $gotMatch = true;
103
            } else {
104
                $resourceDescriptors[] = $resourceDescriptor;
105
            }
106
        }
107
        if (!$gotMatch) {
108
            $resourceDescriptors[] = $resource;
109
        }
110
        $this->descriptor->resources = $resourceDescriptors;
111
        if (!$this->skipValidations) {
112
            $this->revalidate();
113
        }
114
    }
115
116
    // TODO: remove this function and use the getResource / addResource directly (will need to modify a lot of tests code)
117
    public function resource($name, $resource = null)
118
    {
119
        if ($resource) {
120
            $this->addResource($name, $resource);
121
        } else {
122
            return $this->getResource($name);
123
        }
124
    }
125
126
    public function removeResource($name)
127
    {
128
        $resourceDescriptors = [];
129
        foreach ($this->descriptor->resources as $resourceDescriptor) {
130
            if ($resourceDescriptor->name != $name) {
131
                $resourceDescriptors[] = $resourceDescriptor;
132
            }
133
        }
134
        $this->descriptor->resources = $resourceDescriptors;
135
        if (!$this->skipValidations) {
136
            $this->revalidate();
137
        }
138
    }
139
140
    public function saveDescriptor($filename)
141
    {
142
        return file_put_contents($filename, json_encode($this->descriptor()));
143
    }
144
145
    // standard iterator functions - to iterate over the resources
146
    public function rewind()
147
    {
148
        $this->currentResourcePosition = 0;
149
    }
150
151
    public function current()
152
    {
153
        return $this->initResource($this->descriptor()->resources[$this->currentResourcePosition]);
154
    }
155
156
    public function key()
157
    {
158
        return $this->currentResourcePosition;
159
    }
160
161
    public function next()
162
    {
163
        ++$this->currentResourcePosition;
164
    }
165
166
    public function valid()
167
    {
168
        return isset($this->descriptor()->resources[$this->currentResourcePosition]);
169
    }
170
171
    public function save($zip_filename)
172
    {
173
        $zippy = Zippy::load();
174
        $base = tempnam(sys_get_temp_dir(), 'datapackage-zip-');
175
        $files = [
176
            'datapackage.json' => $base.'datapackage.json',
177
        ];
178
        $ri = 0;
179
        foreach ($this as $resource) {
180
            $fileNames = $resource->save($base.'resource-'.$ri);
181
            foreach ($fileNames as $fileName) {
182
                $relname = str_replace($base.'resource-'.$ri, '', $fileName);
183
                $files['resource-'.$ri.$relname] = $fileName;
184
            }
185
            ++$ri;
186
        }
187
        $this->saveDescriptor($files['datapackage.json']);
188
        $zippy->create($zip_filename, $files);
189
        foreach (array_values($files) as $file) {
190
            unlink($file);
191
        }
192
    }
193
194
    protected $descriptor;
195
    protected $currentResourcePosition = 0;
196
    protected $basePath;
197
    protected $skipValidations = false;
198
199
    /**
200
     * called by the resources iterator for each iteration.
201
     *
202
     * @param object $descriptor
203
     *
204
     * @return \frictionlessdata\datapackage\Resources\BaseResource
205
     */
206
    protected function initResource($descriptor)
207
    {
208
        return Factory::resource($descriptor, $this->basePath, $this->skipValidations);
209
    }
210
211
    protected function datapackageValidate()
212
    {
213
        return DatapackageValidator::validate($this->descriptor(), $this->basePath);
214
    }
215
216
    protected static function handlesProfile($profile)
217
    {
218
        return false;
219
    }
220
}
221