From 5ef9b8016c4d9e297b481ce7e7f6b98656155578 Mon Sep 17 00:00:00 2001 From: samizdam Date: Thu, 16 May 2024 02:01:15 +0300 Subject: [PATCH 1/6] Up php versions to actual, remove eol --- .github/workflows/ci.yml | 7 ++++--- CHANGELOG.md | 3 +++ Dockerfile | 2 +- composer.json | 4 ++-- 4 files changed, 10 insertions(+), 6 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 6770b96..9f3946e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -9,11 +9,12 @@ jobs: matrix: experimental: [false] php: - - 7.3 - - 7.4 - 8.0 + - 8.1 + - 8.2 + - 8.3 include: - - php: 8.1 + - php: 8.4 prefer: stable experimental: true prefer: diff --git a/CHANGELOG.md b/CHANGELOG.md index 855926a..b1159ee 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,9 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ## [Unreleased] +### Changed +- Test with new php versions, drop 7.x support + ## [3.1.1] - 2021-09-02 ### Changed - Support all versions of psr/log and psr/container diff --git a/Dockerfile b/Dockerfile index 8c62c34..33dd8cf 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM php:8.0-cli +FROM php:8.3-cli RUN apt-get update \ && apt-get install -y \ diff --git a/composer.json b/composer.json index d59e666..ed611f4 100644 --- a/composer.json +++ b/composer.json @@ -5,7 +5,7 @@ "prefer-stable": true, "config": { "platform": { - "php": "7.4" + "php": "8.3" } }, "require-dev": { @@ -21,7 +21,7 @@ "require": { "psr/log": "^1|^2|^3", "psr/container": "^1|^2", - "php": "^7.3|^8.0" + "php": "^8.0" }, "provide": { "psr/container-implementation": "^1|^2" From 0f99bd3b10fd3a8bdd94e285710089125260d037 Mon Sep 17 00:00:00 2001 From: samizdam Date: Thu, 16 May 2024 02:07:14 +0300 Subject: [PATCH 2/6] Migrate phpunit config file --- phpunit.xml.dist | 30 ++++++++++++------------------ 1 file changed, 12 insertions(+), 18 deletions(-) diff --git a/phpunit.xml.dist b/phpunit.xml.dist index f6aad59..4ab5efc 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -1,12 +1,15 @@ - + + + + src/ + + + + + + + @@ -15,14 +18,5 @@ ./tests - - - src/ - - - - - - - + From e296b6fbb7d7062c7ce1570230ef542eb8383ea6 Mon Sep 17 00:00:00 2001 From: samizdam Date: Thu, 16 May 2024 02:39:31 +0300 Subject: [PATCH 3/6] Drart logger mapping support --- CHANGELOG.md | 3 +++ src/Injector.php | 30 ++++++++++++++++++++--- src/InjectorBuilder.php | 11 ++++++++- tests/Fixture/AnotherLoggerAwareClass.php | 22 +++++++++++++++++ tests/InjectorBuilderTest.php | 9 +++++++ tests/InjectorTest.php | 22 +++++++++++++++++ 6 files changed, 93 insertions(+), 4 deletions(-) create mode 100644 tests/Fixture/AnotherLoggerAwareClass.php diff --git a/CHANGELOG.md b/CHANGELOG.md index b1159ee..219649c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,9 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ## [Unreleased] +### Added +- Logger mapping configuration. + ### Changed - Test with new php versions, drop 7.x support diff --git a/src/Injector.php b/src/Injector.php index 956a33a..8656bfe 100644 --- a/src/Injector.php +++ b/src/Injector.php @@ -27,6 +27,8 @@ class Injector implements ContainerInterface private $enableLoggerAwareInjection = false; + private array $loggersMap = []; + public function __construct(LoggerInterface $logger = null) { $this->loggerHelper = new LoggerHelper($logger ?: new NullLogger()); @@ -82,8 +84,14 @@ public function createInstance($class) $instance = new $class(...$constructorParams); - if ($instance instanceof LoggerAwareInterface && $this->enableLoggerAwareInjection) { - $instance->setLogger($this->getService(LoggerInterface::class)); + if ($this->isLoggerInjectionRequired($instance)) { + if(array_key_exists($class, $this->loggersMap)) { + $logger = $this->loggersMap[$class]; + } else { + $logger = $this->getService(LoggerInterface::class); + } + + $instance->setLogger($logger); } return $instance; @@ -202,5 +210,21 @@ public function useIdAsTypeName(bool $useIdAsTypeName = true) public function enableLoggerAwareInjection(bool $enable = true) { $this->enableLoggerAwareInjection = $enable; - }} + } + + public function getLoggersMap(): array + { + return $this->loggersMap; + } + + public function setLoggersMap(array $map) + { + $this->loggersMap = $map; + } + + private function isLoggerInjectionRequired(mixed $instance): bool + { + return $instance instanceof LoggerAwareInterface && $this->enableLoggerAwareInjection; + } +} diff --git a/src/InjectorBuilder.php b/src/InjectorBuilder.php index 439f3fc..c1f22dc 100644 --- a/src/InjectorBuilder.php +++ b/src/InjectorBuilder.php @@ -10,6 +10,7 @@ class InjectorBuilder public const INSTANCES_KEY = 'instances'; public const REGISTER_KEY = 'register'; public const CALLABLE_KEY = 'callable'; + public const LOGGERS_KEY = 'loggers'; /** * @var string */ @@ -23,15 +24,19 @@ class InjectorBuilder */ private $callableKey; + private string $loggersKey; + public function __construct( string $instancesKey = self::INSTANCES_KEY, string $registerKey = self::REGISTER_KEY, - string $callableKey = self::CALLABLE_KEY + string $callableKey = self::CALLABLE_KEY, + string $loggersKey = self::LOGGERS_KEY, ) { $this->instancesKey = $instancesKey; $this->registerKey = $registerKey; $this->callableKey = $callableKey; + $this->loggersKey = $loggersKey; } public function buildFromArray(array $components): Injector @@ -40,6 +45,10 @@ public function buildFromArray(array $components): Injector $injector->merge($components, $this->instancesKey, $this->registerKey, $this->callableKey); + if (isset($components[$this->loggersKey])) { + $injector->setLoggersMap($components[$this->loggersKey]); + } + return $injector; } } diff --git a/tests/Fixture/AnotherLoggerAwareClass.php b/tests/Fixture/AnotherLoggerAwareClass.php new file mode 100644 index 0000000..9b10db5 --- /dev/null +++ b/tests/Fixture/AnotherLoggerAwareClass.php @@ -0,0 +1,22 @@ + + */ +class AnotherLoggerAwareClass implements LoggerAwareInterface +{ + + use LoggerAwareTrait; + + public function getLogger(): LoggerInterface + { + return $this->logger; + } +} + diff --git a/tests/InjectorBuilderTest.php b/tests/InjectorBuilderTest.php index 5699445..eb5ebf2 100644 --- a/tests/InjectorBuilderTest.php +++ b/tests/InjectorBuilderTest.php @@ -2,11 +2,14 @@ namespace FreeElephants\DI; +use Fixture\AnotherLoggerAwareClass; use Fixture\AnotherService; use Fixture\Bar; use Fixture\ClassWithDefaultConstructorArgValue; use Fixture\Foo; +use Fixture\LoggerAwareClass; use Psr\Container\ContainerInterface; +use Psr\Log\NullLogger; /** * @author samizdam @@ -40,11 +43,17 @@ function (ContainerInterface $container, int $value): ClassWithDefaultConstructo return $bar2; }, ], + 'loggers' => [ + LoggerAwareClass::class => new NullLogger(), + AnotherLoggerAwareClass::class => new NullLogger(), + ], ]); $this->assertSame($bar2, $injector->getService(Bar::class)); $this->assertInstanceOf(Foo::class, $injector->createInstance(Foo::class)); $this->assertSame($anotherServiceInstance, $injector->getService(AnotherService::class)); $this->assertSame(9000, $injector->get(ClassWithDefaultConstructorArgValue::class)->getValue()); + + $this->assertCount(2, $injector->getLoggersMap()); } } diff --git a/tests/InjectorTest.php b/tests/InjectorTest.php index 142c9e5..34c19df 100644 --- a/tests/InjectorTest.php +++ b/tests/InjectorTest.php @@ -2,6 +2,7 @@ namespace FreeElephants\DI; +use Fixture\AnotherLoggerAwareClass; use Fixture\AnotherService; use Fixture\AnotherServiceInterface; use Fixture\Bar; @@ -227,6 +228,27 @@ public function testLoggerInjection() $this->assertSame($logger, $loggerAware->getLogger()); } + public function testLoggerMap() + { + $logger = new NullLogger(); + $anotherLogger = new NullLogger(); + + $injector = new Injector(); + $injector->allowInstantiateNotRegisteredTypes(true); + $injector->enableLoggerAwareInjection(); + $injector->setLoggersMap([ + LoggerAwareClass::class => $logger, + AnotherLoggerAwareClass::class => $anotherLogger, + ]); + + /** @var LoggerAwareClass $loggerAwareInstance */ + $loggerAwareInstance = $injector->get(LoggerAwareClass::class); + $this->assertSame($logger, $loggerAwareInstance->getLogger()); + /** @var AnotherLoggerAwareClass $anotherLoggerAwareInstance */ + $anotherLoggerAwareInstance = $injector->get(AnotherLoggerAwareClass::class); + $this->assertSame($anotherLogger, $anotherLoggerAwareInstance->getLogger()); + } + public function testHandleInstantiateInterfaceError() { $injector = new Injector(); From 53432711bf5cea34dec745b4eedaf208939c48a8 Mon Sep 17 00:00:00 2001 From: samizdam Date: Thu, 16 May 2024 02:45:40 +0300 Subject: [PATCH 4/6] Update readme --- CHANGELOG.md | 2 +- README.md | 17 ++++++++++++++++- 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 219649c..2353a09 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,7 +7,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ## [Unreleased] ### Added -- Logger mapping configuration. +- Logger mapping configuration ### Changed - Test with new php versions, drop 7.x support diff --git a/README.md b/README.md index 59e8212..57ffba1 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,7 @@ Framework-agnostic Dependency Injection tool and PSR-11 implementation provider. ## Requirements -PHP >=7.3|8.0 +PHP >=8.0 ## Installation @@ -63,6 +63,12 @@ return [ 500, ], ], + 'loggers' => [ + // For suitable logger injections use map, where keys are your services, that implement LoggerAwareInterface + // and value is logger instances + LoggerAwareClass::class => $logger, + AnotherLoggerAwareClass::class => $anotherLogger, + ], ]; ``` @@ -83,15 +89,24 @@ $di = (new \FreeElephants\DI\InjectorBuilder)->buildFromArray($components); ## Options: ### `allowNullableConstructorArgs` + Default value is `false`. ### `allowInstantiateNotRegisteredTypes` + Default value is `false`. When you set it `true`, you can register only specific interfaces instances. All final typed dependency will be lazy-instantiated by chain! ### `useIdAsTypeName` + Default value is `true`. +### `enableLoggerAwareInjection` + +Default value is `false`. + +Allow to set LoggerInterface into LoggerAwareInterface instances after constructing, or use loggers map if type present. + ## Conception ## [In Russian] Простейшее внедрение зависимостей через конструктор для PHP From 53cadcd47db5752efaeff711ff2962ce1a5190e4 Mon Sep 17 00:00:00 2001 From: samizdam Date: Thu, 16 May 2024 02:56:35 +0300 Subject: [PATCH 5/6] Add types --- src/CallableBeanContainer.php | 9 +++------ src/EnvAwareConfigLoader.php | 4 ++-- src/Injector.php | 34 +++++++++++++++++----------------- src/InjectorBuilder.php | 15 +++------------ src/LoggerHelper.php | 12 ++++++------ 5 files changed, 31 insertions(+), 43 deletions(-) diff --git a/src/CallableBeanContainer.php b/src/CallableBeanContainer.php index 227a994..42208a9 100644 --- a/src/CallableBeanContainer.php +++ b/src/CallableBeanContainer.php @@ -8,13 +8,10 @@ class CallableBeanContainer { /** - * @var callable|mixed|null + * @var callable|mixed */ - private $function; - /** - * @var array - */ - private $args; + private mixed $function; + private array $args; public function __construct(string $interface, $callable, ContainerInterface $container) { diff --git a/src/EnvAwareConfigLoader.php b/src/EnvAwareConfigLoader.php index 60f8a71..9bfb0c0 100644 --- a/src/EnvAwareConfigLoader.php +++ b/src/EnvAwareConfigLoader.php @@ -5,8 +5,8 @@ class EnvAwareConfigLoader implements ConfigLoaderInterface { private const DEFAULT_ENV_VAR_NAME = 'ENV'; - private $envVariableName; - private $configBasePath; + private string $envVariableName; + private string $configBasePath; public function __construct(string $configBasePath, string $envVariableName = self::DEFAULT_ENV_VAR_NAME) { diff --git a/src/Injector.php b/src/Injector.php index 8656bfe..4478b6f 100644 --- a/src/Injector.php +++ b/src/Injector.php @@ -15,17 +15,17 @@ class Injector implements ContainerInterface { - private $serviceMap = []; + private array $serviceMap = []; - private $loggerHelper; + private LoggerHelper $loggerHelper; - private $allowNullableConstructorArgs = false; + private bool $allowNullableConstructorArgs = false; - private $allowInstantiateNotRegisteredTypes = false; + private bool $allowInstantiateNotRegisteredTypes = false; - private $useIdAsTypeName = true; + private bool $useIdAsTypeName = true; - private $enableLoggerAwareInjection = false; + private bool $enableLoggerAwareInjection = false; private array $loggersMap = []; @@ -39,7 +39,7 @@ public function getLoggerHelper(): LoggerHelper return $this->loggerHelper; } - public function setService(string $typeName, $service) + public function setService(string $typeName, $service): void { if ($this->useIdAsTypeName && false === $service instanceof $typeName) { $this->loggerHelper->logNotMatchedTypeInstance($typeName, $service); @@ -53,7 +53,7 @@ public function setService(string $typeName, $service) $this->loggerHelper->logServiceSetting($typeName, $service); } - public function createInstance($class) + public function createInstance($class): object { $reflectedClass = new \ReflectionClass($class); if ($reflectedClass->isAbstract() || $reflectedClass->isInterface()) { @@ -97,7 +97,7 @@ public function createInstance($class) return $instance; } - public function registerService($implementation, string $interface = null) + public function registerService($implementation, string $interface = null): void { $interface = $interface ?: $implementation; if (isset($this->serviceMap[$interface])) { @@ -108,7 +108,7 @@ public function registerService($implementation, string $interface = null) $this->loggerHelper->logServiceRegistration($implementation, $interface); } - public function getService(string $type) + public function getService(string $type): object { if (!array_key_exists($type, $this->serviceMap)) { if ($this->allowInstantiateNotRegisteredTypes) { @@ -143,7 +143,7 @@ public function merge( string $instancesKey = InjectorBuilder::INSTANCES_KEY, string $registerKey = InjectorBuilder::REGISTER_KEY, string $callableKey = InjectorBuilder::CALLABLE_KEY - ) + ): void { $beansInstances = $components[$instancesKey] ?? []; foreach ($beansInstances as $interface => $instance) { @@ -167,17 +167,17 @@ public function merge( } } - public function allowNullableConstructorArgs(bool $allow) + public function allowNullableConstructorArgs(bool $allow): void { $this->allowNullableConstructorArgs = $allow; } - public function allowInstantiateNotRegisteredTypes(bool $allowInstantiateNotRegisteredTypes) + public function allowInstantiateNotRegisteredTypes(bool $allowInstantiateNotRegisteredTypes): void { $this->allowInstantiateNotRegisteredTypes = $allowInstantiateNotRegisteredTypes; } - public function registerItSelf(bool $asPsrContainer = true) + public function registerItSelf(bool $asPsrContainer = true): void { $this->setService(Injector::class, $this); @@ -202,12 +202,12 @@ public function has($id): bool return $this->hasImplementation($id); } - public function useIdAsTypeName(bool $useIdAsTypeName = true) + public function useIdAsTypeName(bool $useIdAsTypeName = true): void { $this->useIdAsTypeName = $useIdAsTypeName; } - public function enableLoggerAwareInjection(bool $enable = true) + public function enableLoggerAwareInjection(bool $enable = true): void { $this->enableLoggerAwareInjection = $enable; } @@ -217,7 +217,7 @@ public function getLoggersMap(): array return $this->loggersMap; } - public function setLoggersMap(array $map) + public function setLoggersMap(array $map): void { $this->loggersMap = $map; } diff --git a/src/InjectorBuilder.php b/src/InjectorBuilder.php index c1f22dc..c2dbb94 100644 --- a/src/InjectorBuilder.php +++ b/src/InjectorBuilder.php @@ -11,19 +11,10 @@ class InjectorBuilder public const REGISTER_KEY = 'register'; public const CALLABLE_KEY = 'callable'; public const LOGGERS_KEY = 'loggers'; - /** - * @var string - */ - private $instancesKey; - /** - * @var string - */ - private $registerKey; - /** - * @var string - */ - private $callableKey; + private string $instancesKey; + private string $registerKey; + private string $callableKey; private string $loggersKey; public function __construct( diff --git a/src/LoggerHelper.php b/src/LoggerHelper.php index 6909da8..82bf314 100644 --- a/src/LoggerHelper.php +++ b/src/LoggerHelper.php @@ -19,7 +19,7 @@ public function __construct(LoggerInterface $logger) $this->setLogger($logger); } - public function logRequestNotDeterminedService(string $interface) + public function logRequestNotDeterminedService(string $interface): void { $msg = 'Requested service with type ' . $interface . ' is not set. Exception will be thrown. '; $context = [ @@ -28,7 +28,7 @@ public function logRequestNotDeterminedService(string $interface) $this->logger->critical($msg, $context); } - public function logLazyLoading(string $interface, $service) + public function logLazyLoading(string $interface, $service): void { $debugMsg = 'Set service type ' . $interface . ' instance by lazy load. '; $context = [ @@ -38,7 +38,7 @@ public function logLazyLoading(string $interface, $service) $this->logger->debug($debugMsg, $context); } - public function logServiceRegistration($implementation, string $interface) + public function logServiceRegistration($implementation, string $interface): void { $msg = 'Service with type ' . $interface . ' and implementation ' . $this->stringifyImplementation($implementation) . ' register. '; $context = [ @@ -48,7 +48,7 @@ public function logServiceRegistration($implementation, string $interface) $this->logger->debug($msg, $context); } - public function logNotMatchedTypeInstance(string $typeName, $instance) + public function logNotMatchedTypeInstance(string $typeName, $instance): void { $context = [ 'typeName' => $typeName, @@ -69,7 +69,7 @@ public function logServiceInstanceReplacing(string $typeName, $service, $previou return [$debugMsg, $context]; } - public function logRegisterServiceReplacing($implementation, string $interface, $oldImplementation) + public function logRegisterServiceReplacing($implementation, string $interface, $oldImplementation): void { $msg = 'Replace registered service type ' . $interface . ' with another. '; $context = [ @@ -80,7 +80,7 @@ public function logRegisterServiceReplacing($implementation, string $interface, $this->logger->debug($msg, $context); } - public function logServiceSetting(string $typeName, $service) + public function logServiceSetting(string $typeName, $service): void { $debugMsg = 'Instance for service type ' . $typeName . ' was set. '; $context = [ From 07092435a2c389fe80a8b62ec9479d6346d9e793 Mon Sep 17 00:00:00 2001 From: samizdam Date: Thu, 16 May 2024 02:58:34 +0300 Subject: [PATCH 6/6] Update github actions --- .github/workflows/ci.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 9f3946e..7f26157 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -27,7 +27,7 @@ jobs: steps: - name: Checkout Code - uses: actions/checkout@v2 + uses: actions/checkout@v4 - name: Install PHP uses: shivammathur/setup-php@v2 @@ -42,7 +42,7 @@ jobs: - name: Cache Composer packages id: composer-cache - uses: actions/cache@v2 + uses: actions/cache@v4 with: path: vendor key: ${{ runner.os }}-php-${{ matrix.php }}-composer-${{ hashFiles('**/composer.json') }}-${{ matrix.prefer }}-