Completed
Push — master ( 29e67b...7f2aa4 )
by David
14s
created

Service::addSharedEnvVariable()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 1
nc 1
nop 2
dl 0
loc 3
rs 10
c 0
b 0
f 0
1
<?php
2
3
namespace TheAentMachine\Service;
4
5
use Opis\JsonSchema\ValidationError;
6
use Opis\JsonSchema\Validator;
7
use TheAentMachine\Service\Enum\EnvVariableTypeEnum;
8
use TheAentMachine\Service\Enum\VolumeTypeEnum;
9
use TheAentMachine\Service\Environment\EnvVariable;
10
use TheAentMachine\Service\Exception\ServiceException;
11
use TheAentMachine\Service\Volume\BindVolume;
12
use TheAentMachine\Service\Volume\NamedVolume;
13
use TheAentMachine\Service\Volume\TmpfsVolume;
14
15
class Service implements \JsonSerializable
16
{
17
    /** @var string */
18
    private $serviceName = '';
19
    /** @var string */
20
    private $image = '';
21
    /** @var int[] */
22
    private $internalPorts = [];
23
    /** @var string[] */
24
    private $dependsOn = [];
25
    /** @var mixed[] */
26
    private $ports = [];
27
    /** @var mixed[] */
28
    private $labels = [];
29
    /** @var mixed[] */
30
    private $environment = [];
31
    /** @var mixed[] */
32
    private $volumes = [];
33
    /** @var \stdClass */
34
    private $validatorSchema;
35
36
    /**
37
     * Service constructor.
38
     */
39
    public function __construct()
40
    {
41
        $this->validatorSchema = json_decode(file_get_contents(__DIR__ . '/ServiceJsonSchema.json'), false);
42
    }
43
44
    /**
45
     * @param mixed[] $payload
46
     * @return Service
47
     * @throws ServiceException
48
     */
49
    public static function parsePayload(array $payload): Service
50
    {
51
        $service = new Service();
52
        $service->checkValidity($payload);
53
        $service->serviceName = $payload['serviceName'] ?? '';
54
        $s = $payload['service'] ?? array();
55
        if (!empty($s)) {
56
            $service->image = $s['image'] ?? '';
57
            $service->internalPorts = $s['internalPorts'] ?? array();
58
            $service->dependsOn = $s['dependsOn'] ?? array();
59
            $service->ports = $s['ports'] ?? array();
60
            $service->labels = $s['labels'] ?? array();
61
            if (!empty($s['environment'])) {
62
                foreach ($s['environment'] as $key => $env) {
63
                    $service->addEnvVar($key, $env['value'], $env['type']);
64
                }
65
            }
66
            if (!empty($s['volumes'])) {
67
                foreach ($s['volumes'] as $vol) {
68
                    $service->addVolume($vol['type'], $vol['source'], $vol['target'] ?? '', $vol['readOnly'] ?? null);
0 ignored issues
show
Bug introduced by
It seems like $vol['readOnly'] ?? null can also be of type null; however, parameter $readOnly of TheAentMachine\Service\Service::addVolume() does only seem to accept boolean, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

68
                    $service->addVolume($vol['type'], $vol['source'], $vol['target'] ?? '', /** @scrutinizer ignore-type */ $vol['readOnly'] ?? null);
Loading history...
69
                }
70
            }
71
        }
72
        return $service;
73
    }
74
75
    /**
76
     * Specify data which should be serialized to JSON
77
     * @link http://php.net/manual/en/jsonserializable.jsonserialize.php
78
     * @return array data which can be serialized by <b>json_encode</b>,
79
     * which is a value of any type other than a resource.
80
     * @since 5.4.0
81
     * @throws ServiceException
82
     */
83
    public function jsonSerialize(): array
84
    {
85
        $jsonSerializeMap = function (\JsonSerializable $obj): array {
86
            return $obj->jsonSerialize();
87
        };
88
89
        $array = self::arrayFilterRec(array(
90
            'serviceName' => $this->serviceName,
91
            'service' => [
92
                'image' => $this->image,
93
                'internalPorts' => $this->internalPorts,
94
                'dependsOn' => $this->dependsOn,
95
                'ports' => $this->ports,
96
                'labels' => $this->labels,
97
                'environment' => array_map($jsonSerializeMap, $this->environment),
98
                'volumes' => array_map($jsonSerializeMap, $this->volumes),
99
            ]
100
        ));
101
102
        $this->checkValidity($array);
103
        return $array;
104
    }
105
106
    /**
107
     * @param \stdClass|array|string $data
108
     * @return bool
109
     * @throws ServiceException
110
     */
111
    private function checkValidity($data): bool
112
    {
113
        if (\is_array($data)) {
114
            $data = json_decode(json_encode($data), false);
115
        }
116
        $validator = new Validator();
117
        $result = $validator->dataValidation($data, $this->validatorSchema);
118
        if (!$result->isValid()) {
119
            /** @var ValidationError $vError */
120
            $vError = $result->getFirstError();
121
            throw ServiceException::invalidServiceData($vError);
122
        }
123
        return $result->isValid();
124
    }
125
126
    /**
127
     * Delete all key/value pairs with empty value by recursively using array_filter
128
     * @param array $input
129
     * @return mixed[] array
130
     */
131
    private static function arrayFilterRec(array $input): array
132
    {
133
        foreach ($input as &$value) {
134
            if (\is_array($value)) {
135
                $value = self::arrayFilterRec($value);
136
            }
137
        }
138
        return array_filter($input);
139
    }
140
141
142
    /**
143
     * @return string
144
     */
145
    public function getServiceName(): string
146
    {
147
        return $this->serviceName;
148
    }
149
150
    /**
151
     * @return string
152
     */
153
    public function getImage(): string
154
    {
155
        return $this->image;
156
    }
157
158
    /**
159
     * @return int[]
160
     */
161
    public function getInternalPorts(): array
162
    {
163
        return $this->internalPorts;
164
    }
165
166
    /**
167
     * @return string[]
168
     */
169
    public function getDependsOn(): array
170
    {
171
        return $this->dependsOn;
172
    }
173
174
    /**
175
     * @return mixed[]
176
     */
177
    public function getPorts(): array
178
    {
179
        return $this->ports;
180
    }
181
182
    /**
183
     * @return mixed[]
184
     */
185
    public function getLabels(): array
186
    {
187
        return $this->labels;
188
    }
189
190
    /**
191
     * @return mixed[]
192
     */
193
    public function getEnvironment(): array
194
    {
195
        return $this->environment;
196
    }
197
198
    /**
199
     * @return mixed[]
200
     */
201
    public function getVolumes(): array
202
    {
203
        return $this->volumes;
204
    }
205
206
    /**
207
     * @param string $serviceName
208
     */
209
    public function setServiceName(string $serviceName): void
210
    {
211
        $this->serviceName = $serviceName;
212
    }
213
214
    /**
215
     * @param string $image
216
     */
217
    public function setImage(string $image): void
218
    {
219
        $this->image = $image;
220
    }
221
222
    /**
223
     * @param int[] $internalPorts
224
     */
225
    public function setInternalPorts(array $internalPorts): void
226
    {
227
        $this->internalPorts = $internalPorts;
228
    }
229
230
    /**
231
     * @param string[] $dependsOn
232
     */
233
    public function setDependsOn(array $dependsOn): void
234
    {
235
        $this->dependsOn = $dependsOn;
236
    }
237
238
    /**
239
     * @param int $internalPort
240
     */
241
    public function addInternalPort(int $internalPort): void
242
    {
243
        $this->internalPorts[] = $internalPort;
244
    }
245
246
    /**
247
     * @param string $dependsOn
248
     */
249
    public function addDependsOn(string $dependsOn): void
250
    {
251
        $this->dependsOn[] = $dependsOn;
252
    }
253
254
    /**
255
     * @param int $source
256
     * @param int $target
257
     */
258
    public function addPort(int $source, int $target): void
259
    {
260
        $this->ports[] = array(
261
            'source' => $source,
262
            'target' => $target,
263
        );
264
    }
265
266
    /**
267
     * @param string $key
268
     * @param string $value
269
     */
270
    public function addLabel(string $key, string $value): void
271
    {
272
        $this->labels[] = array(
273
            'key' => $key,
274
            'values' => $value,
275
        );
276
    }
277
278
    /**
279
     * @param string $key
280
     * @param string $value
281
     * @param string $type
282
     * @throws ServiceException
283
     */
284
    private function addEnvVar(string $key, string $value, string $type): void
285
    {
286
        switch ($type) {
287
            case EnvVariableTypeEnum::SHARED_ENV_VARIABLE:
288
                $this->addSharedEnvVariable($key, $value);
289
                break;
290
            case EnvVariableTypeEnum::SHARED_SECRET:
291
                $this->addSharedSecret($key, $value);
292
                break;
293
            case EnvVariableTypeEnum::IMAGE_ENV_VARIABLE:
294
                $this->addImageEnvVariable($key, $value);
295
                break;
296
            case EnvVariableTypeEnum::CONTAINER_ENV_VARIABLE:
297
                $this->addContainerEnvVariable($key, $value);
298
                break;
299
            default:
300
                throw ServiceException::unknownEnvVariableType($type);
301
        }
302
    }
303
304
    /**
305
     * @param string $key
306
     * @param string $value
307
     */
308
    public function addSharedEnvVariable(string $key, string $value): void
309
    {
310
        $this->environment[$key] = new EnvVariable($value, 'sharedEnvVariable');
311
    }
312
313
    /**
314
     * @param string $key
315
     * @param string $value
316
     */
317
    public function addSharedSecret(string $key, string $value): void
318
    {
319
        $this->environment[$key] = new EnvVariable($value, 'sharedSecret');
320
    }
321
322
    /**
323
     * @param string $key
324
     * @param string $value
325
     */
326
    public function addImageEnvVariable(string $key, string $value): void
327
    {
328
        $this->environment[$key] = new EnvVariable($value, 'imageEnvVariable');
329
    }
330
331
    /**
332
     * @param string $key
333
     * @param string $value
334
     */
335
    public function addContainerEnvVariable(string $key, string $value): void
336
    {
337
        $this->environment[$key] = new EnvVariable($value, 'containerEnvVariable');
338
    }
339
340
    /**
341
     * @param string $type
342
     * @param string $source
343
     * @param string $target
344
     * @param bool $readOnly
345
     * @throws ServiceException
346
     */
347
    private function addVolume(string $type, string $source, string $target = '', bool $readOnly = false): void
348
    {
349
        switch ($type) {
350
            case VolumeTypeEnum::NAMED_VOLUME:
351
                $this->addNamedVolume($source, $target, $readOnly);
352
                break;
353
            case VolumeTypeEnum::BIND_VOLUME:
354
                $this->addBindVolume($source, $target, $readOnly);
355
                break;
356
            case VolumeTypeEnum::TMPFS_VOLUME:
357
                $this->addTmpfsVolume($source);
358
                break;
359
            default:
360
                throw ServiceException::unknownVolumeType($type);
361
        }
362
    }
363
364
    /**
365
     * @param string $source
366
     * @param string $target
367
     * @param bool $readOnly
368
     */
369
    public function addNamedVolume(string $source, string $target, bool $readOnly = false): void
370
    {
371
        $this->volumes[] = new NamedVolume($source, $target, $readOnly);
372
    }
373
374
    /**
375
     * @param string $source
376
     * @param string $target
377
     * @param bool $readOnly
378
     */
379
    public function addBindVolume(string $source, string $target, bool $readOnly = false): void
380
    {
381
        $this->volumes[] = new BindVolume($source, $target, $readOnly);
382
    }
383
384
    /**
385
     * @param string $source
386
     */
387
    public function addTmpfsVolume(string $source): void
388
    {
389
        $this->volumes[] = new TmpfsVolume($source);
390
    }
391
}
392