Completed
Push — master ( 1675a6...057633 )
by Julien
10s
created

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