-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathScriptClassAbstract.php
More file actions
160 lines (136 loc) · 6.01 KB
/
ScriptClassAbstract.php
File metadata and controls
160 lines (136 loc) · 6.01 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
<?php
declare(strict_types=1);
namespace MagicPush\CliToolkit\Parametizer\ScriptClass;
use MagicPush\CliToolkit\Parametizer\CliRequest\CliRequest;
use MagicPush\CliToolkit\Parametizer\Config\Builder\ConfigBuilder;
use MagicPush\CliToolkit\Parametizer\Config\Config;
use MagicPush\CliToolkit\Parametizer\EnvironmentConfig;
use MagicPush\CliToolkit\Parametizer\Exception\ConfigException;
use MagicPush\CliToolkit\Parametizer\HelpFormatter;
use MagicPush\CliToolkit\Parametizer\Parametizer;
use MagicPush\CliToolkit\Parametizer\ScriptDetector\ScriptClassDetector;
use MagicPush\CliToolkit\Utils;
use ReflectionClass;
abstract class ScriptClassAbstract {
/** @see Config::newSubcommand() - allowed characters validation */
public const string NAME_SECTION_SEPARATOR = ':';
/** @see Config::newSubcommand() - allowed characters validation */
public const string NAME_PART_SEPARATOR = '-';
/**
* The method is utilized by {@see ScriptClassDetector::processDetectedFileContents()} (only when searching by
* directories) mainly to ignore built-in subcommands, because those are added explicitly by the library.
*
* However, this method does NOT restrict script classes to be actually executed.
*
* You may repurpose this method for any other reason you see fit. Just a few examples:
* * Detect particular scripts for selected environments only.
* Like code generators, which are not very useful on test or production servers.
* * Hide particular scripts from all launchers. Sometimes it might be easier to hide a script here,
* rather excluding it in each {@see ScriptClassDetector} instance.
*/
public static function isAvailableByDetector(): bool {
return true;
}
/**
* In comparison with {@see static::getScriptName()} the method returns only the last part
* of a full script name - without {@see static::getNameSections()}.
*/
public static function getScriptInnerName(): string {
$classShortName = Utils::getClassShortName(static::class);
$scriptName = '';
$previousSymbolUpper = null;
$pendingAbbreviation = '';
foreach (mb_str_split($classShortName) as $symbol) {
$symbolToLower = mb_strtolower($symbol);
if ($symbol !== $symbolToLower) {
$symbol = $symbolToLower;
if (null !== $previousSymbolUpper) {
$pendingAbbreviation .= $previousSymbolUpper;
}
$previousSymbolUpper = $symbol;
} else {
if (null !== $previousSymbolUpper) {
if ($scriptName) {
$scriptName .= static::NAME_PART_SEPARATOR;
}
if ($pendingAbbreviation) {
$scriptName .= $pendingAbbreviation . static::NAME_PART_SEPARATOR;
}
$scriptName .= $previousSymbolUpper;
}
$previousSymbolUpper = null;
$pendingAbbreviation = '';
$scriptName .= $symbol;
}
}
if (null !== $previousSymbolUpper) {
if ($scriptName) {
$scriptName .= static::NAME_PART_SEPARATOR;
}
$scriptName .= $pendingAbbreviation . $previousSymbolUpper;
}
return $scriptName;
}
/**
* @return string[]
*/
public static function getNameSections(): array {
return [];
}
/**
* Returns full script name including {@see static::getNameSections()}.
*/
public static function getScriptName(): string {
$errorFormatter = HelpFormatter::createForStdErr();
$classNameFormatted = $errorFormatter->helpNote(static::class);
$errorMessagePrefix = "Script '{$classNameFormatted}' >>> Config error:";
$localName = trim(static::getScriptInnerName());
if ('' === $localName) {
throw new ConfigException("{$errorMessagePrefix} local name can not be empty.");
}
$fullName = '';
$nameSections = static::getNameSections();
$nameSections[] = $localName;
foreach ($nameSections as $section) {
$sectionFiltered = trim($section);
if ('' === $sectionFiltered) {
continue;
}
if ($fullName) {
$fullName .= static::NAME_SECTION_SEPARATOR;
}
$fullName .= $sectionFiltered;
}
return $fullName;
}
protected static function setUpConfig(ConfigBuilder $configBuilder): void { }
/**
* @param bool $throwOnException {@see Parametizer::newConfig()}
*/
public static function getConfigBuilder(
?EnvironmentConfig $envConfig = null,
bool $throwOnException = false,
): ConfigBuilder {
/*
* Here we want to detect environment config files starting from the launched script class location.
*
* debug_backtrace() does not contain script classes mentioning until this method is redefined explicitly.
* That's why we here explicitly specify the bottommost directory path.
*/
if (null === $envConfig && is_subclass_of(static::class, ScriptClassAbstract::class)) {
$staticClassReflection = new ReflectionClass(static::class);
$staticClassFilePath = $staticClassReflection->getFileName();
if (false !== $staticClassFilePath && !$staticClassReflection->isAbstract()) {
$envConfig = EnvironmentConfig::createFromConfigsBottomUpHierarchy(
bottommostDirectoryPath: dirname($staticClassFilePath),
throwOnException: $throwOnException,
);
}
}
$configBuilder = Parametizer::newConfig($envConfig, $throwOnException);
static::setUpConfig($configBuilder);
return $configBuilder;
}
public function __construct(protected readonly CliRequest $request) { }
abstract public function execute(): void;
}