diff --git a/.github/workflows/analysis.yaml b/.github/workflows/analysis.yaml index 0ff5195..0561f43 100644 --- a/.github/workflows/analysis.yaml +++ b/.github/workflows/analysis.yaml @@ -16,12 +16,11 @@ jobs: fail-fast: false matrix: php: - - 7.4 - - 8.0 - - 8.1 + - 8.2 + - 8.5 symfony: - - '5.4.*' - - '6.1.*' + - '6.4.*' + - '7.4.*' env: APP_ENV: test steps: diff --git a/.github/workflows/sylius.yaml b/.github/workflows/sylius.yaml index 18b5159..29751ed 100644 --- a/.github/workflows/sylius.yaml +++ b/.github/workflows/sylius.yaml @@ -16,45 +16,24 @@ jobs: fail-fast: false matrix: php: - - 7.4 - - 8.0 - - 8.1 + - 8.2 + - 8.5 sylius: - - 1.9.0 - - 1.10.0 - - 1.11.0 - - 1.12.0 + - 2.0.0 + - 2.1.0 + - 2.2.0 symfony: - - 5.4 - - 6.1 + - 6.4 + - 7.4 node: - - 14.x + - 24.x exclude: - - - sylius: 1.9.0 - php: 8.0 - - - sylius: 1.9.0 - php: 8.1 - - - sylius: 1.11.0 - php: 7.4 - symfony: 5.4 - - - sylius: 1.9.0 - symfony: 6.1 - - - sylius: 1.10.0 - symfony: 6.1 - - - sylius: 1.11.0 - symfony: 6.1 - - - sylius: 1.12.0 - php: 7.4 - - - php: '8.0' - symfony: 6.1 + - php: "8.5" + symfony: "6.4" + - sylius: "2.0.0" + php: "8.5" + - sylius: "2.0.0" + symfony: "7.4" env: APP_ENV: test package-name: synolia/sylius-admin-notification-plugin diff --git a/Makefile b/Makefile index c6c4616..3623784 100644 --- a/Makefile +++ b/Makefile @@ -6,9 +6,9 @@ CONSOLE=cd tests/Application && php bin/console -e test COMPOSER=cd tests/Application && composer YARN=cd tests/Application && yarn -SYLIUS_VERSION=1.12.0 -SYMFONY_VERSION=6.1 -PHP_VERSION=8.1 +SYLIUS_VERSION=2.0.0 +SYMFONY_VERSION=7.4 +PHP_VERSION=8.2 PLUGIN_NAME=synolia/sylius-admin-notification-plugin ### diff --git a/README.md b/README.md index a751827..cb549c8 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,11 @@

- + + + + Sylius Logo. +

