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

src/Datapackages/BaseDatapackage.php (1 issue)

Labels
Severity

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

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
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