Skip to content

Commit

Permalink
Extract path resolving into a service
Browse files Browse the repository at this point in the history
  • Loading branch information
HypeMC committed Dec 15, 2022
1 parent 4dd078b commit 434d369
Show file tree
Hide file tree
Showing 6 changed files with 170 additions and 107 deletions.
9 changes: 8 additions & 1 deletion config/services.xml
Original file line number Diff line number Diff line change
Expand Up @@ -50,11 +50,18 @@

<service id="Bizkit\LoggableCommandBundle\DependencyInjection\Configurator\LoggableOutputConfigurator">
<argument type="service" id="Bizkit\LoggableCommandBundle\ConfigurationProvider\ConfigurationProviderInterface" />
<argument type="service" id="Bizkit\LoggableCommandBundle\FilenameProvider\FilenameProviderInterface" />
<argument type="service" id="Bizkit\LoggableCommandBundle\PathResolver\PathResolverInterface" />
<argument /> <!-- template logger -->
<argument type="tagged_locator" tag="bizkit_loggable_command.handler_factory" index-by="type" />
</service>

<service id="Bizkit\LoggableCommandBundle\PathResolver\DefaultPathResolver">
<argument type="service" id="Bizkit\LoggableCommandBundle\FilenameProvider\FilenameProviderInterface" />
</service>

<service id="Bizkit\LoggableCommandBundle\PathResolver\PathResolverInterface"
alias="Bizkit\LoggableCommandBundle\PathResolver\DefaultPathResolver" />

<service id="Bizkit\LoggableCommandBundle\FilenameProvider\DefaultFilenameProvider" />

<service id="Bizkit\LoggableCommandBundle\FilenameProvider\FilenameProviderInterface"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,15 @@
namespace Bizkit\LoggableCommandBundle\DependencyInjection\Configurator;

use Bizkit\LoggableCommandBundle\ConfigurationProvider\ConfigurationProviderInterface;
use Bizkit\LoggableCommandBundle\FilenameProvider\FilenameProviderInterface;
use Bizkit\LoggableCommandBundle\HandlerFactory\HandlerFactoryInterface;
use Bizkit\LoggableCommandBundle\LoggableOutput\LoggableOutputInterface;
use Bizkit\LoggableCommandBundle\PathResolver\PathResolverInterface;
use Monolog\Logger;
use Symfony\Contracts\Service\ServiceProviderInterface;

/**
* @internal
*/
final class LoggableOutputConfigurator
{
/**
Expand All @@ -19,9 +22,9 @@ final class LoggableOutputConfigurator
private $configurationProvider;

/**
* @var FilenameProviderInterface
* @var PathResolverInterface
*/
private $filenameProvider;
private $pathResolver;

/**
* @var Logger
Expand All @@ -35,12 +38,12 @@ final class LoggableOutputConfigurator

public function __construct(
ConfigurationProviderInterface $configurationProvider,
FilenameProviderInterface $filenameProvider,
PathResolverInterface $pathResolver,
Logger $templateLogger,
ServiceProviderInterface $handlerFactoryLocator
) {
$this->configurationProvider = $configurationProvider;
$this->filenameProvider = $filenameProvider;
$this->pathResolver = $pathResolver;
$this->templateLogger = $templateLogger;
$this->handlerFactoryLocator = $handlerFactoryLocator;
}
Expand All @@ -51,7 +54,7 @@ public function __invoke(LoggableOutputInterface $loggableOutput): void

$handlerOptionsFactory = $this->getHandlerFactory($handlerOptions['type']);

$handlerOptions['path'] = $this->resolvePath($loggableOutput, $handlerOptions);
$handlerOptions['path'] = ($this->pathResolver)($handlerOptions, $loggableOutput);

/*
* We clone the logger to ensure that each command gets its unique stream handler,
Expand All @@ -65,22 +68,6 @@ public function __invoke(LoggableOutputInterface $loggableOutput): void
$loggableOutput->setOutputLogger($logger);
}

private function resolvePath(LoggableOutputInterface $loggableOutput, array $handlerOptions): string
{
$resolvedPath = $handlerOptions['path'];

if (false !== strpos($resolvedPath, '{filename}')) {
$filename = $handlerOptions['filename'] ?? ($this->filenameProvider)($loggableOutput);
$resolvedPath = strtr($resolvedPath, ['{filename}' => $filename]);
}

if (false !== strpos($resolvedPath, '{date}')) {
$resolvedPath = strtr($resolvedPath, ['{date}' => date($handlerOptions['date_format'])]);
}

return $resolvedPath;
}

private function getHandlerFactory(string $handlerType): HandlerFactoryInterface
{
if (!$this->handlerFactoryLocator->has($handlerType)) {
Expand Down
37 changes: 37 additions & 0 deletions src/PathResolver/DefaultPathResolver.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
<?php

declare(strict_types=1);

namespace Bizkit\LoggableCommandBundle\PathResolver;

use Bizkit\LoggableCommandBundle\FilenameProvider\FilenameProviderInterface;
use Bizkit\LoggableCommandBundle\LoggableOutput\LoggableOutputInterface;

final class DefaultPathResolver implements PathResolverInterface
{
/**
* @var FilenameProviderInterface
*/
private $filenameProvider;

public function __construct(FilenameProviderInterface $filenameProvider)
{
$this->filenameProvider = $filenameProvider;
}

public function __invoke(array $handlerOptions, LoggableOutputInterface $loggableOutput): string
{
$resolvedPath = $handlerOptions['path'];

if (false !== strpos($resolvedPath, '{filename}')) {
$filename = $handlerOptions['filename'] ?? ($this->filenameProvider)($loggableOutput);
$resolvedPath = strtr($resolvedPath, ['{filename}' => $filename]);
}

if (false !== strpos($resolvedPath, '{date}')) {
$resolvedPath = strtr($resolvedPath, ['{date}' => date($handlerOptions['date_format'])]);
}

return $resolvedPath;
}
}
12 changes: 12 additions & 0 deletions src/PathResolver/PathResolverInterface.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<?php

