Completed
Push — master ( e05ed3...7953c8 )
by Julien
05:16
created

AddEvent::processSetupType()   A

Complexity

Conditions 4
Paths 3

Size

Total Lines 16
Code Lines 14

Duplication

Lines 0
Ratio 0 %

Importance

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