mirror of
https://github.com/rectorphp/rector.git
synced 2025-01-29 11:33:33 +01:00
move check_services_in_yaml_configs to ValidateServicesInSetsCommand
This commit is contained in:
parent
be4b34302f
commit
a957eba2eb
@ -2,143 +2,4 @@
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
use Nette\Utils\Strings;
|
||||
use Rector\Core\Exception\ShouldNotHappenException;
|
||||
use Rector\NodeTypeResolver\ClassExistenceStaticHelper;
|
||||
use Symfony\Component\Finder\Finder;
|
||||
use Symfony\Component\Finder\SplFileInfo;
|
||||
use Symfony\Component\Yaml\Yaml;
|
||||
|
||||
require __DIR__ . '/../vendor/autoload.php';
|
||||
|
||||
$serviceExistenceConfigChecker = new ServiceExistenceConfigChecker();
|
||||
$serviceExistenceConfigChecker->check();
|
||||
|
||||
final class ServiceExistenceConfigChecker
|
||||
{
|
||||
/**
|
||||
* @var YamlConfigFileProvider
|
||||
*/
|
||||
private $yamlConfigFileProvider;
|
||||
|
||||
/**
|
||||
* @var ServiceConfigurationValidator
|
||||
*/
|
||||
private $serviceConfigurationValidator;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->yamlConfigFileProvider = new YamlConfigFileProvider();
|
||||
$this->serviceConfigurationValidator = new ServiceConfigurationValidator();
|
||||
}
|
||||
|
||||
public function check(): void
|
||||
{
|
||||
foreach ($this->yamlConfigFileProvider->provider() as $configFileInfo) {
|
||||
$yamlContent = Yaml::parseFile($configFileInfo->getRealPath());
|
||||
if (! isset($yamlContent['services'])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
foreach ($yamlContent['services'] as $service => $serviceConfiguration) {
|
||||
// configuration → skip
|
||||
if (Strings::startsWith($service, '_')) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// autodiscovery → skip
|
||||
if (Strings::endsWith($service, '\\')) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (! ClassExistenceStaticHelper::doesClassLikeExist($service)) {
|
||||
throw new ShouldNotHappenException(sprintf(
|
||||
'Service "%s" from config "%s" was not found. Check if it really exists or is even autoload, please',
|
||||
$service,
|
||||
$configFileInfo->getRealPath()
|
||||
));
|
||||
}
|
||||
|
||||
$this->serviceConfigurationValidator->validate($service, $serviceConfiguration, $configFileInfo);
|
||||
}
|
||||
}
|
||||
|
||||
echo 'All configs have existing services - good job!' . PHP_EOL;
|
||||
}
|
||||
}
|
||||
|
||||
final class YamlConfigFileProvider
|
||||
{
|
||||
/**
|
||||
* @return SplFileInfo[]
|
||||
*/
|
||||
public function provider(): array
|
||||
{
|
||||
$finder = (new Finder())->name('*.yaml')
|
||||
->in(__DIR__ . '/../config')
|
||||
->files();
|
||||
|
||||
return iterator_to_array($finder->getIterator());
|
||||
}
|
||||
}
|
||||
|
||||
final class ServiceConfigurationValidator
|
||||
{
|
||||
public function validate(string $serviceClass, $configuration, SplFileInfo $configFileInfo): void
|
||||
{
|
||||
if (! is_array($configuration)) {
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (array_keys($configuration) as $key) {
|
||||
if (! $this->isArgumentName($key)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$constructorParameterNames = $this->resolveClassConstructorArgumentNames($serviceClass);
|
||||
if (in_array($key, $constructorParameterNames, true)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
throw new ShouldNotHappenException(sprintf(
|
||||
'Service "%s" has unused argument "%s" in config "%s".%sCorrect it to one of existing arguments "%s".',
|
||||
$serviceClass,
|
||||
$key,
|
||||
$configFileInfo->getRealPath(),
|
||||
PHP_EOL,
|
||||
implode('", "', $constructorParameterNames)
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
private function isArgumentName($key): bool
|
||||
{
|
||||
if (! is_string($key)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return Strings::startsWith($key, '$');
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string[]
|
||||
*/
|
||||
private function resolveClassConstructorArgumentNames(string $class): array
|
||||
{
|
||||
$reflectionClass = new ReflectionClass($class);
|
||||
$constructorReflection = $reflectionClass->getConstructor();
|
||||
|
||||
if ($constructorReflection === null) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$constructorParameterNames = [];
|
||||
foreach ($constructorReflection->getParameters() as $parameterReflection) {
|
||||
$constructorParameterNames[] = '$' . $parameterReflection->getName();
|
||||
}
|
||||
|
||||
sort($constructorParameterNames);
|
||||
|
||||
return $constructorParameterNames;
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,98 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Rector\Utils\SetRunner\Command;
|
||||
|
||||
use Nette\Utils\Strings;
|
||||
use Rector\Core\Exception\ShouldNotHappenException;
|
||||
use Rector\NodeTypeResolver\ClassExistenceStaticHelper;
|
||||
use Rector\Utils\SetRunner\Validation\ServiceConfigurationValidator;
|
||||
use Rector\Utils\SetRunner\Yaml\YamlConfigFileProvider;
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Symfony\Component\Console\Style\SymfonyStyle;
|
||||
use Symfony\Component\Yaml\Yaml;
|
||||
use Symplify\PackageBuilder\Console\Command\CommandNaming;
|
||||
use Symplify\PackageBuilder\Console\ShellCode;
|
||||
use Symplify\SmartFileSystem\SmartFileInfo;
|
||||
|
||||
final class ValidateServicesInSetsCommand extends Command
|
||||
{
|
||||
/**
|
||||
* @var SymfonyStyle
|
||||
*/
|
||||
private $symfonyStyle;
|
||||
|
||||
/**
|
||||
* @var ServiceConfigurationValidator
|
||||
*/
|
||||
private $serviceConfigurationValidator;
|
||||
|
||||
/**
|
||||
* @var YamlConfigFileProvider
|
||||
*/
|
||||
private $yamlConfigFileProvider;
|
||||
|
||||
public function __construct(
|
||||
SymfonyStyle $symfonyStyle,
|
||||
ServiceConfigurationValidator $serviceConfigurationValidator,
|
||||
YamlConfigFileProvider $yamlConfigFileProvider
|
||||
) {
|
||||
$this->symfonyStyle = $symfonyStyle;
|
||||
$this->serviceConfigurationValidator = $serviceConfigurationValidator;
|
||||
$this->yamlConfigFileProvider = $yamlConfigFileProvider;
|
||||
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
protected function configure(): void
|
||||
{
|
||||
$this->setName(CommandNaming::classToName(self::class));
|
||||
$this->setDescription('[CI] Validate services in sets');
|
||||
}
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output): int
|
||||
{
|
||||
foreach ($this->yamlConfigFileProvider->provider() as $configFileInfo) {
|
||||
$this->symfonyStyle->note(sprintf('Validating config "%s"', $configFileInfo->getRelativeFilePathFromCwd()));
|
||||
|
||||
$yamlContent = Yaml::parseFile($configFileInfo->getRealPath());
|
||||
if (! isset($yamlContent['services'])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
foreach ($yamlContent['services'] as $service => $serviceConfiguration) {
|
||||
$this->validateService($service, $serviceConfiguration, $configFileInfo);
|
||||
}
|
||||
}
|
||||
|
||||
$this->symfonyStyle->success('All configs have existing services');
|
||||
|
||||
return ShellCode::SUCCESS;
|
||||
}
|
||||
|
||||
private function validateService($service, $serviceConfiguration, SmartFileInfo $configFileInfo): void
|
||||
{
|
||||
// configuration → skip
|
||||
if (Strings::startsWith($service, '_')) {
|
||||
return;
|
||||
}
|
||||
|
||||
// autodiscovery → skip
|
||||
if (Strings::endsWith($service, '\\')) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (! ClassExistenceStaticHelper::doesClassLikeExist($service)) {
|
||||
throw new ShouldNotHappenException(sprintf(
|
||||
'Service "%s" from config "%s" was not found. Check if it really exists or is even autoload, please',
|
||||
$service,
|
||||
$configFileInfo->getRealPath()
|
||||
));
|
||||
}
|
||||
|
||||
$this->serviceConfigurationValidator->validate($service, $serviceConfiguration, $configFileInfo);
|
||||
}
|
||||
}
|
@ -0,0 +1,71 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Rector\Utils\SetRunner\Validation;
|
||||
|
||||
use Nette\Utils\Strings;
|
||||
use Rector\Core\Exception\ShouldNotHappenException;
|
||||
use ReflectionClass;
|
||||
use Symplify\SmartFileSystem\SmartFileInfo;
|
||||
|
||||
final class ServiceConfigurationValidator
|
||||
{
|
||||
public function validate(string $serviceClass, $configuration, SmartFileInfo $configFileInfo): void
|
||||
{
|
||||
if (! is_array($configuration)) {
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (array_keys($configuration) as $key) {
|
||||
if (! $this->isArgumentName($key)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$constructorParameterNames = $this->resolveClassConstructorArgumentNames($serviceClass);
|
||||
if (in_array($key, $constructorParameterNames, true)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
throw new ShouldNotHappenException(sprintf(
|
||||
'Service "%s" has unused argument "%s" in config "%s".%sCorrect it to one of existing arguments "%s".',
|
||||
$serviceClass,
|
||||
$key,
|
||||
$configFileInfo->getRealPath(),
|
||||
PHP_EOL,
|
||||
implode('", "', $constructorParameterNames)
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
private function isArgumentName($key): bool
|
||||
{
|
||||
if (! is_string($key)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return Strings::startsWith($key, '$');
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string[]
|
||||
*/
|
||||
private function resolveClassConstructorArgumentNames(string $class): array
|
||||
{
|
||||
$reflectionClass = new ReflectionClass($class);
|
||||
$constructorReflection = $reflectionClass->getConstructor();
|
||||
|
||||
if ($constructorReflection === null) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$constructorParameterNames = [];
|
||||
foreach ($constructorReflection->getParameters() as $parameterReflection) {
|
||||
$constructorParameterNames[] = '$' . $parameterReflection->getName();
|
||||
}
|
||||
|
||||
sort($constructorParameterNames);
|
||||
|
||||
return $constructorParameterNames;
|
||||
}
|
||||
}
|
35
utils/set-runner/src/Yaml/YamlConfigFileProvider.php
Normal file
35
utils/set-runner/src/Yaml/YamlConfigFileProvider.php
Normal file
@ -0,0 +1,35 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Rector\Utils\SetRunner\Yaml;
|
||||
|
||||
use Symfony\Component\Finder\Finder;
|
||||
use Symplify\SmartFileSystem\Finder\FinderSanitizer;
|
||||
use Symplify\SmartFileSystem\SmartFileInfo;
|
||||
|
||||
final class YamlConfigFileProvider
|
||||
{
|
||||
/**
|
||||
* @var FinderSanitizer
|
||||
*/
|
||||
private $finderSanitizer;
|
||||
|
||||
public function __construct(FinderSanitizer $finderSanitizer)
|
||||
{
|
||||
$this->finderSanitizer = $finderSanitizer;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return SmartFileInfo[]
|
||||
*/
|
||||
public function provider(): array
|
||||
{
|
||||
$finder = (new Finder())->name('*.yaml')
|
||||
->in(__DIR__ . '/../../../../config')
|
||||
->sortByName()
|
||||
->files();
|
||||
|
||||
return $this->finderSanitizer->sanitize($finder);
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user