declare(strict_types=1);

namespace Bizkit\LoggableCommandBundle\PathResolver;

use Bizkit\LoggableCommandBundle\LoggableOutput\LoggableOutputInterface;

interface PathResolverInterface
{
public function __invoke(array $handlerOptions, LoggableOutputInterface $loggableOutput): string;
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,35 +4,51 @@

namespace Bizkit\LoggableCommandBundle\Tests\DependencyInjection\Configurator;

use Bizkit\LoggableCommandBundle\ConfigurationProvider\ConfigurationProviderInterface;
use Bizkit\LoggableCommandBundle\ConfigurationProvider\DefaultConfigurationProvider;
use Bizkit\LoggableCommandBundle\DependencyInjection\Configurator\LoggableOutputConfigurator;
use Bizkit\LoggableCommandBundle\FilenameProvider\DefaultFilenameProvider;
use Bizkit\LoggableCommandBundle\FilenameProvider\FilenameProviderInterface;
use Bizkit\LoggableCommandBundle\PathResolver\PathResolverInterface;
use Bizkit\LoggableCommandBundle\Tests\DependencyInjection\Fixtures\DummyHandler;
use Bizkit\LoggableCommandBundle\Tests\DependencyInjection\Fixtures\DummyHandlerFactory;
use Bizkit\LoggableCommandBundle\Tests\Fixtures\DummyLoggableOutput;
use Bizkit\LoggableCommandBundle\Tests\TestCase;
use Monolog\Logger;
use Symfony\Bridge\PhpUnit\ClockMock;
use Symfony\Component\DependencyInjection\ServiceLocator;

/**
* @covers \Bizkit\LoggableCommandBundle\DependencyInjection\Configurator\LoggableOutputConfigurator
*
* @group time-sensitive
*/
final class LoggableOutputConfiguratorTest extends TestCase
{
/**
* @dataProvider handlerOptions
*/
public function testLoggerIsConfiguredAsExpected(array $handlerOptions, string $resolvedPath): void
public function testLoggerIsConfiguredAsExpected(): void
{
ClockMock::withClockMock(1612711778);
$handlerOptions = [
'type' => 'dummy',
'path' => 'log/console/{filename}.log',
];
$resolvedPath = 'log/console/dummy_loggable_output.log';

$loggableOutput = new DummyLoggableOutput();

$configurationProvider = $this->createMock(ConfigurationProviderInterface::class);
$configurationProvider
->expects($this->once())
->method('__invoke')
->with($loggableOutput)
->willReturn($handlerOptions)
;

$pathResolver = $this->createMock(PathResolverInterface::class);
$pathResolver
->expects($this->once())
->method('__invoke')
->with($handlerOptions, $loggableOutput)
->willReturn($resolvedPath)
;

$configurator = new LoggableOutputConfigurator(
new DefaultConfigurationProvider($handlerOptions),
new DefaultFilenameProvider(),
$configurationProvider,
$pathResolver,
$templateLogger = new Logger('foo'),
new ServiceLocator([
'dummy' => static function () {
Expand All @@ -41,8 +57,6 @@ public function testLoggerIsConfiguredAsExpected(array $handlerOptions, string $
])
);

$loggableOutput = new DummyLoggableOutput();

$configurator($loggableOutput);

/** @var Logger $logger */
Expand All @@ -60,81 +74,14 @@ public function testLoggerIsConfiguredAsExpected(array $handlerOptions, string $
$this->assertSame($resolvedPath, $handler->getHandlerOptions()['path']);
}

public function handlerOptions(): iterable
{
yield 'Filename & date' => [[
'type' => 'dummy',
'path' => 'log/console/{filename}-{date}.log',
'date_format' => 'Y_m_d',
], 'log/console/dummy_loggable_output-2021_02_07.log'];

yield 'Filename from provider' => [[
'type' => 'dummy',
'path' => 'log/console/{filename}.log',
], 'log/console/dummy_loggable_output.log'];

yield 'Filename' => [[
'type' => 'dummy',
'path' => 'log/console/{filename}.log',
'filename' => 'baz',
], 'log/console/baz.log'];

yield 'Date' => [[
'type' => 'dummy',
'path' => 'log/console/foo-{date}.log',
'date_format' => 'Y_m_d',
], 'log/console/foo-2021_02_07.log'];

yield 'None' => [[
'type' => 'dummy',
'path' => 'log/console/foo.log',
], 'log/console/foo.log'];
}

public function testFilenameProviderIsNotCalledWhenFilenameIsProvided(): void
{
$handlerOptions = [
'type' => 'dummy',
'path' => 'log/console/{filename}.log',
'filename' => 'dummy-filename',
];

$filenameProvider = $this->createMock(FilenameProviderInterface::class);
$filenameProvider->expects($this->never())->method('__invoke');

$configurator = new LoggableOutputConfigurator(
new DefaultConfigurationProvider($handlerOptions),
$filenameProvider,
new Logger('foo'),
new ServiceLocator([
'dummy' => static function () {
return new DummyHandlerFactory();
},
])
);

$loggableOutput = new DummyLoggableOutput();

$configurator($loggableOutput);

/** @var Logger $logger */
$logger = $loggableOutput->getOutputLogger();

/** @var DummyHandler $handler */
$handler = $logger->popHandler();

$this->assertSame('log/console/dummy-filename.log', $handler->getHandlerOptions()['path']);
}

public function testExceptionIsThrownIfHandlerFactoryIsNotRegistered(): void
{
$handlerOptions = [
'type' => 'dummy',
'path' => 'log/console/{filename}.log',
];

$filenameProvider = $this->createMock(FilenameProviderInterface::class);
$filenameProvider->expects($this->never())->method('__invoke');
$pathResolver = $this->createMock(PathResolverInterface::class);
$pathResolver->expects($this->never())->method('__invoke');

$templateLogger = $this->getMockBuilder(Logger::class)
->disableOriginalConstructor()
Expand All @@ -147,7 +94,7 @@ public function testExceptionIsThrownIfHandlerFactoryIsNotRegistered(): void

$configurator = new LoggableOutputConfigurator(
new DefaultConfigurationProvider($handlerOptions),
$filenameProvider,
$pathResolver,
$templateLogger,
new ServiceLocator([])
);
Expand Down
73 changes: 73 additions & 0 deletions tests/PathResolver/DefaultPathResolverTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
<?php

declare(strict_types=1);

namespace Bizkit\LoggableCommandBundle\Tests\PathResolver;

use Bizkit\LoggableCommandBundle\FilenameProvider\DefaultFilenameProvider;
use Bizkit\LoggableCommandBundle\FilenameProvider\FilenameProviderInterface;
use Bizkit\LoggableCommandBundle\PathResolver\DefaultPathResolver;
use Bizkit\LoggableCommandBundle\Tests\Fixtures\DummyLoggableOutput;
use Bizkit\LoggableCommandBundle\Tests\TestCase;
use Symfony\Bridge\PhpUnit\ClockMock;

/**
* @covers \Bizkit\LoggableCommandBundle\PathResolver\DefaultPathResolver
*
* @group time-sensitive
*/
final class DefaultPathResolverTest extends TestCase
{
/**
* @dataProvider handlerOptions
*/
public function testLoggerIsConfiguredAsExpected(array $handlerOptions, string $resolvedPath): void
{
ClockMock::withClockMock(1612711778);

$pathResolver = new DefaultPathResolver(new DefaultFilenameProvider());

$this->assertSame($resolvedPath, $pathResolver($handlerOptions, new DummyLoggableOutput()));
}

public function handlerOptions(): iterable
{
yield 'Filename & date' => [[
'path' => 'log/console/{filename}-{date}.log',
'date_format' => 'Y_m_d',
], 'log/console/dummy_loggable_output-2021_02_07.log'];

yield 'Filename from provider' => [[
'path' => 'log/console/{filename}.log',
], 'log/console/dummy_loggable_output.log'];

yield 'Filename' => [[
'path' => 'log/console/{filename}.log',
'filename' => 'baz',
], 'log/console/baz.log'];

yield 'Date' => [[
'path' => 'log/console/foo-{date}.log',
'date_format' => 'Y_m_d',
], 'log/console/foo-2021_02_07.log'];

yield 'None' => [[
'path' => 'log/console/foo.log',
], 'log/console/foo.log'];
}

public function testFilenameProviderIsNotCalledWhenFilenameIsProvided(): void
{
$handlerOptions = [
'path' => 'log/console/{filename}.log',
'filename' => 'dummy-filename',
];

$filenameProvider = $this->createMock(FilenameProviderInterface::class);
$filenameProvider->expects($this->never())->method('__invoke');

$pathResolver = new DefaultPathResolver($filenameProvider);

$this->assertSame('log/console/dummy-filename.log', $pathResolver($handlerOptions, new DummyLoggableOutput()));
}
}

0 comments on commit 434d369

Please sign in to comment.