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

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