Skip to content

Commit

Permalink
[DX] Various injection and tests details improvement (#4702)
Browse files Browse the repository at this point in the history
  • Loading branch information
TomasVotruba committed Aug 7, 2023
1 parent 7725801 commit 6f1f267
Show file tree
Hide file tree
Showing 15 changed files with 497 additions and 120 deletions.
1 change: 1 addition & 0 deletions config/config.php
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,7 @@
__DIR__ . '/../src/Exception',
__DIR__ . '/../src/DependencyInjection/CompilerPass',
__DIR__ . '/../src/DependencyInjection/Loader',
__DIR__ . '/../src/DependencyInjection/LazyContainerFactory.php',
__DIR__ . '/../src/Kernel',
__DIR__ . '/../src/ValueObject',
__DIR__ . '/../src/Bootstrap',
Expand Down
6 changes: 2 additions & 4 deletions packages-tests/Caching/Detector/config.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,8 @@

use Rector\Caching\ValueObject\Storage\MemoryCacheStorage;
use Rector\Config\RectorConfig;
use Rector\Core\Configuration\Option;

return static function (RectorConfig $rectorConfig): void {
$parameters = $rectorConfig->parameters();
$parameters->set(Option::CACHE_DIR, sys_get_temp_dir() . '/_rector_cached_files_test');
$parameters->set(Option::CACHE_CLASS, MemoryCacheStorage::class);
$rectorConfig->cacheDirectory(sys_get_temp_dir() . '/_rector_cached_files_test');
$rectorConfig->cacheClass(MemoryCacheStorage::class);
};
6 changes: 2 additions & 4 deletions packages-tests/Caching/ValueObject/Storage/config.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,8 @@

use Rector\Caching\ValueObject\Storage\MemoryCacheStorage;
use Rector\Config\RectorConfig;
use Rector\Core\Configuration\Option;

return static function (RectorConfig $rectorConfig): void {
$parameters = $rectorConfig->parameters();
$parameters->set(Option::CACHE_DIR, sys_get_temp_dir() . '/_rector_cached_files_test');
$parameters->set(Option::CACHE_CLASS, MemoryCacheStorage::class);
$rectorConfig->cacheDirectory(sys_get_temp_dir() . '/_rector_cached_files_test');
$rectorConfig->cacheClass(MemoryCacheStorage::class);
};
287 changes: 287 additions & 0 deletions packages/Config/LazyRectorConfig.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,287 @@
<?php

declare(strict_types=1);

namespace Rector\Config;

use Illuminate\Container\Container;
use Rector\Caching\Contract\ValueObject\Storage\CacheStorageInterface;
use Rector\Core\Configuration\Option;
use Rector\Core\Configuration\Parameter\SimpleParameterProvider;
use Rector\Core\Configuration\ValueObjectInliner;
use Rector\Core\Contract\Rector\ConfigurableRectorInterface;
use Rector\Core\Contract\Rector\NonPhpRectorInterface;
use Rector\Core\Contract\Rector\PhpRectorInterface;
use Rector\Core\Contract\Rector\RectorInterface;
use Rector\Core\Exception\ShouldNotHappenException;
use Rector\Core\ValueObject\PhpVersion;
use Webmozart\Assert\Assert;

/**
* @api soon be used as public API
*/
final class LazyRectorConfig extends Container
{
/**
* @param string[] $paths
*/
public function paths(array $paths): void
{
Assert::allString($paths);
SimpleParameterProvider::setParameter(Option::PATHS, $paths);
}

/**
* @param string[] $sets
*/
public function sets(array $sets): void
{
Assert::allString($sets);

foreach ($sets as $set) {
Assert::fileExists($set);
$this->import($set);
}
}

public function disableParallel(): void
{
SimpleParameterProvider::setParameter(Option::PARALLEL, false);
}

public function parallel(int $seconds = 120, int $maxNumberOfProcess = 16, int $jobSize = 20): void
{
SimpleParameterProvider::setParameter(Option::PARALLEL, true);
SimpleParameterProvider::setParameter(Option::PARALLEL_JOB_TIMEOUT_IN_SECONDS, $seconds);
SimpleParameterProvider::setParameter(Option::PARALLEL_MAX_NUMBER_OF_PROCESSES, $maxNumberOfProcess);
SimpleParameterProvider::setParameter(Option::PARALLEL_JOB_SIZE, $jobSize);
}

public function noDiffs(): void
{
SimpleParameterProvider::setParameter(Option::NO_DIFFS, true);
}

public function memoryLimit(string $memoryLimit): void
{
SimpleParameterProvider::setParameter(Option::MEMORY_LIMIT, $memoryLimit);
}

/**
* @param array<int|string, mixed> $criteria
*/
public function skip(array $criteria): void
{
SimpleParameterProvider::addParameter(Option::SKIP, $criteria);
}

public function removeUnusedImports(bool $removeUnusedImports = true): void
{
SimpleParameterProvider::setParameter(Option::REMOVE_UNUSED_IMPORTS, $removeUnusedImports);
}

public function importNames(bool $importNames = true, bool $importDocBlockNames = true): void
{
SimpleParameterProvider::setParameter(Option::AUTO_IMPORT_NAMES, $importNames);
SimpleParameterProvider::setParameter(Option::AUTO_IMPORT_DOC_BLOCK_NAMES, $importDocBlockNames);
}

public function importShortClasses(bool $importShortClasses = true): void
{
SimpleParameterProvider::setParameter(Option::IMPORT_SHORT_CLASSES, $importShortClasses);
}

/**
* Set PHPStan custom config to load extensions and custom configuration to Rector.
* By default, the "phpstan.neon" path is used.
*/
public function phpstanConfig(string $filePath): void
{
Assert::fileExists($filePath);

SimpleParameterProvider::setParameter(Option::PHPSTAN_FOR_RECTOR_PATH, $filePath);
}

/**
* @param class-string<ConfigurableRectorInterface&RectorInterface> $rectorClass
* @param mixed[] $configuration
*/
public function ruleWithConfiguration(string $rectorClass, array $configuration): void
{
Assert::classExists($rectorClass);
Assert::isAOf($rectorClass, RectorInterface::class);
Assert::isAOf($rectorClass, ConfigurableRectorInterface::class);

// decorate with value object inliner so Symfony understands, see https://getrector.com/blog/2020/09/07/how-to-inline-value-object-in-symfony-php-config
array_walk_recursive($configuration, static function (&$value) {
if (is_object($value)) {
$value = ValueObjectInliner::inline($value);
}

return $value;
});

$this->singleton($rectorClass);
$this->extend($rectorClass, function (ConfigurableRectorInterface $configurableRector) use ($configuration) {
$configurableRector->configure($configuration);
});

$this->tagRectorService($rectorClass);
}

/**
* @param class-string<RectorInterface> $rectorClass
*/
public function rule(string $rectorClass): void
{
Assert::classExists($rectorClass);
Assert::isAOf($rectorClass, RectorInterface::class);

$this->singleton($rectorClass);
$this->tagRectorService($rectorClass);
}

public function import(string $setFilePath): void
{
$self = $this;
$callable = (require $setFilePath);

Assert::isCallable($callable);
/** @var callable(Container $container): void $callable */
$callable($self);
}

/**
* @param array<class-string<RectorInterface>> $rectorClasses
*/
public function rules(array $rectorClasses): void
{
Assert::allString($rectorClasses);

$duplicatedRectorClasses = $this->resolveDuplicatedValues($rectorClasses);
if ($duplicatedRectorClasses !== []) {
throw new ShouldNotHappenException('Following rules are registered twice: ' . implode(
', ',
$duplicatedRectorClasses
));
}

foreach ($rectorClasses as $rectorClass) {
$this->rule($rectorClass);
}
}

/**
* @param PhpVersion::* $phpVersion
*/
public function phpVersion(int $phpVersion): void
{
SimpleParameterProvider::setParameter(Option::PHP_VERSION_FEATURES, $phpVersion);
}

/**
* @param string[] $autoloadPaths
*/
public function autoloadPaths(array $autoloadPaths): void
{
Assert::allString($autoloadPaths);

SimpleParameterProvider::setParameter(Option::AUTOLOAD_PATHS, $autoloadPaths);
}

/**
* @param string[] $bootstrapFiles
*/
public function bootstrapFiles(array $bootstrapFiles): void
{
Assert::allString($bootstrapFiles);

SimpleParameterProvider::setParameter(Option::BOOTSTRAP_FILES, $bootstrapFiles);
}

public function symfonyContainerXml(string $filePath): void
{
SimpleParameterProvider::setParameter(Option::SYMFONY_CONTAINER_XML_PATH_PARAMETER, $filePath);
}

public function symfonyContainerPhp(string $filePath): void
{
SimpleParameterProvider::setParameter(Option::SYMFONY_CONTAINER_PHP_PATH_PARAMETER, $filePath);
}

/**
* @param string[] $extensions
*/
public function fileExtensions(array $extensions): void
{
Assert::allString($extensions);

SimpleParameterProvider::setParameter(Option::FILE_EXTENSIONS, $extensions);
}

public function cacheDirectory(string $directoryPath): void
{
// cache directory path is created via mkdir in CacheFactory
// when not exists, so no need to validate $directoryPath is a directory
SimpleParameterProvider::setParameter(Option::CACHE_DIR, $directoryPath);
}

public function containerCacheDirectory(string $directoryPath): void
{
// container cache directory path must be a directory on the first place
Assert::directory($directoryPath);

SimpleParameterProvider::setParameter(Option::CONTAINER_CACHE_DIRECTORY, $directoryPath);
}

/**
* @param class-string<CacheStorageInterface> $cacheClass
*/
public function cacheClass(string $cacheClass): void
{
Assert::isAOf($cacheClass, CacheStorageInterface::class);

SimpleParameterProvider::setParameter(Option::CACHE_CLASS, $cacheClass);
}

/**
* @see https://github.com/nikic/PHP-Parser/issues/723#issuecomment-712401963
*/
public function indent(string $character, int $count): void
{
SimpleParameterProvider::setParameter(Option::INDENT_CHAR, $character);
SimpleParameterProvider::setParameter(Option::INDENT_SIZE, $count);
}

/**
* @param string[] $values
* @return string[]
*/
private function resolveDuplicatedValues(array $values): array
{
$counted = array_count_values($values);
$duplicates = [];

foreach ($counted as $value => $count) {
if ($count > 1) {
$duplicates[] = $value;
}
}

return array_unique($duplicates);
}

/**
* @param class-string<RectorInterface|PhpRectorInterface|NonPhpRectorInterface> $rectorClass
*/
private function tagRectorService(string $rectorClass): void
{
$this->tag($rectorClass, RectorInterface::class);

if (is_a($rectorClass, PhpRectorInterface::class, true)) {
$this->tag($rectorClass, PhpRectorInterface::class);
} elseif (is_a($rectorClass, NonPhpRectorInterface::class, true)) {
$this->tag($rectorClass, NonPhpRectorInterface::class);
}
}
}
3 changes: 0 additions & 3 deletions packages/Testing/PHPUnit/AbstractRectorTestCase.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@
use Nette\Utils\Strings;
use PHPStan\Analyser\NodeScopeResolver;
use PHPUnit\Framework\ExpectationFailedException;
use Psr\Container\ContainerInterface;
use Rector\Core\Application\ApplicationFileProcessor;
use Rector\Core\Autoloading\AdditionalAutoloader;
use Rector\Core\Autoloading\BootstrapFilesIncluder;
Expand All @@ -26,8 +25,6 @@

abstract class AbstractRectorTestCase extends AbstractTestCase implements RectorTestInterface
{
protected static ?ContainerInterface $allRectorContainer = null;

private DynamicSourceLocatorProvider $dynamicSourceLocatorProvider;

private ApplicationFileProcessor $applicationFileProcessor;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
namespace Rector\VendorLocker\Exception;

use Exception;

final class UnresolvableClassException extends Exception
{
}
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,6 @@ public function shouldSkipReturnTypeChange(ClassMethod $classMethod, Type $paren
return $this->typeComparator->areTypesEqual($currentReturnType, $parentType);
}


private function resolveParentClassMethod(ClassMethod $classMethod): ?MethodReflection
{
$classReflection = $this->reflectionResolver->resolveClassReflection($classMethod);
Expand Down
11 changes: 11 additions & 0 deletions phpstan.neon
Original file line number Diff line number Diff line change
Expand Up @@ -691,3 +691,14 @@ parameters:
-
message: '#\$this as argument is not allowed\. Refactor method to service composition#'
path: packages/NodeTypeResolver/NodeTypeResolver.php

- '#Call to an undefined method Rector\\Config\\RectorConfig\:\:(.*?)\(\)#'
- '#Call to an undefined method Illuminate\\Container\\Container\:\:(.*?)\(\)#'
- '#Parameter 1 should use "Illuminate\\Container\\Container" type as the only type passed to this method#'
- '#Parameter \#1 \$container of method Rector\\Core\\DependencyInjection\\LazyContainerFactory\:\:createPHPStanServices\(\) expects Rector\\Config\\RectorConfig, Illuminate\\Container\\Container given#'

-
message: '#Content of method "(.*?)" is duplicated\. Use unique content or service instead#'
paths:
- packages/Config/RectorConfig.php
- packages/Config/LazyRectorConfig.php

0 comments on commit 6f1f267

Please sign in to comment.