Skip to content

Commit

Permalink
Add a console user provider (#309)
Browse files Browse the repository at this point in the history
Also write some tests regarding the console user provider, to verify
that it actually is working.

Fixes #267

Co-authored-by: Damien Harper <[email protected]>
  • Loading branch information
SanderVerkuil and DamienHarper authored Mar 31, 2022
1 parent 8ddfa75 commit 41512ce
Show file tree
Hide file tree
Showing 8 changed files with 231 additions and 0 deletions.
47 changes: 47 additions & 0 deletions src/Event/ConsoleEventSubscriber.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
<?php

declare(strict_types=1);

namespace DH\AuditorBundle\Event;

use DH\Auditor\Configuration;
use DH\Auditor\User\UserProviderInterface;
use DH\AuditorBundle\User\ConsoleUserProvider;
use Symfony\Component\Console\ConsoleEvents;
use Symfony\Component\Console\Event\ConsoleCommandEvent;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;

class ConsoleEventSubscriber implements EventSubscriberInterface
{
private ConsoleUserProvider $consoleUserProvider;
private Configuration $configuration;
private UserProviderInterface $provider;

public function __construct(ConsoleUserProvider $consoleUserProvider, Configuration $configuration, UserProviderInterface $provider)
{
$this->consoleUserProvider = $consoleUserProvider;
$this->configuration = $configuration;
$this->provider = $provider;
}

public static function getSubscribedEvents(): array
{
return [
ConsoleEvents::COMMAND => 'registerConsoleUserProvider',
ConsoleEvents::TERMINATE => 'restoreDefaultUserProvider',
];
}

public function registerConsoleUserProvider(ConsoleCommandEvent $commandEvent): void
{
$command = $commandEvent->getCommand();
$this->consoleUserProvider->setCurrentCommand($command);
$this->configuration->setUserProvider($this->consoleUserProvider);
}

public function restoreDefaultUserProvider(): void
{
$this->consoleUserProvider->setCurrentCommand(null);
$this->configuration->setUserProvider($this->provider);
}
}
8 changes: 8 additions & 0 deletions src/Resources/config/services.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,9 @@ services:
arguments: ['@security.helper', '@DH\Auditor\Provider\Doctrine\Configuration']
dh_auditor.user_provider: '@DH\AuditorBundle\User\UserProvider'

DH\AuditorBundle\User\ConsoleUserProvider:
class: DH\AuditorBundle\User\ConsoleUserProvider

DH\AuditorBundle\Security\SecurityProvider:
class: DH\AuditorBundle\Security\SecurityProvider
arguments: ['@request_stack', '@security.firewall.map']
Expand All @@ -90,5 +93,10 @@ services:
DH\AuditorBundle\Event\ViewerEventSubscriber:
class: DH\AuditorBundle\Event\ViewerEventSubscriber
arguments: ['@DH\Auditor\Auditor']
tags:
- { name: kernel.event_subscriber }

DH\AuditorBundle\Event\ConsoleEventSubscriber:
arguments: ['@DH\AuditorBundle\User\ConsoleUserProvider', '@DH\Auditor\Configuration', '@dh_auditor.user_provider']
tags:
- { name: kernel.event_subscriber }
36 changes: 36 additions & 0 deletions src/User/ConsoleUserProvider.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
<?php

declare(strict_types=1);

namespace DH\AuditorBundle\User;

use DH\Auditor\User\User;
use DH\Auditor\User\UserInterface;
use DH\Auditor\User\UserProviderInterface;
use Symfony\Component\Console\Command\Command;

class ConsoleUserProvider implements UserProviderInterface
{
private ?string $currentCommand = null;

public function __invoke(): ?UserInterface
{
if (null === $this->currentCommand) {
return null;
}

return new User(
'command',
$this->currentCommand ?? ''
);
}

public function setCurrentCommand(?Command $command): void
{
if (null === $command) {
$this->currentCommand = null;
} else {
$this->currentCommand = $command->getName();
}
}
}
50 changes: 50 additions & 0 deletions tests/App/Command/CreatePostCommand.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
<?php

declare(strict_types=1);

namespace DH\AuditorBundle\Tests\App\Command;

use DateTimeImmutable;
use DH\Auditor\Provider\Doctrine\DoctrineProvider;
use DH\Auditor\Tests\Provider\Doctrine\Fixtures\Entity\Standard\Blog\Post;
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\HttpKernel\Kernel;

class CreatePostCommand extends Command
{
protected static $defaultName = 'app:post:create';
private DoctrineProvider $doctrineProvider;

public function __construct(DoctrineProvider $doctrineProvider)
{
parent::__construct(self::$defaultName);
$this->doctrineProvider = $doctrineProvider;
}

protected function execute(InputInterface $input, OutputInterface $output): int
{
$io = new SymfonyStyle($input, $output);

$io->write('Creating a new post');

$post = new Post();
$post
->setTitle('Blameable post')
->setBody('yet another post')
->setCreatedAt(new DateTimeImmutable('2020-01-17 22:17:34'))
;

$this->doctrineProvider->getAuditingServiceForEntity(Post::class)->getEntityManager()->persist($post);
$this->doctrineProvider->getAuditingServiceForEntity(Post::class)->getEntityManager()->flush();

// Symfony 4 compatibility
if (Kernel::MAJOR_VERSION >= 5) {
return self::SUCCESS;
}

return 0;
}
}
2 changes: 2 additions & 0 deletions tests/App/Kernel.php
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ protected function configureContainer(ContainerBuilder $container, LoaderInterfa
$container->setParameter('container.dumper.inline_factories', true);

$confDir = $this->getProjectDir().'/config';
$loader->load($confDir.'/services'.self::CONFIG_EXTS, 'glob');
$loader->load($confDir.'/{packages}/*'.self::CONFIG_EXTS, 'glob');
$loader->load($confDir.'/{packages}/sf6/*'.self::CONFIG_EXTS, 'glob');
}
Expand Down Expand Up @@ -81,6 +82,7 @@ protected function configureContainer(ContainerBuilder $container, LoaderInterfa
$container->setParameter('container.dumper.inline_factories', true);

$confDir = $this->getProjectDir().'/config';
$loader->load($confDir.'/services'.self::CONFIG_EXTS, 'glob');
$loader->load($confDir.'/{packages}/*'.self::CONFIG_EXTS, 'glob');
$loader->load($confDir.'/{packages}/sf4_5/*'.self::CONFIG_EXTS, 'glob');
}
Expand Down
6 changes: 6 additions & 0 deletions tests/App/config/services.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
services:
_defaults:
autowire: true
autoconfigure: true

DH\AuditorBundle\Tests\App\Command\CreatePostCommand:
78 changes: 78 additions & 0 deletions tests/Console/ConsoleUserProviderTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
<?php

declare(strict_types=1);

namespace DH\AuditorBundle\Tests\User;

use DH\Auditor\Provider\Doctrine\DoctrineProvider;
use DH\Auditor\Tests\Provider\Doctrine\Fixtures\Entity\Standard\Blog\Post;
use DH\Auditor\Tests\Provider\Doctrine\Traits\ReaderTrait;
use DH\Auditor\Tests\Provider\Doctrine\Traits\Schema\BlogSchemaSetupTrait;
use DH\AuditorBundle\DHAuditorBundle;
use Symfony\Bundle\FrameworkBundle\Console\Application;
use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase;
use Symfony\Component\Console\Tester\ApplicationTester;
use Symfony\Component\HttpKernel\Kernel;

/**
* @internal
*
* @small
*/
final class ConsoleUserProviderTest extends KernelTestCase
{
use BlogSchemaSetupTrait;
use ReaderTrait;

private DoctrineProvider $provider;

protected function setUp(): void
{
parent::setUp();
self::bootKernel();

// provider with 1 em for both storage and auditing
$this->createAndInitDoctrineProvider();

// declare audited entites
$this->configureEntities();

// setup entity and audit schemas
$this->setupEntitySchemas();
$this->setupAuditSchemas();
}

public function testBlameUser(): void
{
$auditingServices = [
Post::class => $this->provider->getAuditingServiceForEntity(Post::class),
];

$kernel = self::bootKernel();
$application = new Application($kernel);
$application->setAutoExit(false);
$tester = new ApplicationTester($application);

$tester->run(['app:post:create']);

if (Kernel::MAJOR_VERSION >= 5) {
$tester->assertCommandIsSuccessful('Expect it to run');
}

$this->flushAll($auditingServices);
// get history
$entries = $this->createReader()->createQuery(Post::class)->execute();
self::assertSame('app:post:create', $entries[0]->getUsername());
self::assertSame('command', $entries[0]->getUserId());
}

protected function getBundleClass()
{
return DHAuditorBundle::class;
}

private function createAndInitDoctrineProvider(): void
{
$this->provider = self::$container->get(DoctrineProvider::class);
}
}
4 changes: 4 additions & 0 deletions tests/DHAuditorBundleTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
use DH\Auditor\Provider\Doctrine\Persistence\Reader\Reader;
use DH\AuditorBundle\Controller\ViewerController;
use DH\AuditorBundle\DHAuditorBundle;
use DH\AuditorBundle\Event\ConsoleEventSubscriber;
use DH\AuditorBundle\Twig\Extension\TwigExtension;
use Doctrine\Bundle\DoctrineBundle\DoctrineBundle;
use Nyholm\BundleTest\BaseBundleTestCase;
Expand Down Expand Up @@ -81,6 +82,9 @@ public function testInitBundle(): void

self::assertTrue($container->has(\DH\AuditorBundle\Twig\Extension\TwigExtension::class));
self::assertInstanceOf(TwigExtension::class, $container->get(\DH\AuditorBundle\Twig\Extension\TwigExtension::class));

self::assertTrue($container->has(\DH\AuditorBundle\Event\ConsoleEventSubscriber::class));
self::assertInstanceOf(ConsoleEventSubscriber::class, $container->get(\DH\AuditorBundle\Event\ConsoleEventSubscriber::class));
}

protected function getBundleClass()
Expand Down

0 comments on commit 41512ce

Please sign in to comment.