Skip to content

Commit

Permalink
Merge pull request #963 from spiral/feature/916
Browse files Browse the repository at this point in the history
Changes behavior for loading system bootloaders.
  • Loading branch information
butschster authored Aug 14, 2023
2 parents ae602f6 + 5d56380 commit d7a1a9d
Show file tree
Hide file tree
Showing 19 changed files with 276 additions and 296 deletions.
2 changes: 1 addition & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,7 @@
"rector/rector": "0.15.23",
"spiral/code-style": "^1.1",
"spiral/nyholm-bridge": "^1.2",
"spiral/testing": "^2.3",
"spiral/testing": "^2.4",
"spiral/validator": "^1.3",
"symplify/monorepo-builder": "^10.2.7",
"vimeo/psalm": "^5.9"
Expand Down
7 changes: 3 additions & 4 deletions src/Boot/src/AbstractKernel.php
Original file line number Diff line number Diff line change
Expand Up @@ -87,8 +87,6 @@ protected function __construct(

$this->finalizer = new Finalizer();
$container->bindSingleton(FinalizerInterface::class, $this->finalizer);

$this->bootloader->bootload($this->defineSystemBootloaders());
}

/**
Expand Down Expand Up @@ -162,13 +160,14 @@ public function run(?EnvironmentInterface $environment = null): ?self
$environment ??= new Environment();
$this->container->bindSingleton(EnvironmentInterface::class, $environment);

$this->fireCallbacks($this->runningCallbacks);

try {
// will protect any against env overwrite action
$this->container->runScope(
[EnvironmentInterface::class => $environment],
function (): void {
$this->bootloader->bootload($this->defineSystemBootloaders());
$this->fireCallbacks($this->runningCallbacks);

$this->bootload();
$this->bootstrap();

Expand Down
9 changes: 6 additions & 3 deletions src/Framework/Bootloader/Attributes/AttributesBootloader.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
use Spiral\Attributes\Psr16CachedReader;
use Spiral\Attributes\ReaderInterface;
use Spiral\Boot\Bootloader\Bootloader;
use Spiral\Boot\EnvironmentInterface;
use Spiral\Config\ConfiguratorInterface;

class AttributesBootloader extends Bootloader
Expand All @@ -32,13 +33,13 @@ public function __construct(
) {
}

public function init(): void
public function init(EnvironmentInterface $env): void
{
$this->config->setDefaults(
AttributesConfig::CONFIG,
[
'annotations' => [
'support' => true,
'support' => $env->get('SUPPORT_ANNOTATIONS', true),
],
],
);
Expand Down Expand Up @@ -68,7 +69,9 @@ private function initReader(
$reader = new Psr16CachedReader($reader, $cache);
}

if ($config->isAnnotationsReaderEnabled()) {
$supportAnnotations = $config->isAnnotationsReaderEnabled();

if ($supportAnnotations) {
if (!\interface_exists(DoctrineReaderInterface::class)) {
throw new InitializationException(
'Doctrine annotations reader is not available, please install "doctrine/annotations" package',
Expand Down
59 changes: 59 additions & 0 deletions src/Framework/Command/Tokenizer/InfoCommand.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
<?php

declare(strict_types=1);

namespace Spiral\Command\Tokenizer;

use Spiral\Boot\DirectoriesInterface;
use Spiral\Console\Attribute\AsCommand;
use Spiral\Console\Command;
use Spiral\Tokenizer\Config\TokenizerConfig;

#[AsCommand(
name: 'tokenizer:info',
description: 'Get information about tokenizer directories to scan'
)]
final class InfoCommand extends Command
{
public function perform(TokenizerConfig $config, DirectoriesInterface $dirs): int
{
$this->info('Included directories:');
$grid = $this->table(['Directory', 'Scope']);
foreach ($config->getDirectories() as $directory) {
$grid->addRow([\str_replace($dirs->get('root'), '', $directory), '']);
}
foreach ($config->getScopes() as $scope => $data) {
foreach ($data['directories'] ?? [] as $directory) {
$grid->addRow([\str_replace($dirs->get('root'), '', $directory), $scope]);
}
}

$grid->render();

$this->newLine();

$this->info('Excluded directories:');
$grid = $this->table(['Directory', 'Scope']);
foreach ($config->getExcludes() as $directory) {
$grid->addRow([\str_replace($dirs->get('root'), '', $directory), '']);
}
foreach ($config->getScopes() as $scope => $data) {
foreach ($data['exclude'] ?? [] as $directory) {
$grid->addRow([\str_replace($dirs->get('root'), '', $directory), $scope]);
}
}

$grid->render();

$this->newLine();
$this->info(
\sprintf('Tokenizer cache: %s', $config->isCacheEnabled() ? '<success>enabled</>' : '<error>disabled</>'),
);
if (!$config->isCacheEnabled()) {
$this->comment('To enable cache, add "TOKENIZER_CACHE_TARGETS=true" to your .env file.');
$this->comment('Read more at https://spiral.dev/docs/advanced-tokenizer/#class-listeners');
}

return self::SUCCESS;
}
}
8 changes: 8 additions & 0 deletions src/Queue/tests/Driver/SyncDriverTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ final class SyncDriverTest extends TestCase
private SyncDriver $queue;
private m\LegacyMockInterface|m\MockInterface|CoreInterface $core;
private m\LegacyMockInterface|m\MockInterface|UuidFactoryInterface $factory;
private UuidFactoryInterface $realfactory;

protected function setUp(): void
{
Expand All @@ -31,6 +32,7 @@ protected function setUp(): void
$container = new Container();
$container->bind(TracerInterface::class, new NullTracer($container));

$this->realfactory = Uuid::getFactory();
Uuid::setFactory($this->factory = m::mock(UuidFactoryInterface::class));

$this->queue = new SyncDriver(
Expand Down Expand Up @@ -70,4 +72,10 @@ public static function payloadDataProvider(): \Traversable
yield [123];
yield [null];
}

protected function tearDown(): void
{
Uuid::setFactory($this->realfactory);
parent::tearDown();
}
}
15 changes: 10 additions & 5 deletions src/Tokenizer/src/Bootloader/TokenizerBootloader.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

use Spiral\Boot\Bootloader\Bootloader;
use Spiral\Boot\DirectoriesInterface;
use Spiral\Boot\EnvironmentInterface;
use Spiral\Config\ConfiguratorInterface;
use Spiral\Config\Patch\Append;
use Spiral\Core\BinderInterface;
Expand Down Expand Up @@ -47,7 +48,7 @@ public function __construct(
) {
}

public function init(BinderInterface $binder, DirectoriesInterface $dirs): void
public function init(BinderInterface $binder, DirectoriesInterface $dirs, EnvironmentInterface $env): void
{
$binder->bindInjector(ClassLocator::class, ClassLocatorInjector::class);
$binder->bindInjector(EnumLocator::class, EnumLocatorInjector::class);
Expand All @@ -65,7 +66,11 @@ public function init(BinderInterface $binder, DirectoriesInterface $dirs): void
'tests',
'migrations',
],
]
'cache' => [
'directory' => $dirs->get('runtime') . 'cache/listeners',
'enabled' => \filter_var($env->get('TOKENIZER_CACHE_TARGETS', false), \FILTER_VALIDATE_BOOL),
],
],
);
}

Expand All @@ -76,7 +81,7 @@ public function addDirectory(string $directory): void
{
$this->config->modify(
TokenizerConfig::CONFIG,
new Append('directories', null, $directory)
new Append('directories', null, $directory),
);
}

Expand All @@ -88,13 +93,13 @@ public function addScopedDirectory(string $scope, string $directory): void
if (!isset($this->config->getConfig(TokenizerConfig::CONFIG)['scopes'][$scope])) {
$this->config->modify(
TokenizerConfig::CONFIG,
new Append('scopes', $scope, [])
new Append('scopes', $scope, []),
);
}

$this->config->modify(
TokenizerConfig::CONFIG,
new Append('scopes.' . $scope, null, $directory)
new Append('scopes.' . $scope, null, $directory),
);
}
}
21 changes: 5 additions & 16 deletions src/Tokenizer/src/Bootloader/TokenizerListenerBootloader.php
Original file line number Diff line number Diff line change
Expand Up @@ -66,29 +66,23 @@ public function boot(AbstractKernel $kernel): void

public function initCachedClassesLoader(
FactoryInterface $factory,
DirectoriesInterface $dirs,
EnvironmentInterface $env,
TokenizerConfig $config,
): ClassesLoaderInterface {
return $this->makeCachedLoader($factory, $dirs, $env, $config, CachedClassesLoader::class);
return $this->makeCachedLoader($factory, $config, CachedClassesLoader::class);
}

public function initCachedEnumsLoader(
FactoryInterface $factory,
DirectoriesInterface $dirs,
EnvironmentInterface $env,
TokenizerConfig $config,
): EnumsLoaderInterface {
return $this->makeCachedLoader($factory, $dirs, $env, $config, CachedEnumsLoader::class);
return $this->makeCachedLoader($factory, $config, CachedEnumsLoader::class);
}

public function initCachedInterfacesLoader(
FactoryInterface $factory,
DirectoriesInterface $dirs,
EnvironmentInterface $env,
TokenizerConfig $config,
): InterfacesLoaderInterface {
return $this->makeCachedLoader($factory, $dirs, $env, $config, CachedInterfacesLoader::class);
return $this->makeCachedLoader($factory, $config, CachedInterfacesLoader::class);
}

/**
Expand All @@ -100,8 +94,6 @@ public function initCachedInterfacesLoader(
*/
private function makeCachedLoader(
FactoryInterface $factory,
DirectoriesInterface $dirs,
EnvironmentInterface $env,
TokenizerConfig $config,
string $classLoader,
): mixed {
Expand All @@ -111,12 +103,9 @@ private function makeCachedLoader(
// but not read from there.
return $factory->make($classLoader, [
'memory' => $factory->make(Memory::class, [
'directory' => $config->getCacheDirectory() ?? $dirs->get('runtime') . 'cache/listeners',
'directory' => $config->getCacheDirectory(),
]),
'readCache' => \filter_var(
$env->get('TOKENIZER_CACHE_TARGETS', $config->isCacheEnabled()),
\FILTER_VALIDATE_BOOL
),
'readCache' => $config->isCacheEnabled(),
]);
}

Expand Down
11 changes: 8 additions & 3 deletions src/Tokenizer/src/Config/TokenizerConfig.php
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,11 @@ public function getScope(string $scope): array
];
}

