feat(plugin): align with Shopware plugin guidelines
- add dedicated monolog channel aeon_dump_manager and log dump jobs - migrate services.xml/routes.php to YAML - require PHP ^8.2 - add extension icon and .config/shopware-extension.yml - drop empty lifecycle overrides Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
29974928d2
commit
8efaef2042
12 files changed
+155
-129
No files matched your search
@@ -0,0 +1,21 @@
|
||||
# shopware-cli extension configuration (build/package/validate)
|
||||
build:
|
||||
zip:
|
||||
pack:
|
||||
excludes:
|
||||
paths:
|
||||
- tests
|
||||
- docs
|
||||
- scripts
|
||||
- phpunit.xml
|
||||
- docker-compose.yml
|
||||
- skills-lock.json
|
||||
- AGENTS.md
|
||||
- CLAUDE.md
|
||||
- QWEN.md
|
||||
- .claude
|
||||
- .scratch
|
||||
- .wayfinder
|
||||
- src/Resources/config/plugin-transparent.png
|
||||
validation:
|
||||
ignore: []
|
||||
@@ -14,7 +14,7 @@ the full build spec live under `.scratch/admin-dump-manager/` and `.scratch/dump
|
||||
- Plugin bootstrap class: `src/AeonDumpManager.php` (extends `Shopware\Core\Framework\Plugin`) — this
|
||||
is the entry point Shopware calls for install/uninstall/activate/deactivate/update lifecycle hooks.
|
||||
- Plugin class name is wired via `composer.json` → `extra.shopware-plugin-class`.
|
||||
- Services are registered manually in `src/Resources/config/services.xml` (Symfony DI, XML format,
|
||||
- Services are registered manually in `src/Resources/config/services.yaml` (Symfony DI, YAML format,
|
||||
autowiring is not configured — every new service/command/task must be added here explicitly with
|
||||
its tag, e.g. `console.command` or `shopware.scheduled.task`).
|
||||
- Plugin store-config UI fields (e.g. `maxDumps`, `retantionDays`) are defined in
|
||||
@@ -66,7 +66,7 @@ vendor/bin/phpunit tests/SomeTest.php # single file
|
||||
## Adding functionality
|
||||
|
||||
- New console commands go in `src/Command/`, new scheduled tasks in `src/ScheduledTask/` — both must
|
||||
be registered in `src/Resources/config/services.xml` with the appropriate tag or Shopware will not
|
||||
be registered in `src/Resources/config/services.yaml` with the appropriate tag or Shopware will not
|
||||
discover them.
|
||||
- Scheduled tasks need a matching handler (tagged `messenger.message_handler`) to actually run; a bare
|
||||
`ScheduledTask` subclass like `ExampleTask` only defines the schedule, not the behavior.
|
||||
+1
-1
@@ -25,7 +25,7 @@
|
||||
"source": "https://git.arthurerlich.de/haylan/AeonDumpManager"
|
||||
},
|
||||
"require": {
|
||||
"php": "^8.1",
|
||||
"php": "^8.2",
|
||||
"shopware/core": "~6.6.0"
|
||||
},
|
||||
"require-dev": {
|
||||
|
||||
+22
-31
@@ -4,17 +4,33 @@ namespace AeonDumpManager;
|
||||
|
||||
use Doctrine\DBAL\Connection;
|
||||
use Shopware\Core\Framework\Plugin;
|
||||
use Shopware\Core\Framework\Plugin\Context\ActivateContext;
|
||||
use Shopware\Core\Framework\Plugin\Context\DeactivateContext;
|
||||
use Shopware\Core\Framework\Plugin\Context\InstallContext;
|
||||
use Shopware\Core\Framework\Plugin\Context\UninstallContext;
|
||||
use Shopware\Core\Framework\Plugin\Context\UpdateContext;
|
||||
use Symfony\Component\Config\FileLocator;
|
||||
use Symfony\Component\Config\Loader\DelegatingLoader;
|
||||
use Symfony\Component\Config\Loader\LoaderResolver;
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
use Symfony\Component\DependencyInjection\Loader\DirectoryLoader;
|
||||
use Symfony\Component\DependencyInjection\Loader\GlobFileLoader;
|
||||
use Symfony\Component\DependencyInjection\Loader\YamlFileLoader;
|
||||
|
||||
class AeonDumpManager extends Plugin
|
||||
{
|
||||
public function install(InstallContext $installContext): void
|
||||
public function build(ContainerBuilder $container): void
|
||||
{
|
||||
// Do stuff such as creating a new payment method
|
||||
parent::build($container);
|
||||
|
||||
// Registers the dedicated monolog channel (Resources/config/packages/monolog.yaml)
|
||||
$locator = new FileLocator('Resources/config');
|
||||
$resolver = new LoaderResolver([
|
||||
new YamlFileLoader($container, $locator),
|
||||
new GlobFileLoader($container, $locator),
|
||||
new DirectoryLoader($container, $locator),
|
||||
]);
|
||||
|
||||
(new DelegatingLoader($resolver))->load(
|
||||
\rtrim($this->getPath(), '/') . '/Resources/config/packages/*.yaml',
|
||||
'glob'
|
||||
);
|
||||
}
|
||||
|
||||
public function uninstall(UninstallContext $uninstallContext): void
|
||||
@@ -29,29 +45,4 @@ class AeonDumpManager extends Plugin
|
||||
$connection = $this->container->get(Connection::class);
|
||||
$connection->executeStatement('DROP TABLE IF EXISTS `aeon_dump_manager_job`');
|
||||
}
|
||||
|
||||
public function activate(ActivateContext $activateContext): void
|
||||
{
|
||||
// Activate entities, such as a new payment method
|
||||
// Or create new entities here, because now your plugin is installed and active for sure
|
||||
}
|
||||
|
||||
public function deactivate(DeactivateContext $deactivateContext): void
|
||||
{
|
||||
// Deactivate entities, such as a new payment method
|
||||
// Or remove previously created entities
|
||||
}
|
||||
|
||||
public function update(UpdateContext $updateContext): void
|
||||
{
|
||||
// Update necessary stuff, mostly non-database related
|
||||
}
|
||||
|
||||
public function postInstall(InstallContext $installContext): void
|
||||
{
|
||||
}
|
||||
|
||||
public function postUpdate(UpdateContext $updateContext): void
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -5,6 +5,7 @@ namespace AeonDumpManager\MessageQueue\Handler;
|
||||
use AeonDumpManager\MessageQueue\Message\CreateDumpMessage;
|
||||
use AeonDumpManager\Service\DumpJobStatusService;
|
||||
use AeonDumpManager\Service\DumpService;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use Symfony\Component\Messenger\Attribute\AsMessageHandler;
|
||||
|
||||
#[AsMessageHandler]
|
||||
@@ -13,6 +14,7 @@ class CreateDumpHandler
|
||||
public function __construct(
|
||||
private readonly DumpService $dumpService,
|
||||
private readonly DumpJobStatusService $jobStatus,
|
||||
private readonly LoggerInterface $logger,
|
||||
) {
|
||||
}
|
||||
|
||||
@@ -20,10 +22,12 @@ class CreateDumpHandler
|
||||
{
|
||||
$jobId = $message->getJobId();
|
||||
$this->jobStatus->markRunning($jobId);
|
||||
$this->logger->info('Dump job started.', ['jobId' => $jobId]);
|
||||
|
||||
try {
|
||||
$this->dumpService->createAsync($jobId, $this->jobStatus);
|
||||
} catch (\Throwable $exception) {
|
||||
$this->logger->error('Dump job failed.', ['jobId' => $jobId, 'exception' => $exception]);
|
||||
$this->jobStatus->markFailed($jobId, $exception->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
monolog:
|
||||
channels: ['aeon_dump_manager']
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 48 KiB |
@@ -1,7 +0,0 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
use Symfony\Component\Routing\Loader\Configurator\RoutingConfigurator;
|
||||
|
||||
return function (RoutingConfigurator $routes): void {
|
||||
$routes->import(__DIR__ . '/../../Controller/*Controller.php', 'attribute');
|
||||
};
|
||||
@@ -0,0 +1,3 @@
|
||||
aeon_dump_manager_controllers:
|
||||
resource: ../../Controller/*Controller.php
|
||||
type: attribute
|
||||
@@ -1,88 +0,0 @@
|
||||
<?xml version="1.0" ?>
|
||||
|
||||
<container xmlns="http://symfony.com/schema/dic/services"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">
|
||||
|
||||
<services>
|
||||
<!-- Services -->
|
||||
|
||||
<service id="Symfony\Component\Process\ExecutableFinder"/>
|
||||
|
||||
<service id="aeon_dump_manager.dump_filename_parser" class="AeonDumpManager\Service\DumpFilenameParser"/>
|
||||
|
||||
<service id="aeon_dump_manager.dump_binary_locator" class="AeonDumpManager\Service\DumpBinaryLocator">
|
||||
<argument type="service" id="Doctrine\DBAL\Connection"/>
|
||||
<argument type="service" id="Shopware\Core\System\SystemConfig\SystemConfigService"/>
|
||||
<argument type="service" id="Symfony\Component\Process\ExecutableFinder"/>
|
||||
</service>
|
||||
|
||||
<service id="aeon_dump_manager.dump_job_status_service" class="AeonDumpManager\Service\DumpJobStatusService">
|
||||
<argument type="service" id="Doctrine\DBAL\Connection"/>
|
||||
</service>
|
||||
|
||||
<service id="aeon_dump_manager.dump_lister" class="AeonDumpManager\Service\DumpLister">
|
||||
<argument type="service" id="aeon_dump_manager.filesystem.private"/>
|
||||
<argument type="service" id="aeon_dump_manager.dump_filename_parser"/>
|
||||
</service>
|
||||
|
||||
<service id="aeon_dump_manager.dump_service" class="AeonDumpManager\Service\DumpService">
|
||||
<argument type="service" id="aeon_dump_manager.dump_lister"/>
|
||||
<argument type="service" id="aeon_dump_manager.filesystem.private"/>
|
||||
<argument type="service" id="aeon_dump_manager.dump_binary_locator"/>
|
||||
<argument type="service" id="Doctrine\DBAL\Connection"/>
|
||||
<argument type="service" id="Shopware\Core\System\SystemConfig\SystemConfigService"/>
|
||||
<argument type="service" id="aeon_dump_manager.dump_filename_parser"/>
|
||||
</service>
|
||||
|
||||
<!-- Async create job -->
|
||||
|
||||
<service id="aeon_dump_manager.message_queue.create_dump_handler" class="AeonDumpManager\MessageQueue\Handler\CreateDumpHandler">
|
||||
<argument type="service" id="aeon_dump_manager.dump_service"/>
|
||||
<argument type="service" id="aeon_dump_manager.dump_job_status_service"/>
|
||||
<tag name="messenger.message_handler"/>
|
||||
</service>
|
||||
|
||||
<!-- Retention -->
|
||||
|
||||
<service id="aeon_dump_manager.scheduled_task.purge_dumps_task" class="AeonDumpManager\ScheduledTask\PurgeDumpsTask">
|
||||
<tag name="shopware.scheduled.task"/>
|
||||
</service>
|
||||
|
||||
<service id="aeon_dump_manager.scheduled_task.purge_dumps_task_handler" class="AeonDumpManager\ScheduledTask\PurgeDumpsTaskHandler">
|
||||
<argument type="service" id="scheduled_task.repository"/>
|
||||
<argument type="service" id="logger"/>
|
||||
<argument type="service" id="aeon_dump_manager.dump_service"/>
|
||||
<argument type="service" id="aeon_dump_manager.dump_job_status_service"/>
|
||||
<argument type="service" id="Shopware\Core\System\SystemConfig\SystemConfigService"/>
|
||||
<tag name="messenger.message_handler" handles="AeonDumpManager\ScheduledTask\PurgeDumpsTask"/>
|
||||
</service>
|
||||
|
||||
<!-- Console commands -->
|
||||
|
||||
<service id="aeon_dump_manager.command.dump_list" class="AeonDumpManager\Command\DumpListCommand">
|
||||
<argument type="service" id="aeon_dump_manager.dump_lister"/>
|
||||
<tag name="console.command"/>
|
||||
</service>
|
||||
|
||||
<service id="aeon_dump_manager.command.dump_create" class="AeonDumpManager\Command\DumpCreateCommand">
|
||||
<argument type="service" id="aeon_dump_manager.dump_service"/>
|
||||
<tag name="console.command"/>
|
||||
</service>
|
||||
|
||||
<service id="aeon_dump_manager.command.dump_remove" class="AeonDumpManager\Command\DumpRemoveCommand">
|
||||
<argument type="service" id="aeon_dump_manager.dump_service"/>
|
||||
<tag name="console.command"/>
|
||||
</service>
|
||||
|
||||
<!-- Admin API controller -->
|
||||
|
||||
<service id="AeonDumpManager\Controller\DumpController" public="true">
|
||||
<argument type="service" id="aeon_dump_manager.dump_lister"/>
|
||||
<argument type="service" id="aeon_dump_manager.dump_service"/>
|
||||
<argument type="service" id="aeon_dump_manager.dump_job_status_service"/>
|
||||
<argument type="service" id="messenger.default_bus"/>
|
||||
</service>
|
||||
|
||||
</services>
|
||||
</container>
|
||||
@@ -0,0 +1,92 @@
|
||||
services:
|
||||
Symfony\Component\Process\ExecutableFinder: ~
|
||||
|
||||
aeon_dump_manager.dump_filename_parser:
|
||||
class: AeonDumpManager\Service\DumpFilenameParser
|
||||
|
||||
aeon_dump_manager.dump_binary_locator:
|
||||
class: AeonDumpManager\Service\DumpBinaryLocator
|
||||
arguments:
|
||||
- '@Doctrine\DBAL\Connection'
|
||||
- '@Shopware\Core\System\SystemConfig\SystemConfigService'
|
||||
- '@Symfony\Component\Process\ExecutableFinder'
|
||||
|
||||
aeon_dump_manager.dump_job_status_service:
|
||||
class: AeonDumpManager\Service\DumpJobStatusService
|
||||
arguments:
|
||||
- '@Doctrine\DBAL\Connection'
|
||||
|
||||
aeon_dump_manager.dump_lister:
|
||||
class: AeonDumpManager\Service\DumpLister
|
||||
arguments:
|
||||
- '@aeon_dump_manager.filesystem.private'
|
||||
- '@aeon_dump_manager.dump_filename_parser'
|
||||
|
||||
aeon_dump_manager.dump_service:
|
||||
class: AeonDumpManager\Service\DumpService
|
||||
arguments:
|
||||
- '@aeon_dump_manager.dump_lister'
|
||||
- '@aeon_dump_manager.filesystem.private'
|
||||
- '@aeon_dump_manager.dump_binary_locator'
|
||||
- '@Doctrine\DBAL\Connection'
|
||||
- '@Shopware\Core\System\SystemConfig\SystemConfigService'
|
||||
- '@aeon_dump_manager.dump_filename_parser'
|
||||
- '@monolog.logger.aeon_dump_manager'
|
||||
|
||||
# Async create job
|
||||
aeon_dump_manager.message_queue.create_dump_handler:
|
||||
class: AeonDumpManager\MessageQueue\Handler\CreateDumpHandler
|
||||
arguments:
|
||||
- '@aeon_dump_manager.dump_service'
|
||||
- '@aeon_dump_manager.dump_job_status_service'
|
||||
- '@monolog.logger.aeon_dump_manager'
|
||||
tags:
|
||||
- { name: messenger.message_handler }
|
||||
|
||||
# Retention
|
||||
aeon_dump_manager.scheduled_task.purge_dumps_task:
|
||||
class: AeonDumpManager\ScheduledTask\PurgeDumpsTask
|
||||
tags:
|
||||
- { name: shopware.scheduled.task }
|
||||
|
||||
aeon_dump_manager.scheduled_task.purge_dumps_task_handler:
|
||||
class: AeonDumpManager\ScheduledTask\PurgeDumpsTaskHandler
|
||||
arguments:
|
||||
- '@scheduled_task.repository'
|
||||
- '@monolog.logger.aeon_dump_manager'
|
||||
- '@aeon_dump_manager.dump_service'
|
||||
- '@aeon_dump_manager.dump_job_status_service'
|
||||
- '@Shopware\Core\System\SystemConfig\SystemConfigService'
|
||||
tags:
|
||||
- { name: messenger.message_handler, handles: AeonDumpManager\ScheduledTask\PurgeDumpsTask }
|
||||
|
||||
# Console commands
|
||||
aeon_dump_manager.command.dump_list:
|
||||
class: AeonDumpManager\Command\DumpListCommand
|
||||
arguments:
|
||||
- '@aeon_dump_manager.dump_lister'
|
||||
tags:
|
||||
- { name: console.command }
|
||||
|
||||
aeon_dump_manager.command.dump_create:
|
||||
class: AeonDumpManager\Command\DumpCreateCommand
|
||||
arguments:
|
||||
- '@aeon_dump_manager.dump_service'
|
||||
tags:
|
||||
- { name: console.command }
|
||||
|
||||
aeon_dump_manager.command.dump_remove:
|
||||
class: AeonDumpManager\Command\DumpRemoveCommand
|
||||
arguments:
|
||||
- '@aeon_dump_manager.dump_service'
|
||||
tags:
|
||||
- { name: console.command }
|
||||
|
||||
# Admin API controller
|
||||
AeonDumpManager\Controller\DumpController:
|
||||
public: true
|
||||
arguments:
|
||||
- '@aeon_dump_manager.dump_lister'
|
||||
- '@aeon_dump_manager.dump_service'
|
||||
- '@aeon_dump_manager.dump_job_status_service'
|
||||
- '@messenger.default_bus'
|
||||
@@ -6,6 +6,7 @@ use AeonDumpManager\Service\Exception\DumpNotFoundException;
|
||||
use AeonDumpManager\Struct\DumpFile;
|
||||
use Doctrine\DBAL\Connection;
|
||||
use League\Flysystem\FilesystemOperator;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use Shopware\Core\System\SystemConfig\SystemConfigService;
|
||||
use Symfony\Component\Process\Exception\ProcessFailedException;
|
||||
use Symfony\Component\Process\Process;
|
||||
@@ -24,6 +25,7 @@ class DumpService
|
||||
private readonly Connection $connection,
|
||||
private readonly SystemConfigService $systemConfigService,
|
||||
private readonly DumpFilenameParser $filenameParser,
|
||||
private readonly LoggerInterface $logger,
|
||||
) {
|
||||
}
|
||||
|
||||
@@ -69,6 +71,7 @@ class DumpService
|
||||
}
|
||||
|
||||
$this->aeonDumpManagerFilesystemPrivate->delete($path);
|
||||
$this->logger->info('Dump deleted.', ['filename' => $filename]);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -100,6 +103,7 @@ class DumpService
|
||||
|
||||
foreach ($excess as $dumpFile) {
|
||||
$this->aeonDumpManagerFilesystemPrivate->delete(DumpLister::path($dumpFile->filename));
|
||||
$this->logger->info('Dump removed: maxDumps exceeded.', ['filename' => $dumpFile->filename]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -108,6 +112,7 @@ class DumpService
|
||||
foreach ($this->dumpLister->list() as $dumpFile) {
|
||||
if ($dumpFile->datetime < $threshold) {
|
||||
$this->aeonDumpManagerFilesystemPrivate->delete(DumpLister::path($dumpFile->filename));
|
||||
$this->logger->info('Dump removed: older than retention.', ['filename' => $dumpFile->filename]);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -143,6 +148,7 @@ class DumpService
|
||||
|
||||
if (!$process->isSuccessful()) {
|
||||
@unlink($tempPath);
|
||||
$this->logger->error('Dump process failed.', ['exitCode' => $process->getExitCode()]);
|
||||
|
||||
throw new ProcessFailedException($process);
|
||||
}
|
||||
@@ -153,6 +159,8 @@ class DumpService
|
||||
fclose($stream);
|
||||
@unlink($tempPath);
|
||||
|
||||
$this->logger->info('Dump created.', ['filename' => $filename, 'sizeBytes' => $sizeBytes]);
|
||||
|
||||
return new DumpFile($filename, $dateTime, $sizeBytes);
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user