Completed
Pull Request — master (#33)
by Jindun
12:01 queued 05:56
created

Service::getDependsOn()   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 0
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|null */
20
    private $image = null;
21
    /** @var string[] */
22
    private $command = [];
23
    /** @var int[] */
24
    private $internalPorts = [];
25
    /** @var string[] */
26
    private $dependsOn = [];
27
    /** @var mixed[] */
28
    private $ports = [];
29
    /** @var mixed[] */
30
    private $labels = [];
31
    /** @var mixed[] */
32
    private $environment = [];
33
    /** @var mixed[] */
34
    private $volumes = [];
35
    /** @var \stdClass */
36
    private $validatorSchema;
37
    /** @var string[] */
38
    private $dockerfileCommands = [];
39
40
    /**
41
     * Service constructor.
42
     */
43
    public function __construct()
44
    {
45
        $this->validatorSchema = json_decode((string)file_get_contents(__DIR__ . '/ServiceJsonSchema.json'), false);
46
    }
47
48
    /**
49
     * @param mixed[] $payload
50
     * @return Service
51
     * @throws ServiceException
52
     */
53
    public static function parsePayload(array $payload): Service
54
    {
55
        $service = new self();
56
        $service->checkValidity($payload);
57
        $service->serviceName = $payload['serviceName'] ?? '';
58
        $s = $payload['service'] ?? [];
59
        if (!empty($s)) {
60
            $service->image = $s['image'] ?? null;
61
            $service->command = $s['command'] ?? [];
62
            $service->internalPorts = $s['internalPorts'] ?? [];
63
            $service->dependsOn = $s['dependsOn'] ?? [];
64
            $service->ports = $s['ports'] ?? [];
65
            $service->labels = $s['labels'] ?? [];
66
            if (!empty($s['environment'])) {
67
                foreach ($s['environment'] as $key => $env) {
68
                    $service->addEnvVar($key, $env['value'], $env['type']);
69
                }
70
            }
71
            if (!empty($s['volumes'])) {
72
                foreach ($s['volumes'] as $vol) {
73
                    $service->addVolume($vol['type'], $vol['source'], $vol['target'] ?? '', $vol['readOnly'] ?? false);
74
                }
75
            }
76
        }
77
        $service->dockerfileCommands = $payload['dockerfileCommands'] ?? [];
78
        return $service;
79
    }
80
81
    /**
82
     * Specify data which should be serialized to JSON
83
     * @link http://php.net/manual/en/jsonserializable.jsonserialize.php
84
     * @return array data which can be serialized by <b>json_encode</b>,
85
     * which is a value of any type other than a resource.
86
     * @since 5.4.0
87
     * @throws ServiceException
88
     */
89
    public function jsonSerialize(): array
90
    {
91
        $jsonSerializeMap = function (\JsonSerializable $obj): array {
92
            return $obj->jsonSerialize();
93
        };
94
95
        $json = array(
96
            'serviceName' => $this->serviceName,
97
        );
98
99
        $service = array_filter([
100
            'image' => $this->image,
101
            'command' => $this->command,
102
            'internalPorts' => $this->internalPorts,
103
            'dependsOn' => $this->dependsOn,
104
            'ports' => $this->ports,
105
            'labels' => $this->labels,
106
            'environment' => array_map($jsonSerializeMap, $this->environment),
107
            'volumes' => array_map($jsonSerializeMap, $this->volumes),
108
        ]);
109
110
        if (!empty($service)) {
111
            $json['service'] = $service;
112
        }
113
114
        if (!empty($this->dockerfileCommands)) {
115
            $json['dockerfileCommands'] = $this->dockerfileCommands;
116
        }
117
118
        $this->checkValidity($json);
119
        return $json;
120
    }
121
122
    /**
123
     * @return mixed[]
124
     * @throws ServiceException
125
     */
126
    public function imageJsonSerialize(): array
127
    {
128
        $this->dockerfileCommands[] = 'FROM ' . $this->image;
129
        foreach ($this->environment as $key => $env) {
130
            if ($env->getType() === EnvVariableTypeEnum::IMAGE_ENV_VARIABLE) {
131
                $this->dockerfileCommands[] = "ENV $key" . '='. $env->getValue();
132
            }
133
        }
134
        foreach ($this->volumes as $volume) {
135
            if ($volume->getType() === VolumeTypeEnum::BIND_VOLUME) {
136
                $this->dockerfileCommands[] = 'COPY ' . $volume->getSource() . ' ' . $volume->getTarget();
137
            }
138
        }
139
140
        if (!empty($this->command)) {
141
            $this->dockerfileCommands[] = 'CMD ' . implode(' ', $this->command);
142
        }
143
144
145
        return $this->jsonSerialize();
146
    }
147
148
    /**
149
     * @param \stdClass|array|string $data
150
     * @return bool
151
     * @throws ServiceException
152
     */
153
    private function checkValidity($data): bool
154
    {
155
        if (\is_array($data)) {
156
            $data = \GuzzleHttp\json_decode(\GuzzleHttp\json_encode($data), false);
157
        }
158
        $validator = new Validator();
159
        $result = $validator->dataValidation($data, $this->validatorSchema);
160
        if (!$result->isValid()) {
161
            /** @var ValidationError $vError */
162
            $vError = $result->getFirstError();
163
            throw ServiceException::invalidServiceData($vError);
164
        }
165
        return $result->isValid();
166
    }
167
168
    /**
169
     * @return string
170
     */
171
    public function getServiceName(): string
172
    {
173
        return $this->serviceName;
174
    }
175
176
    /**
177
     * @return string|null
178
     */
179
    public function getImage(): ?string
180
    {
181
        return $this->image;
182
    }
183
184
    /**
185
     * @return string[]
186
     */
187
    public function getCommand(): array
188
    {
189
        return $this->command;
190
    }
191
192
    /**
193
     * @return int[]
194
     */
195
    public function getInternalPorts(): array
196
    {
197
        return $this->internalPorts;
198
    }
199
200
    /**
201
     * @return string[]
202
     */
203
    public function getDependsOn(): array
204
    {
205
        return $this->dependsOn;
206
    }
207
208
    /**
209
     * @return mixed[]
210
     */
211
    public function getPorts(): array
212
    {
213
        return $this->ports;
214
    }
215
216
    /**
217
     * @return mixed[]
218
     */
219
    public function getLabels(): array
220
    {
221
        return $this->labels;
222
    }
223
224
    /**
225
     * @return mixed[]
226
     */
227
    public function getEnvironment(): array
228
    {
229
        return $this->environment;
230
    }
231
232
    /**
233
     * @return mixed[]
234
     */
235
    public function getVolumes(): array
236
    {
237
        return $this->volumes;
238
    }
239
240
    /**
241
     * @return string[]
242
     */
243
    public function getDockerfileCommands(): array
244
    {
245
        return $this->dockerfileCommands;
246
    }
247
248
    /**
249
     * @param string $serviceName
250
     */
251
    public function setServiceName(string $serviceName): void
252
    {
253
        $this->serviceName = $serviceName;
254
    }
255
256
    /**
257
     * @param string|null $image
258
     */
259
    public function setImage(?string $image): void
260
    {
261
        $this->image = $image;
262
    }
263
264
    /**
265
     * @param string[] $command
266
     */
267
    public function setCommand(array $command): void
268
    {
269
        $this->command = $command;
270
    }
271
272
    /**
273
     * @param int[] $internalPorts
274
     */
275
    public function setInternalPorts(array $internalPorts): void
276
    {
277
        $this->internalPorts = $internalPorts;
278
    }
279
280
    /**
281
     * @param string[] $dependsOn
282
     */
283
    public function setDependsOn(array $dependsOn): void
284
    {
285
        $this->dependsOn = $dependsOn;
286
    }
287
288
    /**
289
     * @param string $command
290
     */
291
    public function addCommand(string $command): void
292
    {
293
        $this->command[] = $command;
294
    }
295
296
    /**
297
     * @param int $internalPort
298
     */
299
    public function addInternalPort(int $internalPort): void
300
    {
301
        $this->internalPorts[] = $internalPort;
302
    }
303
304
    /**
305
     * @param string $dependsOn
306
     */
307
    public function addDependsOn(string $dependsOn): void
308
    {
309
        $this->dependsOn[] = $dependsOn;
310
    }
311
312
    /**
313
     * @param int $source
314
     * @param int $target
315
     */
316
    public function addPort(int $source, int $target): void
317
    {
318
        $this->ports[] = array(
319
            'source' => $source,
320
            'target' => $target,
321
        );
322
    }
323
324
    /**
325
     * @param string $key
326
     * @param string $value
327
     */
328
    public function addLabel(string $key, string $value): void
329
    {
330
        $this->labels[$key] = array(
331
            'value' => $value,
332
        );
333
    }
334
335
    /**
336
     * @param string $key
337
     * @param string $value
338
     * @param string $type
339
     * @throws ServiceException
340
     */
341
    private function addEnvVar(string $key, string $value, string $type): void
342
    {
343
        switch ($type) {
344
            case EnvVariableTypeEnum::SHARED_ENV_VARIABLE:
345
                $this->addSharedEnvVariable($key, $value);
346
                break;
347
            case EnvVariableTypeEnum::SHARED_SECRET:
348
                $this->addSharedSecret($key, $value);
349
                break;
350
            case EnvVariableTypeEnum::IMAGE_ENV_VARIABLE:
351
                $this->addImageEnvVariable($key, $value);
352
                break;
353
            case EnvVariableTypeEnum::CONTAINER_ENV_VARIABLE:
354
                $this->addContainerEnvVariable($key, $value);
355
                break;
356
            default:
357
                throw ServiceException::unknownEnvVariableType($type);
358
        }
359
    }
360
361
    /**
362
     * @param string $key
363
     * @param string $value
364
     */
365
    public function addSharedEnvVariable(string $key, string $value): void
366
    {
367
        $this->environment[$key] = new EnvVariable($value, 'sharedEnvVariable');
368
    }
369
370
    /**
371
     * @param string $key
372
     * @param string $value
373
     */
374
    public function addSharedSecret(string $key, string $value): void
375
    {
376
        $this->environment[$key] = new EnvVariable($value, 'sharedSecret');
377
    }
378
379
    /**
380
     * @param string $key
381
     * @param string $value
382
     */
383
    public function addImageEnvVariable(string $key, string $value): void
384
    {
385
        $this->environment[$key] = new EnvVariable($value, 'imageEnvVariable');
386
    }
387
388
    /**
389
     * @param string $key
390
     * @param string $value
391
     */
392
    public function addContainerEnvVariable(string $key, string $value): void
393
    {
394
        $this->environment[$key] = new EnvVariable($value, 'containerEnvVariable');
395
    }
396
397
    /**
398
     * @param string $type
399
     * @param string $source
400
     * @param string $target
401
     * @param bool $readOnly
402
     * @throws ServiceException
403
     */
404
    private function addVolume(string $type, string $source, string $target = '', bool $readOnly = false): void
405
    {
406
        switch ($type) {
407
            case VolumeTypeEnum::NAMED_VOLUME:
408
                $this->addNamedVolume($source, $target, $readOnly);
409
                break;
410
            case VolumeTypeEnum::BIND_VOLUME:
411
                $this->addBindVolume($source, $target, $readOnly);
412
                break;
413
            case VolumeTypeEnum::TMPFS_VOLUME:
414
                $this->addTmpfsVolume($source);
415
                break;
416
            default:
417
                throw ServiceException::unknownVolumeType($type);
418
        }
419
    }
420
421
    /**
422
     * @param string $source
423
     * @param string $target
424
     * @param bool $readOnly
425
     */
426
    public function addNamedVolume(string $source, string $target, bool $readOnly = false): void
427
    {
428
        $this->volumes[] = new NamedVolume($source, $target, $readOnly);
429
    }
430
431
    /**
432
     * @param string $source
433
     * @param string $target
434
     * @param bool $readOnly
435
     */
436
    public function addBindVolume(string $source, string $target, bool $readOnly = false): void
437
    {
438
        $this->volumes[] = new BindVolume($source, $target, $readOnly);
439
    }
440
441
    /**
442
     * @param string $source
443
     */
444
    public function addTmpfsVolume(string $source): void
445
    {
446
        $this->volumes[] = new TmpfsVolume($source);
447
    }
448
449
    /**
450
     * @param string $dockerfileCommand
451
     */
452
    public function addDockerfileCommand(string $dockerfileCommand): void
453
    {
454
        $this->dockerfileCommands[] = $dockerfileCommand;
455
    }
456
457
    public function generateDockerFileCommands(): void
458
    {
459
        // TODO
460
    }
461
}
462