From a323686a28981883bee4bb0a6d422f83f6dfeeee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Axel=20B=C3=B6swetter?= Date: Wed, 19 Jun 2024 15:08:07 +0200 Subject: [PATCH 1/3] [!!!][TASK] switch to minimum php version >= 8.0 and remove older version constraints for required symfony packages [TASK] allow required symfony/* packages >=7.0 as well [TASK] enhance static code analysis and code-style checks [CLEANUP] updates several php files to pass phpstan tests --- .github/workflows/ci.yml | 2 +- .gitignore | 1 + build/php-cs-fixer.php | 5 +++ build/phpstan.neon | 12 ++++-- composer.json | 30 +++++++++----- features/bootstrap/FeatureContext.php | 2 - .../IO/InputOutputInteractionSpec.php | 2 +- src/Companienv/Application.php | 29 ++++++++----- src/Companienv/Companion.php | 41 +++++++++++-------- .../Composer/InteractionViaComposer.php | 8 ++-- src/Companienv/Composer/ScriptHandler.php | 4 +- src/Companienv/DotEnv/Attribute.php | 22 ++++++++-- src/Companienv/DotEnv/Block.php | 34 ++++++++------- src/Companienv/DotEnv/File.php | 14 +++++-- src/Companienv/DotEnv/MissingVariable.php | 4 +- src/Companienv/DotEnv/Parser.php | 29 +++++++------ src/Companienv/DotEnv/Variable.php | 8 ++-- src/Companienv/Extension.php | 8 ++-- .../Extension/AbstractExtension.php | 3 +- src/Companienv/Extension/Chained.php | 2 +- src/Companienv/Extension/FileToPropagate.php | 10 ++--- src/Companienv/Extension/OnlyIf.php | 4 +- src/Companienv/Extension/RsaKeys.php | 17 ++++---- src/Companienv/Extension/SslCertificate.php | 25 ++++++----- src/Companienv/IO/FileSystem/FileSystem.php | 13 ++++-- .../IO/FileSystem/NativePhpFileSystem.php | 26 ++++++------ src/Companienv/IO/InputOutputInteraction.php | 16 ++++---- src/Companienv/IO/Interaction.php | 9 ++-- .../Interaction/AskVariableValues.php | 9 ++-- tests/Companienv/IO/InMemoryInteraction.php | 19 +++++---- 30 files changed, 245 insertions(+), 163 deletions(-) create mode 100644 build/php-cs-fixer.php diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index a9122a0..5cc6057 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -28,4 +28,4 @@ jobs: strategy: fail-fast: false matrix: - php: [ '7.2', '7.3', '7.4', '8.0', '8.1', '8.2' ] + php: [ '8.0', '8.1', '8.2' ] diff --git a/.gitignore b/.gitignore index 61b5720..befb19e 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ /.build /.idea /.env* +/.php-cs-fixer.cache /composer.lock diff --git a/build/php-cs-fixer.php b/build/php-cs-fixer.php new file mode 100644 index 0000000..5731802 --- /dev/null +++ b/build/php-cs-fixer.php @@ -0,0 +1,5 @@ +getFinder()->exclude(['node_modules', 'var'])->in(__DIR__ . '/..'); +return $config; diff --git a/build/phpstan.neon b/build/phpstan.neon index b6f8c50..5ab8bbb 100644 --- a/build/phpstan.neon +++ b/build/phpstan.neon @@ -1,11 +1,15 @@ +includes: + - %currentWorkingDirectory%/.build/vendor/phpstan/phpstan-strict-rules/rules.neon + - %currentWorkingDirectory%/.build/vendor/phpstan/phpstan-deprecation-rules/rules.neon + parameters: - level: 5 + level: 8 paths: - %currentWorkingDirectory%/spec - %currentWorkingDirectory%/src - %currentWorkingDirectory%/tests -# ignoreErrors: -# - '#Call to method .* on an unknown class .*PxRegisterUser.*#' -# - '#(Parameter|Property) .* has (invalid type|unknown class) .*PxRegisterUser(Repository)?.*#' + ignoreErrors: + - '#Class .* extends generic class PhpSpec\\ObjectBehavior but does not specify its types: TKey, TValue#' + - '#Property class@anonymous.*callable has no type specified.*#' diff --git a/composer.json b/composer.json index d8c497b..4b196ad 100644 --- a/composer.json +++ b/composer.json @@ -19,18 +19,22 @@ } ], "require": { - "php": ">=7.2", + "php": ">=8.0", "jackiedo/dotenv-editor": "^2.0", - "symfony/console": "^3.4 || ^4.0 || ^5.0 || ^6.0", - "symfony/dotenv": "^3.4 || ^4.0 || ^5.0 || ^6.0", - "symfony/process": "^3.4 || ^4.0 || ^5.0 || ^6.0" + "symfony/console": "^6.0 || ^7.0", + "symfony/dotenv": "^6.0 || ^7.0", + "symfony/process": "^6.0 || ^7.0" }, "require-dev": { - "behat/behat": "^3.4", - "composer/composer": "^1.0 || ^2.0", - "ergebnis/composer-normalize": "^2.19", - "phpspec/phpspec": "^4.3 || ^5.0 || ^6.0 || ^7.0", - "phpstan/phpstan": "^1.10" + "behat/behat": "^3.14", + "composer/composer": "^2.0", + "ergebnis/composer-normalize": "^2.43", + "friendsofphp/php-cs-fixer": "^3.47", + "phpspec/phpspec": "^7.0", + "phpstan/phpstan": "^1.10", + "phpstan/phpstan-deprecation-rules": "^1.1", + "phpstan/phpstan-strict-rules": "^1.5", + "typo3/coding-standards": "^0.8" }, "replace": { "sroze/companienv": "*" @@ -74,13 +78,19 @@ "ci:php:stan": "./.build/bin/phpstan analyse -c ./build/phpstan.neon --no-progress", "ci:static": [ "@ci:composer:normalize", + "@ci:php:cs-fixer", "@ci:php:lint", "@ci:php:stan" ], "ci:test": [ "@ci:test:behat" ], - "ci:test:behat": "./.build/bin/behat --strict --stop-on-failure" + "ci:test:behat": "./.build/bin/behat --strict --stop-on-failure", + "fix:php": [ + "@fix:php:cs", + "@fix:php:sniff" + ], + "fix:php:cs": "./.build/bin/php-cs-fixer fix --config ./build/php-cs-fixer.php" }, "scripts-descriptions": { "ci": "Runs all dynamic and static code checks.", diff --git a/features/bootstrap/FeatureContext.php b/features/bootstrap/FeatureContext.php index f56dca7..4480e1b 100644 --- a/features/bootstrap/FeatureContext.php +++ b/features/bootstrap/FeatureContext.php @@ -1,7 +1,6 @@ beConstructedWith($input, $output); } diff --git a/src/Companienv/Application.php b/src/Companienv/Application.php index d042a0c..3bed8dc 100644 --- a/src/Companienv/Application.php +++ b/src/Companienv/Application.php @@ -7,30 +7,34 @@ use Companienv\Extension\OnlyIf; use Companienv\Extension\RsaKeys; use Companienv\Extension\SslCertificate; -use Companienv\IO\FileSystem\NativePhpFileSystem; use Companienv\Interaction\AskVariableValues; +use Companienv\IO\FileSystem\NativePhpFileSystem; use Companienv\IO\InputOutputInteraction; +use Symfony\Component\Console\Application as ConsoleApplication; use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Input\InputOption; -use Symfony\Component\Console\Application as ConsoleApplication; use Symfony\Component\Console\Output\OutputInterface; class Application extends ConsoleApplication { - private $rootDirectory; + private string $rootDirectory; /** @var Extension[] */ - private $extensions = []; + private array $extensions; + /** + * @param string $rootDirectory + * @param Extension[]|null $extensions + */ public function __construct(string $rootDirectory, array $extensions = null) { parent::__construct('Companienv', '0.0.x-dev'); $this->rootDirectory = $rootDirectory; - $this->extensions = $extensions !== null ? $extensions : self::defaultExtensions(); + $this->extensions = $extensions ?? self::defaultExtensions(); - $this->add(new class([$this, 'companion'], 'companion') extends Command { + $this->add(new class ([$this, 'companion'], 'companion') extends Command { private $callable; public function __construct(callable $callable, $name) @@ -54,7 +58,7 @@ protected function execute(InputInterface $input, OutputInterface $output) $this->setDefaultCommand('companion', true); } - public function companion(InputInterface $input, OutputInterface $output) + public function companion(InputInterface $input, OutputInterface $output): int { $companion = new Companion( new NativePhpFileSystem($this->rootDirectory), @@ -67,12 +71,15 @@ public function companion(InputInterface $input, OutputInterface $output) return 0; } - public function registerExtension(Extension $extension) + public function registerExtension(Extension $extension): void { array_unshift($this->extensions, $extension); } - public static function defaultExtensions() + /** + * @return Extension[] + */ + public static function defaultExtensions(): array { return [ new OnlyIf(), @@ -83,12 +90,12 @@ public static function defaultExtensions() ]; } - public static function defaultFile() + public static function defaultFile(): string { return '.env'; } - public static function defaultDistributionFile() + public static function defaultDistributionFile(): string { return '.env.dist'; } diff --git a/src/Companienv/Companion.php b/src/Companienv/Companion.php index 8f1a5a9..4518145 100644 --- a/src/Companienv/Companion.php +++ b/src/Companienv/Companion.php @@ -3,6 +3,7 @@ namespace Companienv; use Companienv\DotEnv\Block; +use Companienv\DotEnv\File; use Companienv\DotEnv\MissingVariable; use Companienv\DotEnv\Parser; use Companienv\IO\FileSystem\FileSystem; @@ -14,11 +15,11 @@ class Companion { - private $fileSystem; - private $interaction; - private $reference; - private $extension; - private $envFileName; + private FileSystem $fileSystem; + private Interaction $interaction; + private File $reference; + private Extension $extension; + private string $envFileName; public function __construct(FileSystem $fileSystem, Interaction $interaction, Extension $extension, string $envFileName = '.env', string $distFileName = '.env.dist') { @@ -29,7 +30,7 @@ public function __construct(FileSystem $fileSystem, Interaction $interaction, Ex $this->envFileName = $envFileName; } - public function fillGaps() + public function fillGaps(): void { $missingVariables = $this->getVariablesRequiringValues(); if (count($missingVariables) === 0) { @@ -45,7 +46,7 @@ public function fillGaps() $this->interaction->writeln([ '', 'I let you think about it then. Re-run the command to get started again.', - '' + '', ]); return; @@ -56,22 +57,25 @@ public function fillGaps() } } - private function fillBlockGaps(Block $block, array $missingVariables) + /** + * @param MissingVariable[] $missingVariables + */ + private function fillBlockGaps(Block $block, array $missingVariables): void { $variablesInBlock = $block->getVariablesInBlock($missingVariables); - if (count($variablesInBlock) == 0) { + if (count($variablesInBlock) === 0) { return; } - if (!empty($title = $block->getTitle())) { + if ($block->getTitle() !== '') { $this->interaction->writeln([ '', '' . $block->getTitle() . '', ]); } - if (!empty($description = $block->getDescription())) { - $this->interaction->writeln($description); + if ($block->getDescription() !== '') { + $this->interaction->writeln($block->getDescription()); } $this->interaction->writeln(''); @@ -83,7 +87,7 @@ private function fillBlockGaps(Block $block, array $missingVariables) } } - private function writeVariable(string $name, string $value) + private function writeVariable(string $name, ?string $value = null): void { if (!$this->fileSystem->exists($this->envFileName)) { $this->fileSystem->write($this->envFileName, ''); @@ -126,7 +130,7 @@ private function writeVariable(string $name, string $value) /** * @return MissingVariable[] */ - private function getVariablesRequiringValues() + private function getVariablesRequiringValues(): array { $variablesInFile = $this->getDefinedVariablesHash(); $missingVariables = []; @@ -144,7 +148,10 @@ private function getVariablesRequiringValues() return $missingVariables; } - public function getDefinedVariablesHash() + /** + * @return array + */ + public function getDefinedVariablesHash(): array { $variablesInFile = []; if ($this->fileSystem->exists($this->envFileName)) { @@ -155,12 +162,12 @@ public function getDefinedVariablesHash() return $variablesInFile; } - public function askConfirmation(string $question) : bool + public function askConfirmation(string $question): bool { return $this->interaction->askConfirmation($question); } - public function ask(string $question, string $default = null) : string + public function ask(string $question, string $default = ''): string { return $this->interaction->ask($question, $default); } diff --git a/src/Companienv/Composer/InteractionViaComposer.php b/src/Companienv/Composer/InteractionViaComposer.php index cb5691c..9aade47 100644 --- a/src/Companienv/Composer/InteractionViaComposer.php +++ b/src/Companienv/Composer/InteractionViaComposer.php @@ -7,7 +7,7 @@ class InteractionViaComposer implements Interaction { - private $io; + private IOInterface $io; public function __construct(IOInterface $io) { @@ -25,7 +25,7 @@ public function askConfirmation(string $question): bool return $this->io->askConfirmation($question); } - public function ask(string $question, string $default = null): string + public function ask(string $question, string $default = ''): string { if (!$this->io->isInteractive()) { $this->writeln(sprintf('Automatically returned "%s" in non-interactive mode', $default)); @@ -36,8 +36,8 @@ public function ask(string $question, string $default = null): string return $this->io->ask($question, $default); } - public function writeln($messageOrMessages) + public function writeln(array|string $messageOrMessages): void { - return $this->io->write($messageOrMessages); + $this->io->write($messageOrMessages); } } diff --git a/src/Companienv/Composer/ScriptHandler.php b/src/Companienv/Composer/ScriptHandler.php index 539100e..b79ea45 100644 --- a/src/Companienv/Composer/ScriptHandler.php +++ b/src/Companienv/Composer/ScriptHandler.php @@ -10,7 +10,7 @@ class ScriptHandler { - public static function run(Event $event) + public static function run(Event $event): void { $extras = $event->getComposer()->getPackage()->getExtra(); @@ -20,7 +20,7 @@ public static function run(Event $event) $configs = [['file' => Application::defaultFile(), 'dist-file' => Application::defaultDistributionFile()]]; } - $directory = getcwd(); + $directory = (string)getcwd(); foreach ($configs as $config) { $companion = new Companion( new NativePhpFileSystem($directory), diff --git a/src/Companienv/DotEnv/Attribute.php b/src/Companienv/DotEnv/Attribute.php index f0a13dc..73e0ef4 100644 --- a/src/Companienv/DotEnv/Attribute.php +++ b/src/Companienv/DotEnv/Attribute.php @@ -4,9 +4,17 @@ class Attribute { - private $name; - private $variableNames; - private $labels; + private string $name; + + /** + * @var string[] + */ + private array $variableNames; + + /** + * @var string[] + */ + private array $labels; /** * @param string $name @@ -25,12 +33,18 @@ public function getName(): string return $this->name; } + /** + * @return string[] + */ public function getVariableNames(): array { return $this->variableNames; } - public function getLabels() + /** + * @return string[] + */ + public function getLabels(): array { return $this->labels; } diff --git a/src/Companienv/DotEnv/Block.php b/src/Companienv/DotEnv/Block.php index 421b9ce..8c0fa5d 100644 --- a/src/Companienv/DotEnv/Block.php +++ b/src/Companienv/DotEnv/Block.php @@ -4,15 +4,21 @@ class Block { - private $title; - private $description; + private string $title; + private string $description; /** @var Variable[] */ - private $variables; + private array $variables; /** @var Attribute[] */ - private $attributes; + private array $attributes; + /** + * @param string $title + * @param string $description + * @param Variable[] $variables + * @param Attribute[] $attributes + */ public function __construct(string $title = '', string $description = '', array $variables = [], array $attributes = []) { $this->title = $title; @@ -21,17 +27,17 @@ public function __construct(string $title = '', string $description = '', array $this->attributes = $attributes; } - public function appendToDescription(string $string) + public function appendToDescription(string $string): void { - $this->description .= ($this->description ? ' ' : '') . $string; + $this->description .= ($this->description !== '' ? ' ' : '') . $string; } - public function addVariable(Variable $variable) + public function addVariable(Variable $variable): void { $this->variables[] = $variable; } - public function addAttribute(Attribute $attribute) + public function addAttribute(Attribute $attribute): void { $this->attributes[] = $attribute; } @@ -69,14 +75,14 @@ public function getVariables(): array * * @return Variable[] */ - public function getVariablesInBlock(array $variables) + public function getVariablesInBlock(array $variables): array { $blockVariableNames = array_map(function (Variable $variable) { return $variable->getName(); }, $this->variables); return array_filter($variables, function (Variable $variable) use ($blockVariableNames) { - return in_array($variable->getName(), $blockVariableNames); + return in_array($variable->getName(), $blockVariableNames, true); }); } @@ -85,10 +91,10 @@ public function getVariablesInBlock(array $variables) * * @return Variable|null */ - public function getVariable(string $name) + public function getVariable(string $name): ?Variable { foreach ($this->variables as $variable) { - if ($variable->getName() == $name) { + if ($variable->getName() === $name) { return $variable; } } @@ -102,14 +108,14 @@ public function getVariable(string $name) * * @return Attribute|null */ - public function getAttribute(string $name, Variable $forVariable = null) + public function getAttribute(string $name, Variable $forVariable = null): ?Attribute { foreach ($this->attributes as $attribute) { if ( $attribute->getName() == $name && ( $forVariable === null - || in_array($forVariable->getName(), $attribute->getVariableNames()) + || in_array($forVariable->getName(), $attribute->getVariableNames(), true) ) ) { return $attribute; diff --git a/src/Companienv/DotEnv/File.php b/src/Companienv/DotEnv/File.php index 211ee1b..b7e656f 100644 --- a/src/Companienv/DotEnv/File.php +++ b/src/Companienv/DotEnv/File.php @@ -4,9 +4,17 @@ class File { - private $header; - private $blocks; + private string $header; + /** + * @var Block[] + */ + private array $blocks; + + /** + * @param string $header + * @param Block[] $blocks + */ public function __construct(string $header = '', array $blocks = []) { $this->header = $header; @@ -32,7 +40,7 @@ public function getBlocks(): array /** * @return Variable[] */ - public function getAllVariables() : array + public function getAllVariables(): array { return array_reduce($this->blocks, function (array $carry, Block $block) { return array_merge($carry, $block->getVariables()); diff --git a/src/Companienv/DotEnv/MissingVariable.php b/src/Companienv/DotEnv/MissingVariable.php index 0ca1c3f..4f0228c 100644 --- a/src/Companienv/DotEnv/MissingVariable.php +++ b/src/Companienv/DotEnv/MissingVariable.php @@ -4,7 +4,7 @@ class MissingVariable extends Variable { - private $currentValue; + private ?string $currentValue; public function __construct(Variable $variable, string $currentValue = null) { @@ -16,7 +16,7 @@ public function __construct(Variable $variable, string $currentValue = null) /** * @return string|null */ - public function getCurrentValue() + public function getCurrentValue(): ?string { return $this->currentValue; } diff --git a/src/Companienv/DotEnv/Parser.php b/src/Companienv/DotEnv/Parser.php index 147c00d..0d34a8e 100644 --- a/src/Companienv/DotEnv/Parser.php +++ b/src/Companienv/DotEnv/Parser.php @@ -6,7 +6,7 @@ class Parser { - public function parse(FileSystem $fileSystem, string $path) : File + public function parse(FileSystem $fileSystem, string $path): File { $blocks = []; @@ -14,26 +14,26 @@ public function parse(FileSystem $fileSystem, string $path) : File $block = null; foreach (explode("\n", $fileSystem->getContents($path)) as $number => $line) { $line = trim($line); - if (empty($line)) { + if ($line === '') { continue; } - if (strpos($line, '#') === 0) { + if (str_starts_with($line, '#')) { // We see a title - if (substr($line, 0, 2) == '##') { + if (substr($line, 0, 2) === '##') { $block = new Block(trim($line, '# ')); $blocks[] = $block; - } elseif (substr($line, 0, 2) == '#~') { + } elseif (substr($line, 0, 2) === '#~') { // Ignore this comment. } elseif ($block !== null) { - if (substr($line, 0, 2) == '#+') { + if (substr($line, 0, 2) === '#+') { $block->addAttribute($this->parseAttribute(substr($line, 2))); - } else if (substr($line, 1, 1) == ' ') { + } elseif (substr($line, 1, 1) === ' ') { $block->appendToDescription(trim($line, '# ')); } } } elseif (false !== ($firstEquals = strpos($line, '='))) { - if (null === $block) { + if ($block === null) { $blocks[] = $block = new Block(); } @@ -54,12 +54,12 @@ public function parse(FileSystem $fileSystem, string $path) : File return new File('', $blocks); } - private function parseAttribute(string $string) + private function parseAttribute(string $string): Attribute { $variableNameRegex = '[A-Z0-9_]+'; $valueRegex = '[^\) ]+'; - if (!preg_match('/^([a-z0-9-]+)\((('.$variableNameRegex.' ?)*)\)(:\((('.$variableNameRegex.'='.$valueRegex.' ?)*)\))?$/', $string, $matches)) { + if (preg_match('/^([a-z0-9-]+)\(((' . $variableNameRegex . ' ?)*)\)(:\(((' . $variableNameRegex . '=' . $valueRegex . ' ?)*)\))?$/', $string, $matches) === false) { throw new \RuntimeException(sprintf( 'Unable to parse the given attribute: %s', $string @@ -69,20 +69,23 @@ private function parseAttribute(string $string) return new Attribute($matches[1], explode(' ', $matches[2]), isset($matches[6]) ? $this->dotEnvMappingToKeyBasedMapping($matches[6]) : []); } - private function dotEnvMappingToKeyBasedMapping(string $dotEnvMapping) + /** + * @return array + */ + private function dotEnvMappingToKeyBasedMapping(string $dotEnvMapping): array { $mapping = []; $envMappings = explode(' ', $dotEnvMapping); foreach ($envMappings as $envMapping) { - if (false === strpos($envMapping, '=')) { + if (!str_contains($envMapping, '=')) { throw new \RuntimeException(sprintf( 'Could not parse attribute mapping "%s"', $dotEnvMapping )); } - list($key, $value) = explode('=', $envMapping); + [$key, $value] = explode('=', $envMapping); $mapping[$key] = $value; } diff --git a/src/Companienv/DotEnv/Variable.php b/src/Companienv/DotEnv/Variable.php index 2073462..1834e35 100644 --- a/src/Companienv/DotEnv/Variable.php +++ b/src/Companienv/DotEnv/Variable.php @@ -4,8 +4,8 @@ class Variable { - private $name; - private $value; + private string $name; + private ?string $value; public function __construct(string $name, string $value = null) { @@ -20,10 +20,10 @@ public function getName(): string public function hasValue(): bool { - return !empty($this->value); + return $this->value !== null; } - public function getValue() + public function getValue(): ?string { return $this->value; } diff --git a/src/Companienv/Extension.php b/src/Companienv/Extension.php index 4739e5f..a64966b 100644 --- a/src/Companienv/Extension.php +++ b/src/Companienv/Extension.php @@ -7,9 +7,9 @@ interface Extension { - const VARIABLE_REQUIRED = 1; - const VARIABLE_SKIP = -1; - const ABSTAIN = 0; + public const VARIABLE_REQUIRED = 1; + public const VARIABLE_SKIP = -1; + public const ABSTAIN = 0; /** * Get the variable value, from a given source. @@ -36,5 +36,5 @@ public function getVariableValue(Companion $companion, Block $block, Variable $v * * @return int */ - public function isVariableRequiringValue(Companion $companion, Block $block, Variable $variable, string $currentValue = null) : int; + public function isVariableRequiringValue(Companion $companion, Block $block, Variable $variable, string $currentValue = null): int; } diff --git a/src/Companienv/Extension/AbstractExtension.php b/src/Companienv/Extension/AbstractExtension.php index 01ba680..19a76f6 100644 --- a/src/Companienv/Extension/AbstractExtension.php +++ b/src/Companienv/Extension/AbstractExtension.php @@ -9,7 +9,6 @@ /** * An abstract class that contains default non-intrusive implementations of the extension methods. - * */ class AbstractExtension implements Extension { @@ -24,7 +23,7 @@ public function getVariableValue(Companion $companion, Block $block, Variable $v /** * {@inheritdoc} */ - public function isVariableRequiringValue(Companion $companion, Block $block, Variable $variable, string $currentValue = null) : int + public function isVariableRequiringValue(Companion $companion, Block $block, Variable $variable, string $currentValue = null): int { return Extension::ABSTAIN; } diff --git a/src/Companienv/Extension/Chained.php b/src/Companienv/Extension/Chained.php index fb67a40..85f7f98 100644 --- a/src/Companienv/Extension/Chained.php +++ b/src/Companienv/Extension/Chained.php @@ -39,7 +39,7 @@ public function getVariableValue(Companion $companion, Block $block, Variable $v /** * {@inheritdoc} */ - public function isVariableRequiringValue(Companion $companion, Block $block, Variable $variable, string $currentValue = null) : int + public function isVariableRequiringValue(Companion $companion, Block $block, Variable $variable, string $currentValue = null): int { foreach ($this->extensions as $extension) { if (($vote = $extension->isVariableRequiringValue($companion, $block, $variable, $currentValue)) != Extension::ABSTAIN) { diff --git a/src/Companienv/Extension/FileToPropagate.php b/src/Companienv/Extension/FileToPropagate.php index c2752f0..a6e89ae 100644 --- a/src/Companienv/Extension/FileToPropagate.php +++ b/src/Companienv/Extension/FileToPropagate.php @@ -22,16 +22,16 @@ public function getVariableValue(Companion $companion, Block $block, Variable $v $fileSystem = $companion->getFileSystem(); // If the file exists and seems legit, keep the file. - if ($fileSystem->exists($filename = $variable->getValue()) && isset($definedVariablesHash[$variable->getName()])) { + if ($fileSystem->exists((string)$filename = $variable->getValue()) && isset($definedVariablesHash[$variable->getName()])) { return $definedVariablesHash[$variable->getName()]; } - $downloadedFilePath = $companion->ask(''.$variable->getName().': What is the path of your downloaded file? '); + $downloadedFilePath = $companion->ask('' . $variable->getName() . ': What is the path of your downloaded file? '); if (!$fileSystem->exists($downloadedFilePath)) { throw new \InvalidArgumentException(sprintf('The file "%s" does not exist', $downloadedFilePath)); } - if (false === $fileSystem->write($filename, $fileSystem->getContents($downloadedFilePath))) { + if ($fileSystem->write((string)$filename, $fileSystem->getContents($downloadedFilePath)) === false) { throw new \RuntimeException(sprintf( 'Unable to write into "%s"', $filename @@ -44,13 +44,13 @@ public function getVariableValue(Companion $companion, Block $block, Variable $v /** * {@inheritdoc} */ - public function isVariableRequiringValue(Companion $companion, Block $block, Variable $variable, string $currentValue = null) : int + public function isVariableRequiringValue(Companion $companion, Block $block, Variable $variable, string $currentValue = null): int { if (null === ($attribute = $block->getAttribute('file-to-propagate', $variable))) { return Extension::ABSTAIN; } - return $companion->getFileSystem()->exists($variable->getValue()) + return $companion->getFileSystem()->exists((string)$variable->getValue()) ? Extension::VARIABLE_REQUIRED : Extension::ABSTAIN; } diff --git a/src/Companienv/Extension/OnlyIf.php b/src/Companienv/Extension/OnlyIf.php index ba71adb..33c8119 100644 --- a/src/Companienv/Extension/OnlyIf.php +++ b/src/Companienv/Extension/OnlyIf.php @@ -29,7 +29,7 @@ public function getVariableValue(Companion $companion, Block $block, Variable $v /** * {@inheritdoc} */ - public function isVariableRequiringValue(Companion $companion, Block $block, Variable $variable, string $currentValue = null) : int + public function isVariableRequiringValue(Companion $companion, Block $block, Variable $variable, string $currentValue = null): int { if (null === ($attribute = $block->getAttribute('only-if', $variable))) { return Extension::ABSTAIN; @@ -40,7 +40,7 @@ public function isVariableRequiringValue(Companion $companion, Block $block, Var : Extension::VARIABLE_SKIP; } - private function matchesCondition(Companion $companion, Attribute $attribute) : bool + private function matchesCondition(Companion $companion, Attribute $attribute): bool { $definedVariablesHash = $companion->getDefinedVariablesHash(); foreach ($attribute->getLabels() as $otherVariableName => $expectedValue) { diff --git a/src/Companienv/Extension/RsaKeys.php b/src/Companienv/Extension/RsaKeys.php index 47addb1..20481c4 100644 --- a/src/Companienv/Extension/RsaKeys.php +++ b/src/Companienv/Extension/RsaKeys.php @@ -10,7 +10,10 @@ class RsaKeys implements Extension { - private $populatedVariables = []; + /** + * @var array + */ + private array $populatedVariables = []; /** * {@inheritdoc} @@ -28,7 +31,7 @@ public function getVariableValue(Companion $companion, Block $block, Variable $v if (!$companion->askConfirmation(sprintf( 'Variables %s represents an RSA public/private key. Do you want to automatically generate them? (y) ', implode(' and ', array_map(function ($variable) { - return ''.$variable.''; + return '' . $variable . ''; }, $attribute->getVariableNames())) ))) { // Ensure we don't ask anymore for this variable pair @@ -41,8 +44,8 @@ public function getVariableValue(Companion $companion, Block $block, Variable $v $fileSystem = $companion->getFileSystem(); $passPhrase = $companion->ask('Enter pass phrase to protect the keys: '); - $privateKeyPath = $block->getVariable($privateKeyVariableName = $attribute->getVariableNames()[0])->getValue(); - $publicKeyPath = $block->getVariable($publicKeyVariableName = $attribute->getVariableNames()[1])->getValue(); + $privateKeyPath = (string)$block->getVariable($privateKeyVariableName = $attribute->getVariableNames()[0])?->getValue(); + $publicKeyPath = (string)$block->getVariable($publicKeyVariableName = $attribute->getVariableNames()[1])?->getValue(); try { (new Process(['openssl', 'genrsa', '-out', $fileSystem->realpath($privateKeyPath), '-aes256', '-passout', 'pass:' . $passPhrase, '4096']))->mustRun(); @@ -61,7 +64,7 @@ public function getVariableValue(Companion $companion, Block $block, Variable $v /** * {@inheritdoc} */ - public function isVariableRequiringValue(Companion $companion, Block $block, Variable $variable, string $currentValue = null) : int + public function isVariableRequiringValue(Companion $companion, Block $block, Variable $variable, string $currentValue = null): int { if (null === ($attribute = $block->getAttribute('rsa-pair', $variable))) { return Extension::ABSTAIN; @@ -70,8 +73,8 @@ public function isVariableRequiringValue(Companion $companion, Block $block, Var $fileSystem = $companion->getFileSystem(); return ( - !$fileSystem->exists($block->getVariable($attribute->getVariableNames()[0])->getValue()) - || !$fileSystem->exists($block->getVariable($attribute->getVariableNames()[1])->getValue()) + !$fileSystem->exists((string)$block->getVariable($attribute->getVariableNames()[0])?->getValue()) + || !$fileSystem->exists((string)$block->getVariable($attribute->getVariableNames()[1])?->getValue()) ) ? Extension::VARIABLE_REQUIRED : Extension::ABSTAIN; } diff --git a/src/Companienv/Extension/SslCertificate.php b/src/Companienv/Extension/SslCertificate.php index ac5d304..b37d2ed 100644 --- a/src/Companienv/Extension/SslCertificate.php +++ b/src/Companienv/Extension/SslCertificate.php @@ -10,7 +10,10 @@ class SslCertificate implements Extension { - private $populatedVariables = []; + /** + * @var array + */ + private array $populatedVariables = []; /** * {@inheritdoc} @@ -28,27 +31,27 @@ public function getVariableValue(Companion $companion, Block $block, Variable $v if (!$companion->askConfirmation(sprintf( 'Variables %s represents an SSL certificate. Do you want to automatically generate them? (y) ', implode(' and ', array_map(function ($variable) { - return ''.$variable.''; + return '' . $variable . ''; }, $attribute->getVariableNames())) ))) { // Ensure we don't ask anymore for this variable pair - foreach ($attribute->getVariableNames() as $variable) { - $this->populatedVariables[$variable] = null; + foreach ($attribute->getVariableNames() as $variableName) { + $this->populatedVariables[$variableName] = null; } return null; } $domainName = $companion->ask('Enter the domain name for which to generate the self-signed SSL certificate: '); - $privateKeyPath = $block->getVariable($privateKeyVariableName = $attribute->getVariableNames()[0])->getValue(); - $certificateKeyPath = $block->getVariable($certificateVariableName = $attribute->getVariableNames()[1])->getValue(); + $privateKeyPath = (string)$block->getVariable($privateKeyVariableName = $attribute->getVariableNames()[0])?->getValue(); + $certificateKeyPath = (string)$block->getVariable($certificateVariableName = $attribute->getVariableNames()[1])?->getValue(); try { (new Process([ - 'openssl', 'req', '-x509', '-nodes', '-days', '3650', '-newkey', 'rsa:2048', '-keyout', $companion->getFileSystem()->realpath($privateKeyPath), '-out', $companion->getFileSystem()->realpath($certificateKeyPath), '-subj', '"/C=SS/ST=SS/L=SelfSignedCity/O=SelfSignedOrg/CN=' . $domainName . '"' + 'openssl', 'req', '-x509', '-nodes', '-days', '3650', '-newkey', 'rsa:2048', '-keyout', $companion->getFileSystem()->realpath($privateKeyPath), '-out', $companion->getFileSystem()->realpath($certificateKeyPath), '-subj', '"/C=SS/ST=SS/L=SelfSignedCity/O=SelfSignedOrg/CN=' . $domainName . '"', ]))->mustRun(); } catch (\Symfony\Component\Process\Exception\RuntimeException $e) { - throw new \RuntimeException('Could not have generated the SSL certificate: '.$e->getMessage(), $e->getCode(), $e); + throw new \RuntimeException('Could not have generated the SSL certificate: ' . $e->getMessage(), $e->getCode(), $e); } $this->populatedVariables[$privateKeyVariableName] = $privateKeyPath; @@ -61,7 +64,7 @@ public function getVariableValue(Companion $companion, Block $block, Variable $v /** * {@inheritdoc} */ - public function isVariableRequiringValue(Companion $companion, Block $block, Variable $variable, string $currentValue = null) : int + public function isVariableRequiringValue(Companion $companion, Block $block, Variable $variable, string $currentValue = null): int { if (null === ($attribute = $block->getAttribute('ssl-certificate', $variable))) { return Extension::ABSTAIN; @@ -70,8 +73,8 @@ public function isVariableRequiringValue(Companion $companion, Block $block, Var $fileSystem = $companion->getFileSystem(); return ( - !$fileSystem->exists($block->getVariable($privateKeyVariableName = $attribute->getVariableNames()[0])->getValue()) - || !$fileSystem->exists($block->getVariable($attribute->getVariableNames()[1])->getValue()) + !$fileSystem->exists((string)$block->getVariable($privateKeyVariableName = $attribute->getVariableNames()[0])?->getValue()) + || !$fileSystem->exists((string)$block->getVariable($attribute->getVariableNames()[1])?->getValue()) ) ? Extension::VARIABLE_REQUIRED : Extension::ABSTAIN; } diff --git a/src/Companienv/IO/FileSystem/FileSystem.php b/src/Companienv/IO/FileSystem/FileSystem.php index 4ea758b..471890e 100644 --- a/src/Companienv/IO/FileSystem/FileSystem.php +++ b/src/Companienv/IO/FileSystem/FileSystem.php @@ -4,11 +4,16 @@ interface FileSystem { - public function write($path, string $contents); + /** + * @param string $path + * @param string|string[] $contents + * @return bool + */ + public function write(string $path, string|array $contents): bool; - public function exists($path); + public function exists(string $path): bool; - public function getContents($path); + public function getContents(string $path): string; - public function realpath($path); + public function realpath(string $path): string; } diff --git a/src/Companienv/IO/FileSystem/NativePhpFileSystem.php b/src/Companienv/IO/FileSystem/NativePhpFileSystem.php index da1a601..f64aacd 100644 --- a/src/Companienv/IO/FileSystem/NativePhpFileSystem.php +++ b/src/Companienv/IO/FileSystem/NativePhpFileSystem.php @@ -4,42 +4,44 @@ class NativePhpFileSystem implements FileSystem { - - private $root; + private string $root; public function __construct(string $root) { $this->root = $root; } - public function write($path, string $contents) + /** + * @param string $path + * @param string|string[] $contents + * @return bool + */ + public function write(string $path, string|array $contents): bool { - $relative = $this->isRelativePath($path); - file_put_contents($this->isRelativePath($path) ? $this->realpath($path) : $path, $contents); + return (bool)file_put_contents($this->isRelativePath($path) ? $this->realpath($path) : $path, $contents); } - public function exists($path) + public function exists(string $path): bool { - $relative = $this->isRelativePath($path); return file_exists($this->isRelativePath($path) ? $this->realpath($path) : $path); } - public function getContents($path) + public function getContents(string $path): string { - return file_get_contents($this->isRelativePath($path) ? $this->realpath($path) : $path); + return (string)file_get_contents($this->isRelativePath($path) ? $this->realpath($path) : $path); } - public function delete($path) + public function delete(string $path): bool { return unlink($this->isRelativePath($path) ? $this->realpath($path) : $path); } - public function realpath($path) + public function realpath(string $path): string { return $this->root . DIRECTORY_SEPARATOR . $path; } - protected function isRelativePath($path) + protected function isRelativePath(string $path): bool { return substr($path, 0, 1) !== '/'; } diff --git a/src/Companienv/IO/InputOutputInteraction.php b/src/Companienv/IO/InputOutputInteraction.php index 16f34a3..d2d52a6 100644 --- a/src/Companienv/IO/InputOutputInteraction.php +++ b/src/Companienv/IO/InputOutputInteraction.php @@ -9,8 +9,8 @@ class InputOutputInteraction implements Interaction { - private $input; - private $output; + private InputInterface $input; + private OutputInterface $output; public function __construct(InputInterface $input, OutputInterface $output) { @@ -18,24 +18,24 @@ public function __construct(InputInterface $input, OutputInterface $output) $this->output = $output; } - public function askConfirmation(string $question) : bool + public function askConfirmation(string $question): bool { - return in_array(strtolower($this->ask($question, 'y')), ['y', 'yes']); + return in_array(strtolower($this->ask($question, 'y')), ['y', 'yes'], true); } - public function ask(string $question, string $default = null) : string + public function ask(string $question, string $default = ''): string { $answer = (new QuestionHelper())->ask($this->input, $this->output, new Question($question, $default)); - if (null === $answer || ('' === $answer && $default !== null)) { + if ($answer === null || ($answer === '' && $default !== '')) { return $this->ask($question, $default); } return $answer; } - public function writeln($messageOrMessages) + public function writeln(array|string $messageOrMessages): void { - return $this->output->writeln($messageOrMessages); + $this->output->writeln($messageOrMessages); } } diff --git a/src/Companienv/IO/Interaction.php b/src/Companienv/IO/Interaction.php index 013ec3a..7bf2bec 100644 --- a/src/Companienv/IO/Interaction.php +++ b/src/Companienv/IO/Interaction.php @@ -4,9 +4,12 @@ interface Interaction { - public function askConfirmation(string $question) : bool; + public function askConfirmation(string $question): bool; - public function ask(string $question, string $default = null) : string; + public function ask(string $question, string $default = ''): string; - public function writeln($messageOrMessages); + /** + * @param string|string[] $messageOrMessages + */ + public function writeln(array|string $messageOrMessages): void; } diff --git a/src/Companienv/Interaction/AskVariableValues.php b/src/Companienv/Interaction/AskVariableValues.php index 91744f1..fce3508 100644 --- a/src/Companienv/Interaction/AskVariableValues.php +++ b/src/Companienv/Interaction/AskVariableValues.php @@ -12,14 +12,15 @@ class AskVariableValues implements Extension /** * {@inheritdoc} */ - public function getVariableValue(Companion $companion, Block $block, Variable $variable) + public function getVariableValue(Companion $companion, Block $block, Variable $variable): string { $definedVariablesHash = $companion->getDefinedVariablesHash(); - $defaultValue = ($definedVariablesHash[$variable->getName()] ?? $variable->getValue()) ?: $variable->getValue(); + $defaultValue = (string)($definedVariablesHash[$variable->getName()] ?? $variable->getValue()); + $defaultValue = (string)($defaultValue !== '' ? $defaultValue : $variable->getValue()); $question = sprintf('%s ? ', $variable->getName()); if ($defaultValue !== '') { - $question .= '('.$defaultValue.') '; + $question .= '(' . $defaultValue . ') '; } return $companion->ask($question, $defaultValue); @@ -28,7 +29,7 @@ public function getVariableValue(Companion $companion, Block $block, Variable $v /** * {@inheritdoc} */ - public function isVariableRequiringValue(Companion $companion, Block $block, Variable $variable, string $currentValue = null) : int + public function isVariableRequiringValue(Companion $companion, Block $block, Variable $variable, string $currentValue = null): int { return ( $currentValue === null || ( diff --git a/tests/Companienv/IO/InMemoryInteraction.php b/tests/Companienv/IO/InMemoryInteraction.php index 2e7d5ae..005cb44 100644 --- a/tests/Companienv/IO/InMemoryInteraction.php +++ b/tests/Companienv/IO/InMemoryInteraction.php @@ -7,12 +7,15 @@ class InMemoryInteraction implements Interaction /** * A question-answer mapping. * - * @var array + * @var array */ - private $answers; + private array $answers; - private $buffer = ''; + private string $buffer = ''; + /** + * @param array $answers + */ public function __construct(array $answers = []) { $this->answers = $answers; @@ -20,13 +23,13 @@ public function __construct(array $answers = []) public function askConfirmation(string $question): bool { - return (bool) $this->ask($question); + return (bool)$this->ask($question); } - public function ask(string $question, string $default = null): string + public function ask(string $question, string $default = ''): string { $normalizedKey = trim(strip_tags($question)); - $this->buffer .= trim(strip_tags($question))."\n"; + $this->buffer .= trim(strip_tags($question)) . "\n"; if (isset($this->answers[$normalizedKey])) { return $this->answers[$normalizedKey]; @@ -38,13 +41,13 @@ public function ask(string $question, string $default = null): string )); } - public function writeln($messageOrMessages) + public function writeln(array|string $messageOrMessages): void { if (!is_array($messageOrMessages)) { $messageOrMessages = [$messageOrMessages]; } - $this->buffer .= implode("\n", $messageOrMessages)."\n"; + $this->buffer .= implode("\n", $messageOrMessages) . "\n"; } public function getBuffer(): string From 2847f1cb03fa59c62e7a60d0b3a68ee44e3adaf2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Axel=20B=C3=B6swetter?= Date: Wed, 19 Jun 2024 15:19:58 +0200 Subject: [PATCH 2/3] [TASK] adds php v8.3 to github workflow matrix --- .github/workflows/ci.yml | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 5cc6057..62b90c0 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -3,8 +3,6 @@ name: CI on: push: pull_request: - schedule: - - cron: '5 5 * * *' jobs: testsuite: @@ -28,4 +26,4 @@ jobs: strategy: fail-fast: false matrix: - php: [ '8.0', '8.1', '8.2' ] + php: [ '8.0', '8.1', '8.2', '8.3' ] From 33e6df9cd58a6efc776217a1f0a4e3db5235b5d9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Axel=20B=C3=B6swetter?= Date: Wed, 19 Jun 2024 15:24:05 +0200 Subject: [PATCH 3/3] [BUGFIX] lower version contraint of dev package to fullfill php >= 8.0 specification --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 4b196ad..2cc1090 100644 --- a/composer.json +++ b/composer.json @@ -34,7 +34,7 @@ "phpstan/phpstan": "^1.10", "phpstan/phpstan-deprecation-rules": "^1.1", "phpstan/phpstan-strict-rules": "^1.5", - "typo3/coding-standards": "^0.8" + "typo3/coding-standards": "^0.7" }, "replace": { "sroze/companienv": "*"