public function getScopes(): array
{
return $this->config['scopes'] ?? [];
}

/**
* Check if tokenizer listeners cache is enabled.
*/
Expand All @@ -102,16 +107,16 @@ public function getCacheDirectory(): ?string

public function isLoadClassesEnabled(): bool
{
return (bool) ($this->config['load']['classes'] ?? true);
return (bool)($this->config['load']['classes'] ?? true);
}

public function isLoadEnumsEnabled(): bool
{
return (bool) ($this->config['load']['enums'] ?? false);
return (bool)($this->config['load']['enums'] ?? false);
}

public function isLoadInterfacesEnabled(): bool
{
return (bool) ($this->config['load']['interfaces'] ?? false);
return (bool)($this->config['load']['interfaces'] ?? false);
}
}
54 changes: 54 additions & 0 deletions src/Tokenizer/tests/Bootloader/TokenizerBootloaderTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
<?php

declare(strict_types=1);

namespace Spiral\Tests\Tokenizer\Bootloader;

use Mockery as m;
use PHPUnit\Framework\Attributes\DataProvider;
use PHPUnit\Framework\TestCase;
use Spiral\Boot\DirectoriesInterface;
use Spiral\Boot\EnvironmentInterface;
use Spiral\Config\ConfigManager;
use Spiral\Config\Loader\DirectoryLoader;
use Spiral\Core\BinderInterface;
use Spiral\Tokenizer\Bootloader\TokenizerBootloader;
use Spiral\Tokenizer\Config\TokenizerConfig;

