AddEvent::getOrchestratorAent()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 3
nc 1
nop 2
dl 0
loc 5
rs 10
c 0
b 0
f 0
1
<?php
2
3
namespace TheAentMachine\AentBootstrap\Event;
4
5
use Safe\Exceptions\ArrayException;
6
use Safe\Exceptions\StringsException;
7
use TheAentMachine\Aent\Context\Context;
8
use TheAentMachine\Aent\Event\Bootstrap\AbstractBootstrapAddEvent;
9
use TheAentMachine\Aent\Event\Bootstrap\Model\OrchestratorBootstrap;
10
use TheAentMachine\Aent\Registry\AentItemRegistry;
11
use TheAentMachine\Aent\Registry\ColonyRegistry;
12
use TheAentMachine\Aent\Registry\Exception\ColonyRegistryException;
13
use TheAentMachine\Prompt\Helper\ValidatorHelper;
14
15
final class AddEvent extends AbstractBootstrapAddEvent
16
{
17
    /** @var ColonyRegistry */
18
    private $orchestratorRegistry;
19
20
    /** @var OrchestratorBootstrap[] */
21
    private $bootstraps;
22
23
    /** @var string */
24
    private $appName;
25
26
    /** @var string[] */
27
    private $setupTypes = [
28
        'Docker Compose for your development environment',
29
        'Docker Compose for your development environment and Kubernetes for your test environment',
30
        'Docker Compose for your development environment and Kubernetes for your test and production environments',
31
        'Custom',
32
    ];
33
34
    /**
35
     * @return OrchestratorBootstrap[]
36
     * @throws ColonyRegistryException
37
     * @throws StringsException
38
     * @throws ArrayException
39
     */
40
    protected function getOrchestratorsBootstraps(): array
41
    {
42
        $this->orchestratorRegistry = ColonyRegistry::orchestratorRegistry();
43
        $this->bootstraps = [];
44
        $appName = $this->prompt->input("\nYour application name", null, null, true, ValidatorHelper::getAlphaValidator());
45
        $this->appName = \strtolower($appName ?? '');
46
        $this->processSetupType();
47
        return $this->bootstraps;
48
    }
49
50
    /**
51
     * @return void
52
     * @throws ColonyRegistryException
53
     * @throws StringsException
54
     * @throws ArrayException
55
     */
56
    private function processSetupType(): void
57
    {
58
        $setupTypeIndex = $this->getSetupType();
59
        if ($setupTypeIndex < 3) {
60
            $setupType = $this->setupTypes[$setupTypeIndex];
61
            $this->output->writeln("\n👌 Alright, I'm going to setup <info>$setupType</info>!");
62
            $this->addDefaultPayloads($setupTypeIndex);
63
            return;
64
        }
65
        $this->output->writeln("\n👌 In this step, you may add as many environments as you wish. Let's begin with your first environment!");
66
        $this->addCustomPayload();
67
        $this->printSummary($this->bootstraps);
68
        if ($this->prompt->confirm("\nDo you want to add another environment?")) {
69
            do {
70
                $this->addCustomPayload();
71
                $this->printSummary($this->bootstraps);
72
            } while ($this->prompt->confirm("\nDo you want to add another environment?"));
73
        }
74
    }
75
76
    /**
77
     * @return int
78
     */
79
    private function getSetupType(): int
80
    {
81
        $appName = $this->appName;
82
        $helpText = 'We provide a bunch of defaults setup which fit for most cases. By choosing the custom option, you may define your own environments.';
83
        $response = $this->prompt->select("\nYour setup type for <info>$appName</info>", $this->setupTypes, $helpText, null, true);
84
        $setupTypeIndex = \array_search($response, $this->setupTypes);
85
        return $setupTypeIndex !== false ? (int)$setupTypeIndex : 3;
86
    }
87
88
    /**
89
     * @param int $setupTypeIndex
90
     * @return void
91
     * @throws ColonyRegistryException
92
     */
93
    private function addDefaultPayloads(int $setupTypeIndex): void
94
    {
95
        switch ($setupTypeIndex) {
96
            case 0:
97
                // Docker Compose for your development environment
98
                $this->addDockerComposeForDevelopment();
99
                break;
100
            case 1:
101
                // Docker Compose for your development environment and Kubernetes for your test environment
102
                $this->addDockerComposeForDevelopment();
103
                $this->addKubernetesForTest();
104
                break;
105
            default:
106
                // Docker Compose for your development environment and Kubernetes for your test and production environments
107
                $this->addDockerComposeForDevelopment();
108
                $this->addKubernetesForTest();
109
                $this->addKubernetesForProd();
110
        }
111
    }
112
113
    /**
114
     * @return void
115
     * @throws ColonyRegistryException
116
     */
117
    private function addDockerComposeForDevelopment(): void
118
    {
119
        $environmentType = Context::DEV;
120
        $environmentName = 'dev';
121
        $bootstrap = new OrchestratorBootstrap();
122
        $bootstrap->setAent($this->orchestratorRegistry->getAent(ColonyRegistry::DOCKER_COMPOSE));
123
        $bootstrap->setEnvironmentType($environmentType);
124
        $bootstrap->setEnvironmentName($environmentName);
125
        $bootstrap->setBaseVirtualHost($this->getBaseVirtualHost($environmentType, $environmentName));
126
        $this->bootstraps[] = $bootstrap;
127
    }
128
129
    /**
130
     * @return void
131
     * @throws ColonyRegistryException
132
     */
133
    private function addKubernetesForTest(): void
134
    {
135
        $environmentType = Context::TEST;
136
        $environmentName = 'test';
137
        $bootstrap = new OrchestratorBootstrap();
138
        $bootstrap->setAent($this->orchestratorRegistry->getAent(ColonyRegistry::KUBERNETES));
139
        $bootstrap->setEnvironmentType($environmentType);
140
        $bootstrap->setEnvironmentName($environmentName);
141
        $bootstrap->setBaseVirtualHost($this->getBaseVirtualHost($environmentType, $environmentName));
142
        $this->bootstraps[] = $bootstrap;
143
    }
144
145
    /**
146
     * @return void
147
     * @throws ColonyRegistryException
148
     */
149
    private function addKubernetesForProd(): void
150
    {
151
        $environmentType = Context::PROD;
152
        $environmentName = 'prod';
153
        $bootstrap = new OrchestratorBootstrap();
154
        $bootstrap->setAent($this->orchestratorRegistry->getAent(ColonyRegistry::KUBERNETES));
155
        $bootstrap->setEnvironmentType($environmentType);
156
        $bootstrap->setEnvironmentName($environmentName);
157
        $bootstrap->setBaseVirtualHost($this->getBaseVirtualHost($environmentType, $environmentName));
158
        $this->bootstraps[] = $bootstrap;
159
    }
160
161
    /**
162
     * @return void
163
     * @throws ArrayException
164
     * @throws StringsException
165
     */
166
    private function addCustomPayload(): void
167
    {
168
        $typeHelpText = "We organize environments into three categories:\n - <info>development</info>: your local environment\n - <info>test</info>: a remote environment where you're pushing some features to test\n - <info>production</info>: a remote environment for staging/production purpose";
169
        $environmentType = $this->prompt->select("\nYour environment type", Context::getEnvironmentTypeList(), $typeHelpText, null, true) ?? '';
170
        $nameHelpText = "A unique identifier for your environment.\nFor instance, a <info>development</info> environment might be called <info>dev</info>.";
171
        $nameValidator =  ValidatorHelper::merge(
172
            ValidatorHelper::getFuncShouldNotReturnTrueValidator([$this, 'doesEnvironmentNameExist'], 'Environment "%s" does already exist!'),
173
            ValidatorHelper::getAlphaValidator()
174
        );
175
        $environmentName = $this->prompt->input("\nYour <info>$environmentType</info> environment name", $nameHelpText, null, true, $nameValidator) ?? '';
176
        $bootstrap = new OrchestratorBootstrap();
177
        $bootstrap->setEnvironmentType($environmentType);
178
        $bootstrap->setEnvironmentName($environmentName);
179
        $bootstrap->setBaseVirtualHost($this->getBaseVirtualHost($environmentType, $environmentName));
180
        $bootstrap->setAent($this->getOrchestratorAent($environmentType, $environmentName));
181
        $this->bootstraps[] = $bootstrap;
182
    }
183
184
    /**
185
     * @param string $environmentType
186
     * @param string $environmentName
187
     * @return string
188
     */
189
    private function getBaseVirtualHost(string $environmentType, string $environmentName): string
190
    {
191
        $appName = $this->appName;
192
        $default = null;
193
        switch ($environmentType) {
194
            case Context::DEV:
195
                $default = "$appName.localhost";
196
                break;
197
            case Context::TEST:
198
                $default = "$environmentName.$appName.com";
199
                break;
200
            default:
201
                $default = "$appName.com";
202
        }
203
        $default = !empty($default) && !$this->doesBaseVirtualHostExist($default) ? $default : null;
204
        $helpText = "The base virtual host will determine on which URL your web services will be accessible.\nFor instance, if your base virtual host is <info>foo.localhost</info>, a web service may be accessible through <info>{service sub domain}.foo.localhost</info>.";
205
        $validator = ValidatorHelper::merge(
206
            ValidatorHelper::getFuncShouldNotReturnTrueValidator([$this, 'doesBaseVirtualHostExist'], 'Base virtual host "%s" does already exist!'),
207
            ValidatorHelper::getDomainNameValidator()
208
        );
209
        return $this->prompt->input("\nYour base virtual host for your <info>$environmentType</info> environment <info>$environmentName</info>", $helpText, $default, true, $validator) ?? '';
210
    }
211
212
    /**
213
     * @param string $environmentType
214
     * @param string $environmentName
215
     * @return AentItemRegistry
216
     * @throws ArrayException
217
     * @throws StringsException
218
     */
219
    private function getOrchestratorAent(string $environmentType, string $environmentName): AentItemRegistry
220
    {
221
        $text = "\nYour orchestrator for your <info>$environmentType</info> environment <info>$environmentName</info>";
222
        $helpText = 'The orchestrator is a tool which will manage your container.';
223
        return $this->prompt->getPromptHelper()->getFromColonyRegistry($this->orchestratorRegistry, $text, $helpText);
224
    }
225
226
    /**
227
     * @param string $environmentName
228
     * @return bool
229
     */
230
    public function doesEnvironmentNameExist(string $environmentName): bool
231
    {
232
        foreach ($this->bootstraps as $bootstrap) {
233
            if ($bootstrap->getEnvironmentName() === $environmentName) {
234
                return true;
235
            }
236
        }
237
        return false;
238
    }
239
240
    /**
241
     * @param string $baseVirtualHost
242
     * @return bool
243
     */
244
    public function doesBaseVirtualHostExist(string $baseVirtualHost): bool
245
    {
246
        foreach ($this->bootstraps as $bootstrap) {
247
            if ($bootstrap->getBaseVirtualHost() === $baseVirtualHost) {
248
                return true;
249
            }
250
        }
251
        return false;
252
    }
253
}
254