@@ -16,10 +20,10 @@ ## Requirements -| | Version | -|:-------|:-----------| -| PHP | ^7.4, ^8.0 | -| Sylius | ^1.9 | +| | Version | +|:-------|:--------| +| PHP | ^8.2 | +| Sylius | ^2.0 | ## Installation diff --git a/composer.json b/composer.json index 55cf5ba..ddc1022 100644 --- a/composer.json +++ b/composer.json @@ -9,31 +9,31 @@ "description": "Admin notifications for Sylius.", "license": "EUPL-1.2", "require": { - "php": "^7.4 || ^8.0", + "php": "^8.2", "ext-json": "*", - "sylius/sylius": "^1.9", - "symfony/cache": "^5.4|^6.0", + "sylius/sylius": "^2.0", + "symfony/cache": "^6.4 || ^7.3 || ^8.0", "symfony/monolog-bundle": "^3.0", - "symfony/notifier": "^5.4|^6.0" + "symfony/notifier": "^6.4 || ^7.3" }, "require-dev": { - "friendsofphp/php-cs-fixer": "3.9.5", - "php-parallel-lint/php-parallel-lint": "1.3.2", - "phpmd/phpmd": "2.12.0", - "phpro/grumphp": "1.13.0", - "phpstan/extension-installer": "1.1.0", - "phpstan/phpstan": "1.8.2", - "phpstan/phpstan-doctrine": "1.3.11", - "phpstan/phpstan-strict-rules": "1.3.0", - "phpstan/phpstan-webmozart-assert": "1.2.0", - "phpunit/phpunit": "9.5.21", - "povils/phpmnd": "3.0.0", - "sebastian/phpcpd": "6.0.3", - "squizlabs/php_codesniffer": "3.7.1", - "symfony/browser-kit": "5.4.3", - "symfony/debug-bundle": "5.4.3", - "symfony/dotenv": "5.4.5", - "symfony/web-profiler-bundle": "5.4.10" + "friendsofphp/php-cs-fixer": "^3.9", + "php-parallel-lint/php-parallel-lint": "^1.3", + "phpmd/phpmd": "^2.12", + "phpro/grumphp": "^2.5", + "phpstan/extension-installer": "^1.1", + "phpstan/phpstan": "^2.0", + "phpstan/phpstan-doctrine": "^2.0", + "phpstan/phpstan-strict-rules": "^2.0", + "phpstan/phpstan-webmozart-assert": "^2.0", + "phpunit/phpunit": "^9.5", + "povils/phpmnd": "^3.0", + "sebastian/phpcpd": "^6.0", + "squizlabs/php_codesniffer": "^3.7", + "symfony/browser-kit": "^6.4 || ^7.3", + "symfony/debug-bundle": "^6.4 || ^7.3", + "symfony/dotenv": "^6.4 || ^7.3", + "symfony/web-profiler-bundle": "^6.4 || ^7.3" }, "config": { "sort-packages": true, @@ -41,7 +41,8 @@ "dealerdirect/phpcodesniffer-composer-installer": true, "symfony/thanks": true, "phpstan/extension-installer": true, - "phpro/grumphp": true + "phpro/grumphp": true, + "php-http/discovery": true } }, "autoload": { diff --git a/config/packages/app.yaml b/config/packages/app.yaml index ba62a8b..2eea26d 100644 --- a/config/packages/app.yaml +++ b/config/packages/app.yaml @@ -1,10 +1,3 @@ -sylius_ui: - events: - sylius.admin.layout.topbar_right: - blocks: - admin_notifications: - template: '@SynoliaSyliusAdminNotificationPlugin/Notifications/top_bar.html.twig' - priority: 11 framework: notifier: @@ -49,17 +42,21 @@ sylius_grid: sortable: true enabled: false filters: - channel: - type: string - label: sylius.ui.channel - enabled: true - default_value: ~ levelName: - type: criticality + type: select enabled: true - label: sylius.ui.channel + label: synolia_sylius_admin_notification.ui.level_name + form_options: + choices: + synolia_sylius_admin_notification.ui.levels.debug: DEBUG + synolia_sylius_admin_notification.ui.levels.info: INFO + synolia_sylius_admin_notification.ui.levels.notice: NOTICE + synolia_sylius_admin_notification.ui.levels.warning: WARNING + synolia_sylius_admin_notification.ui.levels.error: ERROR + synolia_sylius_admin_notification.ui.levels.critical: CRITICAL + synolia_sylius_admin_notification.ui.levels.alert: ALERT + synolia_sylius_admin_notification.ui.levels.emergency: EMERGENCY default_value: ~ - message: type: string label: synolia_sylius_admin_notification.ui.message @@ -83,6 +80,3 @@ sylius_grid: enabled: true position: 100 options: { } - templates: - filter: - criticality: '@SynoliaSyliusAdminNotificationPlugin/Grid/Filter/criticality.html.twig' diff --git a/config/routes/admin_routing.yaml b/config/routes/admin_routing.yaml index 7f99a01..7d47260 100644 --- a/config/routes/admin_routing.yaml +++ b/config/routes/admin_routing.yaml @@ -3,17 +3,11 @@ synolia_sylius_admin_notification: alias: synolia_sylius_admin_notification.notification section: admin redirect: index - templates: '@SyliusAdmin/Crud' + templates: '@SyliusAdmin/shared/crud' grid: synolia_sylius_admin_notification permission: true - except: ['show', 'create', 'update'] + except: ['create', 'update'] vars: all: - subheader: synolia_sylius_admin_notification.ui.admin.subheader - index: - icon: balance scale + hook_prefix: 'synolia.admin.notification' type: sylius.resource - -synolia_sylius_admin_notification_admin_notification_show: - path: /notifications/{id}/show - controller: Synolia\SyliusAdminNotificationPlugin\Controller\ShowAction diff --git a/config/twig_hooks/admin/layout/navbar.yaml b/config/twig_hooks/admin/layout/navbar.yaml new file mode 100644 index 0000000..3b33a21 --- /dev/null +++ b/config/twig_hooks/admin/layout/navbar.yaml @@ -0,0 +1,6 @@ +sylius_twig_hooks: + hooks: + 'sylius_admin.common.component.navbar.items': + admin_notifications: + template: '@SynoliaSyliusAdminNotificationPlugin/Notifications/top_bar.html.twig' + priority: 11 diff --git a/config/twig_hooks/admin/notification/show.yaml b/config/twig_hooks/admin/notification/show.yaml new file mode 100644 index 0000000..509795a --- /dev/null +++ b/config/twig_hooks/admin/notification/show.yaml @@ -0,0 +1,5 @@ +sylius_twig_hooks: + hooks: + 'synolia.admin.notification.show.content': + content: + template: '@SynoliaSyliusAdminNotificationPlugin/show.html.twig' diff --git a/dev/phpstan.neon b/dev/phpstan.neon index c87b180..720a2f4 100644 --- a/dev/phpstan.neon +++ b/dev/phpstan.neon @@ -1,8 +1,6 @@ parameters: level: max reportUnmatchedIgnoredErrors: false - checkMissingIterableValueType: false - checkGenericClassInNonGenericObjectType: false bootstrapFiles: - ../vendor/autoload.php excludePaths: diff --git a/src/DependencyInjection/SynoliaSyliusAdminNotificationExtension.php b/src/DependencyInjection/SynoliaSyliusAdminNotificationExtension.php index 4ff765c..1b6e8ca 100644 --- a/src/DependencyInjection/SynoliaSyliusAdminNotificationExtension.php +++ b/src/DependencyInjection/SynoliaSyliusAdminNotificationExtension.php @@ -19,6 +19,7 @@ final class SynoliaSyliusAdminNotificationExtension extends AbstractResourceExte public function load(array $configs, ContainerBuilder $container): void { + /** @var array{driver: string, resources: array} $config */ $config = $this->processConfiguration(new Configuration(), $configs); $this->registerResources( 'synolia_sylius_admin_notification', @@ -35,13 +36,16 @@ public function prepend(ContainerBuilder $container): void { $container->setParameter('synolia_sylius_admin_notification.model.admin_notification.class', AdminNotification::class); - /** @var iterable $config */ - $config = Yaml::parseFile(\dirname(__DIR__, 2) . '/config/packages/app.yaml'); + $configPath = \dirname(__DIR__, 2) . '/config'; + /** @var array> $config */ + $config = Yaml::parseFile($configPath . '/packages/app.yaml'); foreach ($config as $packageName => $packageConfig) { $container->prependExtensionConfig($packageName, $packageConfig); } + $this->prependTwigHooks($container, $configPath . '/twig_hooks'); + $this->prependDoctrineMigrations($container); } @@ -55,8 +59,36 @@ protected function getMigrationsDirectory(): string return '@SynoliaSyliusAdminNotificationPlugin/migrations'; } + /** + * @return array + */ protected function getNamespacesOfMigrationsExecutedBefore(): array { return []; } + + private function prependTwigHooks(ContainerBuilder $container, string $configPath): void + { + if (!is_dir($configPath)) { + return; + } + + $files = new \RecursiveIteratorIterator( + new \RecursiveDirectoryIterator($configPath, \RecursiveDirectoryIterator::SKIP_DOTS), + \RecursiveIteratorIterator::LEAVES_ONLY + ); + + /** @var \SplFileInfo $file */ + foreach ($files as $file) { + if ('yaml' === $file->getExtension()) { + /** @var array $config */ + $config = Yaml::parseFile($file->getPathname()); + if (isset($config['sylius_twig_hooks']) && \is_array($config['sylius_twig_hooks'])) { + /** @var array $hooks */ + $hooks = $config['sylius_twig_hooks']; + $container->prependExtensionConfig('sylius_twig_hooks', $hooks); + } + } + } + } } diff --git a/src/Entity/AdminNotification.php b/src/Entity/AdminNotification.php index 2dc0306..1f292fb 100644 --- a/src/Entity/AdminNotification.php +++ b/src/Entity/AdminNotification.php @@ -18,6 +18,7 @@ class AdminNotification implements AdminNotificationInterface protected string $message = ''; + /** @var array */ protected array $context = []; public function getId(): ?int @@ -61,11 +62,17 @@ public function setLevelName(string $levelName): self return $this; } + /** + * @return array + */ public function getContext(): array { return $this->context; } + /** + * @param array $context + */ public function setContext(array $context): self { $this->context = $context; diff --git a/src/Entity/AdminNotificationInterface.php b/src/Entity/AdminNotificationInterface.php index 44b1f6e..6503157 100644 --- a/src/Entity/AdminNotificationInterface.php +++ b/src/Entity/AdminNotificationInterface.php @@ -21,7 +21,13 @@ public function getLevelName(): string; public function setLevelName(string $levelName): self; + /** + * @return array + */ public function getContext(): array; + /** + * @param array $context + */ public function setContext(array $context): self; } diff --git a/src/Handler/Monolog/AdminNotificationHandler.php b/src/Handler/Monolog/AdminNotificationHandler.php index 40c5d70..3731c08 100644 --- a/src/Handler/Monolog/AdminNotificationHandler.php +++ b/src/Handler/Monolog/AdminNotificationHandler.php @@ -7,6 +7,7 @@ use Doctrine\ORM\EntityManagerInterface; use Monolog\Formatter\HtmlFormatter; use Monolog\Handler\AbstractProcessingHandler; +use Monolog\LogRecord; use Sylius\Component\Resource\Factory\FactoryInterface; use Symfony\Component\Cache\Adapter\ArrayAdapter; use Symfony\Component\Cache\CacheItem; @@ -29,7 +30,7 @@ final class AdminNotificationHandler extends AbstractProcessingHandler public function __construct( FactoryInterface $notificationFactory, EntityManagerInterface $entityManager, - HtmlFormatter $htmlFormatter + HtmlFormatter $htmlFormatter, ) { parent::__construct(); $this->notificationFactory = $notificationFactory; @@ -39,14 +40,14 @@ public function __construct( $this->cache = new ArrayAdapter(); } - protected function write(array $record): void + protected function write(LogRecord $record): void { $cachedNotifications = $this->cacheValue($record); $this->cache->save($cachedNotifications); $this->flushCache($cachedNotifications); } - private function cacheValue(array $record): CacheItem + private function cacheValue(LogRecord $record): CacheItem { $cachedNotifications = $this->cache->getItem(self::CACHE_KEY); @@ -56,7 +57,7 @@ private function cacheValue(array $record): CacheItem return $cachedNotifications; } - /** @var array $cachedValues */ + /** @var array $cachedValues */ $cachedValues = $cachedNotifications->get(); $cachedValues[] = $record; @@ -67,7 +68,7 @@ private function cacheValue(array $record): CacheItem private function flushCache(CacheItem $cachedNotifications): void { - /** @var array $cachedValue */ + /** @var array $cachedValue */ $cachedValue = $cachedNotifications->get(); // OR check last update @@ -78,11 +79,11 @@ private function flushCache(CacheItem $cachedNotifications): void foreach ($cachedValue as $record) { /** @var AdminNotificationInterface $adminNotification */ $adminNotification = $this->notificationFactory->createNew(); - $adminNotification->setCreatedAt($record['datetime']); + $adminNotification->setCreatedAt($record->datetime); $adminNotification - ->setLevelName($record['level_name']) - ->setChannel($record['channel']) - ->setMessage($record['message']) + ->setLevelName($record->level->getName()) + ->setChannel($record->channel) + ->setMessage($record->message) ->setContext(['html' => $this->htmlFormatter->format($record)]) ; diff --git a/src/Menu/AdminMenuListener.php b/src/Menu/AdminMenuListener.php index 803ce61..90a35b3 100644 --- a/src/Menu/AdminMenuListener.php +++ b/src/Menu/AdminMenuListener.php @@ -5,23 +5,12 @@ namespace Synolia\SyliusAdminNotificationPlugin\Menu; use Knp\Menu\ItemInterface; -use Sylius\Bundle\CoreBundle\Application\Kernel; use Sylius\Bundle\UiBundle\Menu\Event\MenuBuilderEvent; -use Sylius\Component\Resource\Repository\RepositoryInterface; +use Symfony\Component\EventDispatcher\Attribute\AsEventListener; final class AdminMenuListener { - private const SYLIUS_MAJOR_VERSION = 1; - - private const SYLIUS_MIN_MAJOR_VERSION = 11; - - private RepositoryInterface $notificationRepository; - - public function __construct(RepositoryInterface $notificationRepository) - { - $this->notificationRepository = $notificationRepository; - } - + #[AsEventListener(event: 'sylius.menu.admin.main', priority: -99)] public function addAdminMenuItems(MenuBuilderEvent $event): void { $menu = $this->getParentMenu($event); @@ -30,37 +19,22 @@ public function addAdminMenuItems(MenuBuilderEvent $event): void return; } - $menu + $notificationsMenu = $menu ->addChild('synolia_sylius_admin_notification.ui.notifications', [ 'route' => 'synolia_sylius_admin_notification_admin_notification_index', ]) ->setAttribute('type', 'link') ->setLabel('synolia_sylius_admin_notification.ui.notifications') - ->setLabelAttribute('icon', $this->getIcons()) ; - } - private function getIcons(): string - { - /** @phpstan-ignore-next-line */ - $count = $this->notificationRepository->count([]); - - if (0 === $count) { - return 'bell'; - } - - return 'bell yellow'; + $notificationsMenu->setExtra('routes', [ + ['pattern' => '/^synolia_sylius_admin_notification_/'], + ]); } /** @phpstan-ignore-next-line */ private function getParentMenu(MenuBuilderEvent $event): ?ItemInterface { - /** @phpstan-ignore-next-line */ - if (self::SYLIUS_MAJOR_VERSION === (int) Kernel::MAJOR_VERSION && (int) Kernel::MINOR_VERSION >= self::SYLIUS_MIN_MAJOR_VERSION) { - return $event->getMenu()->addChild('administration'); - } - - /** @phpstan-ignore-next-line */ return $event->getMenu()->getChild('sylius.ui.administration'); } } diff --git a/src/Transport/Notification/AdminNotificationTransport.php b/src/Transport/Notification/AdminNotificationTransport.php index aab6c04..7f6846c 100644 --- a/src/Transport/Notification/AdminNotificationTransport.php +++ b/src/Transport/Notification/AdminNotificationTransport.php @@ -22,7 +22,7 @@ final class AdminNotificationTransport implements TransportInterface public function __construct( EntityManagerInterface $entityManager, - FactoryInterface $notificationFactory + FactoryInterface $notificationFactory, ) { $this->entityManager = $entityManager; $this->notificationFactory = $notificationFactory; @@ -33,7 +33,7 @@ public function __toString(): string return self::TRANSPORT; } - public function send(MessageInterface $message): ?SentMessage + public function send(MessageInterface $message): SentMessage { return $this->doSend($message); } diff --git a/src/Transport/Notification/AdminNotificationTransportFactory.php b/src/Transport/Notification/AdminNotificationTransportFactory.php index 2050788..19194b1 100644 --- a/src/Transport/Notification/AdminNotificationTransportFactory.php +++ b/src/Transport/Notification/AdminNotificationTransportFactory.php @@ -17,7 +17,7 @@ final class AdminNotificationTransportFactory implements TransportFactoryInterfa public function __construct( EntityManagerInterface $entityManager, - FactoryInterface $notificationFactory + FactoryInterface $notificationFactory, ) { $this->entityManager = $entityManager; $this->notificationFactory = $notificationFactory; diff --git a/src/Twig/Extension/NotificationWidgetExtension.php b/src/Twig/Extension/NotificationWidgetExtension.php index 1b9385b..0e36259 100644 --- a/src/Twig/Extension/NotificationWidgetExtension.php +++ b/src/Twig/Extension/NotificationWidgetExtension.php @@ -35,8 +35,6 @@ public function getFunctions(): array public function renderWidget(Environment $environment): string { return $environment->render('@SynoliaSyliusAdminNotificationPlugin/Notifications/_notification_widget.html.twig', [ - /** @phpstan-ignore-next-line */ - 'count' => $this->notificationRepository->count([]), 'resources' => $this->notificationRepository->findBy([], ['createdAt' => 'DESC'], 5), ]); } diff --git a/src/Twig/Extension/SerializeExtension.php b/src/Twig/Extension/SerializeExtension.php index 445d2ae..bd22e5c 100644 --- a/src/Twig/Extension/SerializeExtension.php +++ b/src/Twig/Extension/SerializeExtension.php @@ -24,10 +24,14 @@ public function getFilters() ]; } + /** + * @param array $object + * @param array $context + */ public function serialize( array $object, string $format = 'json', - array $context = ['json_encode_options' => \JSON_PRETTY_PRINT] + array $context = ['json_encode_options' => \JSON_PRETTY_PRINT], ): string { return $this->serializer->serialize($object, $format, $context); } diff --git a/templates/Notifications/_notification_widget.html.twig b/templates/Notifications/_notification_widget.html.twig index aed0d66..517db25 100644 --- a/templates/Notifications/_notification_widget.html.twig +++ b/templates/Notifications/_notification_widget.html.twig @@ -1,33 +1,35 @@ -