final class TokenizerBootloaderTest extends TestCase
{
#[DataProvider('readCacheDataProvider')]
public function testCastingReadCacheEnvVariable(mixed $readCache, bool $expected): void
{
$binder = m::spy(BinderInterface::class);
$dirs = m::mock(DirectoriesInterface::class);
$env = m::mock(EnvironmentInterface::class);

$env->shouldReceive('get')->once()->with('TOKENIZER_CACHE_TARGETS', false)->andReturn($readCache);

$dirs->shouldReceive('get')->once()->with('app')->andReturn('app/');
$dirs->shouldReceive('get')->once()->with('resources')->andReturn('resources/');
$dirs->shouldReceive('get')->once()->with('config')->andReturn('config/');
$dirs->shouldReceive('get')->once()->with('runtime')->andReturn('runtime/');

$bootloader = new TokenizerBootloader($config = new ConfigManager(new DirectoryLoader('config')));
$bootloader->init($binder, $dirs, $env);

$initConfig = $config->getConfig(TokenizerConfig::CONFIG);

$this->assertSame('runtime/cache/listeners', $initConfig['cache']['directory']);
$this->assertSame($expected, $initConfig['cache']['enabled']);
}

public static function readCacheDataProvider(): \Traversable
{
yield [true, true];
yield [false, false];
yield [1, true];
yield [0, false];
yield ['1', true];
yield ['0', false];
yield ['true', true];
yield ['false', false];
}
}
Loading

0 comments on commit d7a1a9d

Please sign in to comment.