diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml deleted file mode 100644 index c4253bf..0000000 --- a/.github/workflows/main.yml +++ /dev/null @@ -1,101 +0,0 @@ -name: Testing Shopware 6.5 - -on: - push: - branches: - - dev - - main65 - pull_request: - branches: - - dev - - main65 - workflow_dispatch: - -env: - MODULE_NAME: MuckiLogPlugin - COMPOSER_NAME: muckiware/log-plugin - TEST_DATABASE_URL: "mysql://root:root@127.0.0.1:3306/db_test" - -jobs: - ci-current: - name: SW ${{ matrix.shopware-versions }}, PHP ${{ matrix.php-versions }}, MySQL ${{ matrix.mysql-versions }} - runs-on: ubuntu-latest - strategy: - max-parallel: 15 - fail-fast: false - matrix: - php-versions: [ '8.2' ] - mysql-versions: [ '8.0' ] - shopware-versions: [ 'v6.5.3.0' ] - services: - mysql: - image: mysql:${{ matrix.mysql-versions }} - env: - MYSQL_DATABASE: db_test - MYSQL_ROOT_PASSWORD: root - ports: - - 3306:3306 - - steps: - - name: Install PHP - uses: shivammathur/setup-php@master - with: - php-version: ${{ matrix.php-versions }} - extensions: mbstring, xdebug, curl, dom, fileinfo, gd, iconv, intl, json, xml, mbstring, pdo, phar, zip, sodium, pdo_mysql - tools: composer:2.7.7 - - - name: "Check PHP Version" - run: php -v - - - name: "Check Composer Version" - run: composer -V - - - name: "Check PHP Extensions" - run: php -m - - - name: "checkout Shopware" - uses: actions/checkout@v3 - with: - repository: shopware/production - ref: ${{ matrix.shopware-versions }} - - - name: "Checkout ${{ env.COMPOSER_NAME }}" - uses: actions/checkout@v3 - with: - path: custom/plugins/${{ env.MODULE_NAME }} - - - name: "Get composer cache directory" - id: composer-cache - run: echo "dir=$(composer config cache-files-dir)" >> $GITHUB_OUTPUT - - - name: "Cache Composer dependencies" - uses: actions/cache@v3 - with: - path: ${{ steps.composer-cache.outputs.dir }} - key: ${{ matrix.operating-system }}-${{ matrix.php-versions }}-${{ matrix.shopware-versions }}-${{ hashFiles('**/composer.lock') }} - - - name: "Install Shopware dependencies" - # Install Shopware with --no-dev to prevent that dev-tools of the module got in conflict with the tools of shopware - run: | - composer req shopware/administration:${{ matrix.shopware-versions }} shopware/core:${{ matrix.shopware-versions }} shopware/elasticsearch:${{ matrix.shopware-versions }} shopware/storefront:${{ matrix.shopware-versions }} --no-update - composer install --no-dev - - - name: "Install DEV-Tools" - working-directory: custom/plugins/${{ env.MODULE_NAME }} - run: | - composer remove shopware/* --no-update - composer install - - - name: "Install code-Tools" - run: composer req phpunit/phpunit:^9.5 phpstan/phpstan - - - name: "Install Shopware" - run: | - echo APP_ENV=dev >> .env - echo APP_URL=http://localhost >> .env - echo DATABASE_URL=${{ env.TEST_DATABASE_URL }} >> .env - echo APP_SECRET=secretf0rt3st >> .env - bin/console system:install --basic-setup - - - name: "Run PHPUnit Tests" - run: ./vendor/bin/phpunit --configuration="custom/plugins/${{ env.MODULE_NAME }}" diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000..d921d74 --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,198 @@ +# MuckiLogPlugin – CLAUDE.md + +## Zweck + +`muckiware/log-plugin` (v2.4.0) ersetzt das Standard-Monolog-Logging von Shopware durch **Apache Log4php** mittels des Symfony **Decorator-Patterns**. Jede Log-Ausgabe, die in Shopware oder Plugins über `Psr\Log\LoggerInterface` erfolgt, wird automatisch abgefangen und durch Log4php geroutet — ohne Codeänderungen in anderen Plugins. + +--- + +## Decorator-Mechanismus (Kernprinzip) + +### 1. Logger-Decorator + +**Datei:** `src/Services/LoggerServiceDecorator.php` +**Interface:** implementiert `Psr\Log\LoggerInterface` + +**Registrierung in** `src/Resources/config/services.xml`: + +```xml + + + + + + +``` + +**Wie es funktioniert:** +- `decorates="Psr\Log\LoggerInterface"` weist Symfony an, diesen Service als Wrapper um den Original-Logger (Monolog) einzusetzen. +- Der Original-Monolog-Service wird als `LoggerServiceDecorator.inner` übergeben, aber **nicht mehr aufgerufen** — alle Log-Methoden (`emergency`, `alert`, `critical`, `error`, `warning`, `notice`, `info`, `debug`, `log`) delegieren stattdessen an `MuckiLogPlugin\Logging\Logger` (Log4php). +- `decoration-priority="10"` — höhere Zahl = äußerster Decorator (wird zuerst ausgeführt). + +### 2. ErrorController-Decorator + +**Datei:** `src/Storefront/Controller/ErrorControllerDecorator.php` + +```xml + +``` + +Dekoriert den Shopware `ErrorController`, um Storefront-Exceptions (außer 404) automatisch mit Log4php zu loggen und eine Flash-Message mit Error-ID anzuzeigen. + +--- + +## Log4php-Integration + +### Logging-Stack + +``` +Psr\Log\LoggerInterface (Aufruf aus beliebigem Plugin/Shopware) + └─> LoggerServiceDecorator::error/warning/info/debug(...) + └─> LoggerServiceDecorator::getLoggerSetup() → LoggerSetup DTO + └─> MuckiLogPlugin\Logging\Logger::logItem() + └─> Logconfig::checkConfigPath() — lädt/erstellt XML-Konfiguration + └─> Log4php\Logger::error/warning/info/debug() + └─> RollingFileAppender → var/log/..log +``` + +### Log-Konfiguration pro Plugin + +`Logconfig` erzeugt automatisch eine XML-Konfigurationsdatei pro Vendor/Plugin-Kombination: + +- **Pfad-Konvention:** `src/Resources/config/logconfig...xml` +- **Log-Datei:** `var/log/..log` +- Standard-Appender: `LoggerAppenderRollingFile` mit konfigurierbarer Dateigröße, Backup-Anzahl und Komprimierung. + +--- + +## Context-Array-Konvention + +Damit ein Log-Eintrag der richtigen Log-Datei zugeordnet wird, muss der Context-Array eine bestimmte Struktur haben: + +```php +$this->logger->error('Fehlermeldung', [ + 'vendorName', // $context[0] → Vendor-Ordner / Log-Kategorie + 'pluginName', // $context[1] → Plugin-Name / Dateiname + // optional: + [ + 'setup' => [ + 'notificationEmail' => true, + 'notificationEmailReceiver' => 'admin@example.com', + 'notificationEmailSender' => 'shop@example.com', + 'notificationEmailTemplateId' => '', + ] + ] +]); +``` + +Fehlt der Context, wird der Fallback `sw` / `dev` verwendet → `var/log/dev.sw.log`. + +--- + +## Services im Überblick + +| Service | Zweck | +|---|---| +| `LoggerServiceDecorator` | Decorator für `Psr\Log\LoggerInterface`, Einstiegspunkt für alle Logs | +| `MuckiLogPlugin\Logging\Logger` | Routing an Log4php, dispatcht Events vor/nach dem Logging | +| `Logconfig` | Verwaltet Log4php XML-Config-Dateien (erstellt sie bei Bedarf) | +| `Settings` | Liest Plugin-Konfiguration aus `SystemConfigService` | +| `LoggingEvent` | Speichert Benachrichtigungs-Events in DB-Tabelle `muwa_logging_event` | +| `SendNotification` | Versendet E-Mail-Benachrichtigungen per Log-Level | +| `Mailer` | Shopware `MailService`-Wrapper für Notification-Mails | +| `ErrorControllerDecorator` | Decorator für Storefront `ErrorController` | + +--- + +## Events + +| Event-Konstante | Wann | +|---|---| +| `LoggerEvents::CREATE_LOG_EVENT_BEFORE` (`create.log.before`) | Vor dem eigentlichen Log-Schreiben | +| `LoggerEvents::CREATE_LOG_EVENT_AFTER` (`create.log.after`) | Nach dem Log-Schreiben (inkl. DB-Speicherung) | + +Payload: `CreateLogEvent` mit `LoggerSetup`-DTO (enthält Vendor, Plugin, LogLevel, Message, Notification-Einstellungen). + +--- + +## Entities & Migrations + +| Entity | DB-Tabelle | Zweck | +|---|---|---| +| `LoggingEventEntity` | `muwa_logging_event` | Speichert Log-Einträge, für die eine E-Mail-Benachrichtigung aussteht | +| `EmailNotificationEntity` | — | E-Mail-Notification-Konfiguration | + +Migration: `src/Migration/Migration1729614227.php` + +--- + +## Plugin-Konfiguration (`config.xml`) + +Alle Keys beginnen mit `MuckiLogPlugin.config.`: + +| Key | Typ | Bedeutung | +|---|---|---| +| `active` | bool | Plugin aktiv/inaktiv | +| `level` | string | Mindest-Log-Level (`debug`, `info`, `warning`, `error`, `critical`) | +| `maxbackupindex` | int | Anzahl Rolling-Backup-Dateien (Default: 10) | +| `maxfilesize` | int | Max. Dateigröße in MB (Default: 10) | +| `logpattern` | string | Log4php Conversion-Pattern | +| `activeCompress` | bool | Backup-Logs komprimieren | +| `activeNotificationMail` | bool | E-Mail-Benachrichtigung aktiv | +| `notificationMailAddress` | string | Empfänger-Adresse | +| `notificationMailTemplateId` | uuid | Shopware E-Mail-Template | +| `notificationMailActive{Level}` | bool | Benachrichtigung je Log-Level | +| `salesChannelId` | uuid | Sales-Channel für Mails | +| `sendMailMode` | string | `eachLogLevelOneMail` (Default) | + +--- + +## Scheduled Task + +`SendNotificationLogsTask` — läuft alle 300 Sekunden, versendet ausstehende Log-Benachrichtigungen aus `muwa_logging_event`. + +--- + +## CLI-Befehle + +| Befehl | Klasse | Zweck | +|---|---|---| +| (registriert) | `Commands\Checkup` | Logger-Konfiguration prüfen | +| (registriert) | `Commands\SendNotification` | Benachrichtigungen manuell auslösen | + +--- + +## Wichtige Besonderheiten / Fallstricke + +- **Kein Monolog-Fallback**: Der Original-Monolog-Service (`.inner`) wird im Decorator gespeichert, aber **nie aufgerufen**. Wenn das Plugin deaktiviert ist (`Settings::isEnabled() === false`), wird **gar nicht** geloggt. +- **Level-Mapping**: `alert` → `WARNING`, `notice` → `INFO`, `log()` → immer `DEBUG` — Abweichung von PSR-3-Semantik beachten. +- **Context-Index-Abhängigkeit**: Der Context-Array wird per numerischem Index (`$context[0]`, `$context[1]`, `$context[2]`) ausgewertet — kein assoziativer Zugriff auf Vendor/Plugin-Namen. Bei falscher Struktur greift immer der Fallback. +- **Config-Datei-Erstellung**: Fehlt die XML-Konfiguration für eine Vendor/Plugin-Kombination, erstellt `Logconfig::_createConfigXML()` sie automatisch via DOM — erfordert Schreibrechte auf `src/Resources/config/`. +- **ErrorControllerDecorator-Bug**: `$this->originalLoggerService = $errorController;` — Property-Name ist falsch (`originalLoggerService` statt `originalErrorController`), führt aber zu keinem Laufzeitfehler, da die Property nur gesetzt, nie gelesen wird. +- **`http\Message` Import**: In `LoggerServiceDecorator` wird `use http\Message;` importiert, aber nie genutzt — toter Import. + +--- + +## Verwendung in eigenen Plugins + +```php +// services.xml + + +// PHP +$this->logger->error('Fehlermeldung', ['lightsOn', 'myPlugin']); +$this->logger->info('Info', ['lightsOn', 'myPlugin']); + +// Mit E-Mail-Benachrichtigung +$this->logger->error('Kritischer Fehler', [ + 'lightsOn', + 'myPlugin', + ['setup' => ['notificationEmail' => true]] +]); +``` + +Log-Datei landet in: `var/log/myPlugin.lightsOn.log` \ No newline at end of file diff --git a/composer.json b/composer.json index a5c96a3..ed9ceb1 100644 --- a/composer.json +++ b/composer.json @@ -24,7 +24,8 @@ } }, "require" : { - "php" : ">= 8.1" + "php" : ">= 8.2", + "shopware/core" : ">= 6.5.8.0" }, "require-dev" : { "phpstan/phpstan" : "*" diff --git a/readme.md b/readme.md index 7ab933f..f349727 100644 --- a/readme.md +++ b/readme.md @@ -110,6 +110,78 @@ $loggerContext = array( ); $this->logger->critical('Call HeaderPageletLoadedEvent with mail notification', $loggerContext); ``` +## Decorator Coverage + +MuckiLogPlugin intercepts Shopware and Symfony log calls through two complementary mechanisms. + +### 1. `Psr\Log\LoggerInterface` — via service decorator + +The primary decorator (`LoggerServiceDecorator`) wraps the default Symfony/Monolog logger. Any service +that injects the logger via the standard PSR-3 interface is automatically covered: + +```xml + +``` + +This is the recommended way to use the logger in your own plugins. + +### 2. `id="logger"` — via DI CompilerPass + +Many Shopware core services use the explicit `logger` service ID instead of the interface alias: + +```xml + +``` + +The `LoggerDecoratorCompilerPass` runs at container compile time, traverses all service definitions +and replaces every `id="logger"` reference with a reference to the `LoggerServiceDecorator` — except +for services that are transitive dependencies of the decorator itself (those would create circular +references). + +**What this means in practice:** Log calls from Shopware core services like `ProductStreamProcessor`, +`StockUpdater`, or `ElasticsearchEntitySearcher` are routed through MuckiLogPlugin automatically, +without any code changes in those services. + +### Why Monolog channel loggers (`id="monolog.logger.*"`) are not auto-decorated + +Shopware registers a dedicated Monolog logger per concern (`monolog.logger.event`, +`monolog.logger.messenger`, `monolog.logger.request`, etc.). Decorating these channels with a +service decorator is architecturally incompatible with the current plugin design: + +`LoggerServiceDecorator` → `MuckiLogPlugin\Logging\Logger` → `LoggingEvent` +→ `muwa_logging_event.repository` → Shopware DAL → most Shopware services +→ those Shopware services use channel loggers → **circular reference** + +The correct approach for intercepting channel loggers is a **Monolog Handler** (a handler is a leaf +node in the DI graph and does not create cycles). This is documented as a future improvement. + +### Context array convention + +The decorator reads the PSR-3 context array to determine which log file to write to: + +```php +// Writes to var/log/myplugin.myvendor.log +$this->logger->error('Something failed', ['myvendor', 'myplugin']); + +// Writes to var/log/dev.sw.log (default fallback) +$this->logger->error('Something failed', []); + +// Writes with email notification +$this->logger->error('Critical failure', [ + 'myvendor', + 'myplugin', + ['setup' => [ + 'notificationEmail' => true, + 'notificationEmailReceiver' => 'ops@example.com', + 'notificationEmailSender' => 'shop@example.com', + ]] +]); +``` + +> **Important:** The context array must use numeric indices `0` (vendor) and `1` (plugin name). +> Associative arrays passed by Shopware core services (e.g. `['exception' => ...]`) are handled +> gracefully — they fall back to the default `sw/dev` log file without errors. + ## CLIs ```shell bin/console muckiware:logger:send @@ -118,7 +190,16 @@ This command execute the sending of open logger events by email. Regular will th ```shell bin/console muckiware:logger:check ``` -This command is just for testing logging methods. +This command tests the `Psr\Log\LoggerInterface` injection path and writes sample log entries +across all log levels. + +```shell +bin/console muckiware:logger:check-sw +``` +This command tests the `id="logger"` injection path (typical Shopware core pattern) to verify +that the `LoggerDecoratorCompilerPass` correctly routes those calls through MuckiLogPlugin. +The first output line shows the actual class injected — it should read +`MuckiLogPlugin\Services\LoggerServiceDecorator`, not `Monolog\Logger`. # Testing ## phpstan diff --git a/src/Commands/CheckupSwLogger.php b/src/Commands/CheckupSwLogger.php new file mode 100644 index 0000000..99536b8 --- /dev/null +++ b/src/Commands/CheckupSwLogger.php @@ -0,0 +1,101 @@ +container = $container; + } + + public function getContainer(): ?ContainerInterface + { + return $this->container; + } + + public function configure(): void + { + $this->setDescription( + 'Tests logging via id="logger" injection (typical Shopware pattern) — verifies the CompilerPass routes calls through the MuckiLog decorator.' + ); + parent::configure(); + } + + public function execute(InputInterface $input, OutputInterface $output): int + { + $output->writeln('Start SW-logger checkup (id="logger" injection)'); + $output->writeln('Logger class: '.get_class($this->logger)); + + $this->writeTestLogEntries($output); + + $output->writeln('Done SW-logger checkup'); + + return Command::SUCCESS; + } + + private function writeTestLogEntries(OutputInterface $output): void + { + $output->writeln('Write into path: '.$this->pluginSettings->getLogPath()); + + foreach (LogLevel::cases() as $key => $logLevel) { + $method = $logLevel->value; + + $output->writeln($key.' - Write '.$method.' via id="logger"'); + + // Einfache Nachricht — kein Context → Fallback sw/dev Log-Datei + $this->logger->{$method}($key.' - SW-logger test (no context): '.$method); + + // Mit Vendor/Plugin-Context → eigene Log-Datei + $this->logger->{$method}( + $key.' - SW-logger test (with context): '.$method, + [PluginDefaults::CONTEXT, PluginDefaults::EXTENSION] + ); + } + + $defaultLogFile = $this->pluginSettings->getLogPath().'/'.PluginDefaults::DEFAULT_SW_EXTENSION.'.'.PluginDefaults::DEFAULT_SW_CONTEXT.'.log'; + $contextLogFile = $this->pluginSettings->getLogPath().'/'.PluginDefaults::EXTENSION.'.'.PluginDefaults::CONTEXT.'.log'; + + if (file_exists($defaultLogFile)) { + $output->writeln('OK: default log file written → '.$defaultLogFile); + } else { + $output->writeln('FAIL: default log file missing → '.$defaultLogFile); + } + + if (file_exists($contextLogFile)) { + $output->writeln('OK: context log file written → '.$contextLogFile); + } else { + $output->writeln('FAIL: context log file missing → '.$contextLogFile); + } + } +} diff --git a/src/DependencyInjection/LoggerDecoratorCompilerPass.php b/src/DependencyInjection/LoggerDecoratorCompilerPass.php new file mode 100644 index 0000000..b81625b --- /dev/null +++ b/src/DependencyInjection/LoggerDecoratorCompilerPass.php @@ -0,0 +1,113 @@ +hasDefinition(self::DECORATOR_ID)) { + return; + } + + $decoratorDeps = []; + $this->collectTransitiveDeps(self::DECORATOR_ID, $container, $decoratorDeps); + + $this->replaceLoggerArguments($container, $decoratorDeps); + } + + /** + * Ersetzt id="logger" Injektionen durch den Decorator. + */ + private function replaceLoggerArguments(ContainerBuilder $container, array $decoratorDeps): void + { + foreach ($container->getDefinitions() as $serviceId => $definition) { + if ($serviceId === self::DECORATOR_ID || isset($decoratorDeps[$serviceId])) { + continue; + } + + foreach ($definition->getArguments() as $index => $argument) { + if ($argument instanceof Reference && (string) $argument === self::LOGGER_ID) { + $definition->replaceArgument($index, new Reference(self::DECORATOR_ID)); + } + } + + $methodCalls = $definition->getMethodCalls(); + $modified = false; + foreach ($methodCalls as &$call) { + [, $arguments] = $call; + foreach ($arguments as $argIndex => $argument) { + if ($argument instanceof Reference && (string) $argument === self::LOGGER_ID) { + $arguments[$argIndex] = new Reference(self::DECORATOR_ID); + $modified = true; + } + } + $call[1] = $arguments; + } + unset($call); + + if ($modified) { + $definition->setMethodCalls($methodCalls); + } + } + } + + private function collectTransitiveDeps(string $serviceId, ContainerBuilder $container, array &$visited): void + { + $resolvedId = $this->resolveAlias($serviceId, $container); + + if (isset($visited[$resolvedId])) { + return; + } + + $visited[$resolvedId] = true; + if ($resolvedId !== $serviceId) { + $visited[$serviceId] = true; + } + + if (!$container->hasDefinition($resolvedId)) { + return; + } + + $definition = $container->getDefinition($resolvedId); + + foreach ($definition->getArguments() as $argument) { + if ($argument instanceof Reference) { + $this->collectTransitiveDeps((string) $argument, $container, $visited); + } + } + + foreach ($definition->getMethodCalls() as [, $arguments]) { + foreach ($arguments as $argument) { + if ($argument instanceof Reference) { + $this->collectTransitiveDeps((string) $argument, $container, $visited); + } + } + } + } + + private function resolveAlias(string $serviceId, ContainerBuilder $container): string + { + while ($container->hasAlias($serviceId)) { + $serviceId = (string) $container->getAlias($serviceId); + } + + return $serviceId; + } +} diff --git a/src/Logging/Logger.php b/src/Logging/Logger.php index 211afc1..79c8798 100644 --- a/src/Logging/Logger.php +++ b/src/Logging/Logger.php @@ -4,7 +4,7 @@ * * @category Muckiware * @package Logger - * @copyright Copyright (c) 2021-2024 by muckiware + * @copyright Copyright (c) 2021-2026 by muckiware * */ namespace MuckiLogPlugin\Logging; @@ -41,6 +41,11 @@ public function __construct( $this->logger = $this->logConfig->getLogger(); } + public function setLogger(LogconfigInterface $logConfig): void + { + $this->logger = $logConfig->getLogger(); + } + public function executeLoggingByLogLevel(LoggerSetup $loggerSetup): void { $event = new CreateLogEvent($loggerSetup); diff --git a/src/MuckiLogPlugin.php b/src/MuckiLogPlugin.php index 690fdad..2dd6189 100644 --- a/src/MuckiLogPlugin.php +++ b/src/MuckiLogPlugin.php @@ -4,7 +4,7 @@ * * @category SW6 Plugin * @package Muckilog - * @copyright Copyright (c) 2021-2024 by Muckiware + * @copyright Copyright (c) 2021-2026 by Muckiware * @license MIT * @author Muckiware * @@ -17,13 +17,21 @@ use Shopware\Core\Framework\Plugin\Context\InstallContext; use Shopware\Core\Framework\Plugin\Context\UninstallContext; use Shopware\Core\Framework\Plugin\Context\UpdateContext; +use Symfony\Component\DependencyInjection\ContainerBuilder; +use MuckiLogPlugin\DependencyInjection\LoggerDecoratorCompilerPass; use MuckiLogPlugin\Setup\Setup; use MuckiLogPlugin\Services\Logconfig; use MuckiLogPlugin\Services\Settings; class MuckiLogPlugin extends Plugin { + public function build(ContainerBuilder $container): void + { + parent::build($container); + $container->addCompilerPass(new LoggerDecoratorCompilerPass()); + } + /** * @throws \Exception */ diff --git a/src/Resources/config/services.xml b/src/Resources/config/services.xml index 67ad6f3..4c91db7 100644 --- a/src/Resources/config/services.xml +++ b/src/Resources/config/services.xml @@ -18,7 +18,7 @@ - + @@ -47,6 +47,14 @@ + + + + + + + + diff --git a/src/Services/LoggerServiceDecorator.php b/src/Services/LoggerServiceDecorator.php index 17d8450..0551922 100644 --- a/src/Services/LoggerServiceDecorator.php +++ b/src/Services/LoggerServiceDecorator.php @@ -5,12 +5,11 @@ * * @category Muckiware * @package Muckilog - * @copyright Copyright (c) 2021-2024 by Muckiware + * @copyright Copyright (c) 2021-2026 by Muckiware * @license MIT * @author Muckiware * */ - namespace MuckiLogPlugin\Services; use http\Message; @@ -111,8 +110,9 @@ public function getLoggerSetup(LogLevel $logLevel, mixed $message, array $contex public function contextSetupNeedNotification(array $context): bool { - if( - !empty($context) && count($context) === 3 && + if ( + isset($context[2]) && + is_array($context[2]) && array_key_exists('setup', $context[2]) && array_key_exists('notificationEmail', $context[2]['setup']) && is_bool($context[2]['setup']['notificationEmail']) @@ -124,8 +124,9 @@ public function contextSetupNeedNotification(array $context): bool public function setupNotificationEmailTemplateId(array $context, LoggerSetup $loggerSetup): LoggerSetup { - if( - !empty($context) && count($context) === 3 && + if ( + isset($context[2]) && + is_array($context[2]) && array_key_exists('setup', $context[2]) && array_key_exists('notificationEmailTemplateId', $context[2]['setup']) && Uuid::isValid(trim($context[2]['setup']['notificationEmailTemplateId'])) @@ -143,8 +144,9 @@ public function setupNotificationEmailTemplateId(array $context, LoggerSetup $lo public function setupNotificationEmailReceiver(array $context, LoggerSetup $loggerSetup): LoggerSetup { - if( - !empty($context) && count($context) === 3 && + if ( + isset($context[2]) && + is_array($context[2]) && array_key_exists('setup', $context[2]) && array_key_exists('notificationEmailReceiver', $context[2]['setup']) && $this->pluginHelper->isValidEmail(trim($context[2]['setup']['notificationEmailReceiver'])) @@ -162,8 +164,9 @@ public function setupNotificationEmailReceiver(array $context, LoggerSetup $logg public function setupNotificationEmailSender(array $context, LoggerSetup $loggerSetup): LoggerSetup { - if( - !empty($context) && count($context) === 3 && + if ( + isset($context[2]) && + is_array($context[2]) && array_key_exists('setup', $context[2]) && array_key_exists('notificationEmailSender', $context[2]['setup']) && $this->pluginHelper->isValidEmail(trim($context[2]['setup']['notificationEmailSender'])) @@ -177,12 +180,10 @@ public function setupNotificationEmailSender(array $context, LoggerSetup $logger public function setupVendorPluginNames(array $context, LoggerSetup $loggerSetup): LoggerSetup { - if(!empty($context) && count($context) >= 2) { - + if (isset($context[0], $context[1])) { $loggerSetup->setVendor(trim($context[0])); $loggerSetup->setPlugin(trim($context[1])); } else { - $loggerSetup->setVendor(Defaults::DEFAULT_SW_CONTEXT); $loggerSetup->setPlugin(Defaults::DEFAULT_SW_EXTENSION); } diff --git a/tests/Logging/LoggerTest.php b/tests/Logging/LoggerTest.php new file mode 100644 index 0000000..16f8293 --- /dev/null +++ b/tests/Logging/LoggerTest.php @@ -0,0 +1,72 @@ +createMock(PluginSettings::class); + $pluginSettings->method('getConfigPath')->willReturn(TestDefaults::getLoggerConfigPath()); + $pluginSettings->method('getLoggerFileName')->willReturn(TestDefaults::getLoggerFilePath()); + $pluginSettings->method('getMaxBackupIndex')->willReturn(PluginSettings::CONFIG_PATH_MAX_BACKUP_INDEX_DEFAULT); + $pluginSettings->method('getMaxFileSize')->willReturn(PluginSettings::CONFIG_PATH_MAX_FILESIZE_DEFAULT); + $pluginSettings->method('isEnabledCompress')->willReturn(false); + $pluginSettings->method('getConversionPattern')->willReturn(PluginSettings::CONFIG_PATH_CONVERSIONPATTERN_DEFAULT); + $pluginSettings->method('getLoglevel')->willReturn('debug'); + $logconfig = new Logconfig( + $this->createMock(KernelInterface::class), + $pluginSettings + ); + + //Create the log config for the test + $checkConfigPath = $logconfig->checkConfigPath(TestDefaults::DEFAULT_TEST_PLUGIN, TestDefaults::DEFAULT_TEST_VENDOR); + $this->assertIsBool($checkConfigPath); + $this->assertTrue($checkConfigPath, 'Logconfig path could not be created for the test.'); + + \MuckiLogPlugin\Log4php\Logger::configure(TestDefaults::getLoggerConfigPath()); + + $logconfigInterface = $this->createMock(LogconfigInterface::class); + $Log4phpLogger = \MuckiLogPlugin\Log4php\Logger::getLogger('muckilog'); + $logconfigInterface->method('getLogger')->willReturn($Log4phpLogger); + + $logger = new Logger( + $this->createMock(EventDispatcherInterface::class), + $logconfigInterface, + $this->createMock(SettingsInterface::class), + $this->createMock(LoggingEvent::class) + ); + + $loggerSetup = new LoggerSetup(); + $loggerSetup->setLogLevel(LogLevel::INFO); + $loggerSetup->setMessage('This is a test log message.'); + $loggerSetup->setPlugin(TestDefaults::DEFAULT_TEST_PLUGIN); + $loggerSetup->setVendor(TestDefaults::DEFAULT_TEST_VENDOR); + $loggerSetup->setPathLogFile(TestDefaults::getLoggerConfigPath()); + + $logger->executeLoggingByLogLevel($loggerSetup); + + $checker = true; + } +} diff --git a/tests/TestCaseBase/Defaults.php b/tests/TestCaseBase/Defaults.php new file mode 100644 index 0000000..773838e --- /dev/null +++ b/tests/TestCaseBase/Defaults.php @@ -0,0 +1,39 @@ +