Use container for dependencies

This looks more complicated but removes a lot of hard coded class connections
and will make injecting config easier.
This commit is contained in:
James Gilliland 2022-03-05 13:57:22 -06:00
parent e8724f4513
commit 12211289bf
11 changed files with 156 additions and 37 deletions

View file

@ -3,12 +3,8 @@
require __DIR__ . '/../vendor/autoload.php';
use Pfatt\Commands\Monitor;
use Pfatt\Commands\Startup;
use Symfony\Component\Console\Application;
use Pfatt\PfattKernel;
$application = new Application();
$application->add(new Monitor());
$application->add(new Startup());
$application->run();
(new PfattKernel())
->create()
->run();

View file

@ -1,6 +1,7 @@
{
"output" : "build/pfatt.phar",
"files": [
"bin/pfatt"
"bin/pfatt",
"cache/container.php"
]
}

2
cache/.gitignore vendored Normal file
View file

@ -0,0 +1,2 @@
*
!.gitignore

View file

@ -18,6 +18,7 @@
"php": ">=7.4",
"psr/log": "^1.1",
"symfony/console": "^5.4",
"symfony/dependency-injection": "^5.4",
"symfony/process": "^5.4"
},
"require-dev": {

View file

@ -4,12 +4,11 @@ declare(strict_types=1);
namespace Pfatt\Commands;
use Pfatt\Config;
use Pfatt\Logger;
use Pfatt\NgController;
use Pfatt\Service\Config;
use Pfatt\Service\Logger;
use Pfatt\Service\NgController;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Logger\ConsoleLogger;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Process\Process;
@ -21,12 +20,15 @@ final class Monitor extends Command
protected Logger $logger;
protected NgController $ngControl;
protected function configure(): void
{
// @todo Inject these. Maybe with a factory or container.
$this->config = new Config('', '', '');
$this->logger = new Logger('pfatt-5268AC');
$this->ngControl = new NgController($this->logger);
public function __construct(
Config $config,
Logger $logger,
NgController $ngControl
) {
parent::__construct('monitor');
$this->config = $config;
$this->logger = $logger;
$this->ngControl = $ngControl;
}
/**

View file

@ -4,9 +4,9 @@ declare(strict_types=1);
namespace Pfatt\Commands;
use Pfatt\Config;
use Pfatt\Logger;
use Pfatt\NgController;
use Pfatt\Service\Config;
use Pfatt\Service\Logger;
use Pfatt\Service\NgController;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
@ -20,20 +20,26 @@ final class Startup extends Command
protected Logger $logger;
protected NgController $ngControl;
protected function configure(): void
{
// @todo Inject these. Maybe with a factory or container.
$this->config = new Config('', '', '');
$this->logger = new Logger('pfatt');
$this->ngControl = new NgController($this->logger);
public function __construct(
Config $config,
Logger $logger,
NgController $ngControl
) {
parent::__construct('startup');
$this->config = $config;
$this->logger = $logger;
$this->ngControl = $ngControl;
}
/**
* {@inheritDoc}
*/
protected function execute(InputInterface $input, OutputInterface $output): int
{
protected function execute(
InputInterface $input,
OutputInterface $output
): int {
$this->logger->setOutput($output);
switch ($this->getVeriant()) {
case 'opnsense':
$kldload = function (string $mod): Process {
@ -53,7 +59,11 @@ final class Startup extends Command
case 'pfsense':
default:
$attach = function (string $interface): Process {
return new Process(['/usr/local/bin/php', '-r', '"pfSense_ngctl_attach(\'.\', \'' . $interface . '\';"']);
return new Process([
'/usr/local/bin/php',
'-r',
'"pfSense_ngctl_attach(\'.\', \'' . $interface . '\';"'
]);
};
$this->logger->info('attaching interfaces to ng_ether...');
@ -73,7 +83,9 @@ final class Startup extends Command
/**
* @return string
*/
private function getVeriant(): string {
private function getVeriant(): string
{
// @todo detect the variant to trigger different behaviors.
return 'opnsense';
}
}

11
src/PfattApplication.php Normal file
View file

@ -0,0 +1,11 @@
<?php
declare(strict_types=1);
namespace Pfatt;
use Symfony\Component\Console\Application;
final class PfattApplication extends Application
{
}

94
src/PfattKernel.php Normal file
View file

@ -0,0 +1,94 @@
<?php
declare(strict_types=1);
namespace Pfatt;
use Pfatt\Commands\Monitor;
use Pfatt\Commands\Startup;
use Pfatt\Service\Config;
use Pfatt\Service\Logger;
use Pfatt\Service\NgController;
use Psr\Log\LoggerInterface;
use Symfony\Component\Console\Application;
use Symfony\Component\Console\CommandLoader\ContainerCommandLoader;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\DependencyInjection\Dumper\PhpDumper;
use Symfony\Component\DependencyInjection\Reference;
final class PfattKernel
{
/**
* @var string[]
*/
private $commands = [
'monitor' => Monitor::class,
'startup' => Startup::class,
];
public function create(): Application
{
// Lazy load command with container
$container = $this->getContainer();
/** @var \Pfatt\PfattApplication $application */
$application = $container->get(PfattApplication::class);
return $application;
}
public function getContainer(): ContainerInterface
{
$file = __DIR__ . '/../cache/container.php';
if (!file_exists($file)) {
$containerBuilder = new ContainerBuilder();
$containerBuilder->register(Logger::class, Logger::class)
->setPublic(true);
$containerBuilder->setAlias(LoggerInterface::class, Logger::class);
$containerBuilder->register('logger-5268', Logger::class)
->setPublic(true)
->setArgument('$channel', 'pfatt-5268AC');
$containerBuilder->register(Config::class, Config::class)
->setPublic(true)
->setArguments(['', '', '']);
$containerBuilder->autowire(NgController::class, NgController::class)
->setPublic(true);
$containerBuilder->autowire(Monitor::class, Monitor::class)
->setPublic(true)
->setArgument(Logger::class, new Reference('logger-5268'));
$containerBuilder->autowire(Startup::class, Startup::class)
->setPublic(true);
$containerBuilder->register(ContainerCommandLoader::class, ContainerCommandLoader::class)
->setArguments([
new Reference('service_container'),
$this->commands
])
->setPublic(true);
$containerBuilder->register(PfattApplication::class, PfattApplication::class)
->setArguments(['PfATT'])
->addMethodCall('setCommandLoader', [new Reference(ContainerCommandLoader::class)])
->setPublic(true);
$containerBuilder->compile();
$dumper = new PhpDumper($containerBuilder);
/**
* This will always be a string because of the default options.
* @psalm-suppress MixedArgumentTypeCoercion
*/
file_put_contents($file, $dumper->dump());
}
require_once $file;
/**
* Tell static analysis of this dynamic class.
* @var \Symfony\Component\DependencyInjection\ContainerInterface $container
* @psalm-suppress UndefinedClass
* @phpstan-ignore-next-line
*/
$container = new \ProjectServiceContainer();
return $container;
}
}

View file

@ -2,7 +2,7 @@
declare(strict_types=1);
namespace Pfatt;
namespace Pfatt\Service;
/**
* Config wrapper.

View file

@ -2,7 +2,7 @@
declare(strict_types=1);
namespace Pfatt;
namespace Pfatt\Service;
use Psr\Log\AbstractLogger;
use Psr\Log\LoggerInterface;
@ -20,7 +20,7 @@ class Logger extends AbstractLogger
*/
private ?LoggerInterface $logger;
public function __construct(string $channel, LoggerInterface $logger = null)
public function __construct(string $channel = 'pfatt', LoggerInterface $logger = null)
{
$this->channel = $channel;
$this->logger = $logger;

View file

@ -2,7 +2,7 @@
declare(strict_types=1);
namespace Pfatt;
namespace Pfatt\Service;
use Psr\Log\LoggerAwareInterface;
use Psr\Log\LoggerInterface;