diff --git a/.docker/php/Dockerfile b/.docker/php/Dockerfile
index 33dd796..82be215 100644
--- a/.docker/php/Dockerfile
+++ b/.docker/php/Dockerfile
@@ -1,4 +1,4 @@
-FROM php:8.4-fpm-alpine
+FROM php:8.5-fpm-alpine
ARG UID
ARG GID
@@ -13,8 +13,7 @@ RUN apk update && apk add \
bash \
icu-dev \
&& docker-php-ext-configure intl \
- && docker-php-ext-install intl opcache \
- && docker-php-ext-enable opcache
+ && docker-php-ext-install intl
RUN ln -s /usr/share/zoneinfo/Europe/Paris /etc/localtime \
&& sed -i "s/^;date.timezone =.*/date.timezone = Europe\/Paris/" $PHP_INI_DIR/php.ini
diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
index 0e07db0..f2b0431 100644
--- a/.github/workflows/test.yml
+++ b/.github/workflows/test.yml
@@ -23,13 +23,14 @@ jobs:
- '8.2'
- '8.3'
- '8.4'
- dependencies: [highest]
+ - '8.5'
+ dependencies: [highest, lowest]
allowed-to-fail: [false]
symfony-require: ['']
variant: [normal]
include:
- - php-version: '8.1'
- dependencies: highest
+ - php-version: '8.2'
+ dependencies: lowest
allowed-to-fail: false
symfony-require: 6.4.*
variant: symfony/symfony:"6.4.*"
@@ -41,8 +42,8 @@ jobs:
- php-version: '8.2'
dependencies: highest
allowed-to-fail: false
- symfony-require: 7.3.*
- variant: symfony/symfony:"7.3.*"
+ symfony-require: 7.4.*
+ variant: symfony/symfony:"7.4.*"
- php-version: '8.3'
dependencies: highest
allowed-to-fail: false
@@ -51,8 +52,8 @@ jobs:
- php-version: '8.3'
dependencies: highest
allowed-to-fail: false
- symfony-require: 7.3.*
- variant: symfony/symfony:"7.3.*"
+ symfony-require: 7.4.*
+ variant: symfony/symfony:"7.4.*"
- php-version: '8.4'
dependencies: highest
allowed-to-fail: false
@@ -61,12 +62,31 @@ jobs:
- php-version: '8.4'
dependencies: highest
allowed-to-fail: false
- symfony-require: 7.3.*
- variant: symfony/symfony:"7.3.*"
-
+ symfony-require: 7.4.*
+ variant: symfony/symfony:"7.4.*"
+ - php-version: '8.4'
+ dependencies: highest
+ allowed-to-fail: false
+ symfony-require: 8.*
+ variant: symfony/symfony:"8.*"
+ - php-version: '8.5'
+ dependencies: highest
+ allowed-to-fail: false
+ symfony-require: 6.4.*
+ variant: symfony/symfony:"6.4.*"
+ - php-version: '8.5'
+ dependencies: highest
+ allowed-to-fail: false
+ symfony-require: 7.4.*
+ variant: symfony/symfony:"7.4.*"
+ - php-version: '8.5'
+ dependencies: highest
+ allowed-to-fail: false
+ symfony-require: 8.*
+ variant: symfony/symfony:"8.*"
steps:
- name: Checkout
- uses: actions/checkout@v4
+ uses: actions/checkout@v6
- name: Install PHP with extensions
uses: shivammathur/setup-php@v2
with:
@@ -87,4 +107,4 @@ jobs:
#- name: Send coverage to Codecov
# uses: codecov/codecov-action@v4
# with:
- # files: build/logs/clover.xml
+ # files: build/logs/clover.xml
\ No newline at end of file
diff --git a/.php-cs-fixer.dist.php b/.php-cs-fixer.dist.php
index ed5c8c5..d097551 100644
--- a/.php-cs-fixer.dist.php
+++ b/.php-cs-fixer.dist.php
@@ -24,9 +24,8 @@
return (new PhpCsFixer\Config())
->setRules([
- '@PHP71Migration' => true,
- '@PHP82Migration' => true,
- '@PHPUnit75Migration:risky' => true,
+ '@PHP8x2Migration' => true,
+ '@PHPUnit7x5Migration:risky' => true,
'@Symfony' => true,
'@Symfony:risky' => true,
'@DoctrineAnnotation' => true,
diff --git a/composer.json b/composer.json
index cb0eff3..630fa34 100644
--- a/composer.json
+++ b/composer.json
@@ -22,7 +22,7 @@
{
"name": "Xavier Marchegay",
"email": "xmarchegay@clever-age.com",
- "role": "Developer"
+ "role": "Lead Developer"
}
],
"autoload": {
@@ -36,41 +36,41 @@
}
},
"require": {
- "php": ">=8.1",
+ "php": ">=8.2",
"ext-ctype": "*",
"ext-iconv": "*",
- "cleverage/process-bundle": "^4.0",
- "doctrine/common": "^3.0",
- "doctrine/dbal": "^2.9 || ^3.0",
- "doctrine/doctrine-bundle": "^2.5",
- "doctrine/doctrine-migrations-bundle": "^3.2",
- "doctrine/orm": "^2.9 || ^3.0",
- "dragonmantank/cron-expression": "^3.4",
- "easycorp/easyadmin-bundle": "^4.8",
- "symfony/doctrine-messenger": "^6.4|^7.3",
- "symfony/dotenv": "^6.4|^7.3",
- "symfony/messenger": "^6.4|^7.3",
- "symfony/runtime": "^6.4|^7.3",
- "symfony/scheduler": "^6.4|^7.3",
- "symfony/string": "^6.4|^7.3",
- "symfony/uid": "^6.4|^7.3"
+ "cleverage/process-bundle": "^5.0",
+ "doctrine/common": "^3.5",
+ "doctrine/dbal": "^3.10 || ^4.4",
+ "doctrine/doctrine-bundle": "^2.18 || ^3.1",
+ "doctrine/doctrine-migrations-bundle": "^3.7 || ^4",
+ "doctrine/orm": "^2.20 || ^3.5",
+ "dragonmantank/cron-expression": "^3.6",
+ "easycorp/easyadmin-bundle": "^4.27",
+ "symfony/doctrine-messenger": "^6.4 || ^7.4 || ^8",
+ "symfony/dotenv": "^6.4 || ^7.4 || ^8",
+ "symfony/messenger":"^6.4 || ^7.4 || ^8",
+ "symfony/runtime": "^6.4 || ^7.4 || ^8",
+ "symfony/scheduler": "^6.4 || ^7.4 || ^8",
+ "symfony/string":"^6.4 || ^7.4 || ^8",
+ "symfony/uid": "^6.4 || ^7.4 || ^8"
},
"require-dev": {
- "doctrine/doctrine-fixtures-bundle": "^3.4",
+ "doctrine/doctrine-fixtures-bundle": "^3 || ^4",
"friendsofphp/php-cs-fixer": "*",
"phpstan/extension-installer": "*",
"phpstan/phpstan": "*",
"phpstan/phpstan-doctrine": "*",
"phpstan/phpstan-symfony": "*",
- "phpunit/phpunit": "<10.0",
+ "phpunit/phpunit": "*",
"rector/rector": "*",
"roave/security-advisories": "dev-latest",
- "symfony/browser-kit": "^6.4|^7.3",
- "symfony/css-selector": "^6.4|^7.3",
- "symfony/debug-bundle": "^6.4|^7.3",
+ "symfony/browser-kit": "^6.4 || ^7.4 || ^8",
+ "symfony/css-selector": "^6.4 || ^7.4 || ^8",
+ "symfony/debug-bundle": "^6.4 || ^7.4 || ^8",
"symfony/maker-bundle": "^1.31",
- "symfony/web-profiler-bundle": "^6.4|^7.3",
- "vincentlanglet/twig-cs-fixer": "^3.3"
+ "symfony/web-profiler-bundle": "^6.4 || ^7.4 || ^8",
+ "vincentlanglet/twig-cs-fixer": "^3.11"
},
"conflict": {
"symfony/twig-bridge": "7.2.0",
diff --git a/config/routes/easyadmin.yaml b/config/routes/easyadmin.yaml
new file mode 100644
index 0000000..a88552e
--- /dev/null
+++ b/config/routes/easyadmin.yaml
@@ -0,0 +1,3 @@
+easyadmin:
+ resource: .
+ type: easyadmin.routes
\ No newline at end of file
diff --git a/phpunit.xml.dist b/phpunit.xml.dist
index 766495c..c3e7947 100644
--- a/phpunit.xml.dist
+++ b/phpunit.xml.dist
@@ -1,27 +1,22 @@
+ failOnWarning="true">
tests
-
-
+
src
-
-
+
+
\ No newline at end of file
diff --git a/rector.php b/rector.php
index 9f9d327..46168ac 100644
--- a/rector.php
+++ b/rector.php
@@ -8,18 +8,18 @@
use Rector\ValueObject\PhpVersion;
return RectorConfig::configure()
- ->withPhpVersion(PhpVersion::PHP_84)
+ ->withPhpVersion(PhpVersion::PHP_85)
->withPaths([
__DIR__.'/src',
__DIR__.'/tests',
])
- ->withPhpSets(php81: true)
+ ->withPhpSets(php82: true)
// here we can define, what prepared sets of rules will be applied
->withComposerBased(doctrine: true)
->withPreparedSets(deadCode: true, codeQuality: true, doctrineCodeQuality: true, symfonyCodeQuality: true)
->withAttributesSets(symfony: true, doctrine: true)
->withSets([
- LevelSetList::UP_TO_PHP_81,
+ LevelSetList::UP_TO_PHP_82,
SymfonySetList::SYMFONY_64,
SymfonySetList::SYMFONY_CODE_QUALITY,
SymfonySetList::SYMFONY_CONSTRUCTOR_INJECTION,
diff --git a/src/Controller/Admin/LogRecordCrudController.php b/src/Controller/Admin/LogRecordCrudController.php
index 40ea6cb..8659dc4 100644
--- a/src/Controller/Admin/LogRecordCrudController.php
+++ b/src/Controller/Admin/LogRecordCrudController.php
@@ -89,7 +89,7 @@ public function configureFilters(Filters $filters): Filters
{
$id = $this->requestStack->getMainRequest()?->query->all('filters')['process']['value'] ?? null;
$processList = $this->processConfigurationsManager->getPublicProcesses();
- $processList = array_map(fn (ProcessConfiguration $cfg) => $cfg->getCode(), $processList);
+ $processList = array_map(static fn (ProcessConfiguration $cfg) => $cfg->getCode(), $processList);
return $filters->add(
LogProcessFilter::new('Process', $processList, $id)
@@ -97,7 +97,7 @@ public function configureFilters(Filters $filters): Filters
ChoiceFilter::new('level')
->setTranslatableChoices(array_combine(
Level::VALUES,
- array_map(fn ($value) => 'enum.log_level.'.strtolower((string) $value), Level::NAMES)
+ array_map(static fn ($value) => 'enum.log_level.'.strtolower((string) $value), Level::NAMES)
))
->setFormTypeOption('translation_domain', 'enums'),
)->add('message')->add('context')->add('createdAt');
diff --git a/src/Controller/Admin/Process/LaunchAction.php b/src/Controller/Admin/Process/LaunchAction.php
index 8f6bed5..709b5f2 100644
--- a/src/Controller/Admin/Process/LaunchAction.php
+++ b/src/Controller/Admin/Process/LaunchAction.php
@@ -19,7 +19,7 @@
use CleverAge\UiProcessBundle\Manager\ProcessConfigurationsManager;
use CleverAge\UiProcessBundle\Message\ProcessExecuteMessage;
use EasyCorp\Bundle\EasyAdminBundle\Config\Asset;
-use EasyCorp\Bundle\EasyAdminBundle\Context\AdminContext;
+use EasyCorp\Bundle\EasyAdminBundle\Provider\AdminContextProvider;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\Filesystem\Filesystem;
use Symfony\Component\Form\Extension\Core\Type\TextType;
@@ -40,21 +40,18 @@
#[IsGranted('ROLE_USER')]
class LaunchAction extends AbstractController
{
- public function __construct(private readonly MessageBusInterface $messageBus)
+ public function __construct(private readonly MessageBusInterface $messageBus, private readonly RequestStack $requestStack, private readonly ProcessConfigurationsManager $processConfigurationsManager, private readonly AdminContextProvider $adminContextProvider)
{
}
public function __invoke(
- RequestStack $requestStack,
string $uploadDirectory,
- ProcessConfigurationsManager $processConfigurationsManager,
- AdminContext $context,
): Response {
- $processCode = $requestStack->getMainRequest()?->get('process');
- if (null === $processCode) {
+ $processCode = (string) $this->requestStack->getMainRequest()?->query->get('process');
+ if ('' === $processCode) {
throw new MissingProcessException();
}
- $uiOptions = $processConfigurationsManager->getUiOptions($processCode);
+ $uiOptions = $this->processConfigurationsManager->getUiOptions($processCode);
if (null === $uiOptions) {
throw new \InvalidArgumentException('Missing UI Options');
}
@@ -84,7 +81,7 @@ public function __invoke(
}
$form->setData($default);
}
- $form->handleRequest($requestStack->getMainRequest());
+ $form->handleRequest($this->requestStack->getMainRequest());
if ($form->isSubmitted() && $form->isValid()) {
$input = $form->get('input')->getData();
if ($input instanceof UploadedFile) {
@@ -104,7 +101,7 @@ public function __invoke(
return $this->redirectToRoute('process', ['routeName' => 'process_list']);
}
- $context->getAssets()->addJsAsset(Asset::fromEasyAdminAssetPackage('field-collection.js')->getAsDto());
+ $this->adminContextProvider->getContext()?->getAssets()->addJsAsset(Asset::fromEasyAdminAssetPackage('field-collection.js')->getAsDto());
return $this->render(
'@CleverAgeUiProcess/admin/process/launch.html.twig',
diff --git a/src/Controller/Admin/Process/ListAction.php b/src/Controller/Admin/Process/ListAction.php
index 4857c75..7caa193 100644
--- a/src/Controller/Admin/Process/ListAction.php
+++ b/src/Controller/Admin/Process/ListAction.php
@@ -24,16 +24,16 @@
#[IsGranted('ROLE_USER')]
class ListAction extends AbstractController
{
- public function __construct(private readonly IntlFormatterInterface $intlFormatter)
+ public function __construct(private readonly IntlFormatterInterface $intlFormatter, private readonly ProcessConfigurationsManager $processConfigurationsManager)
{
}
- public function __invoke(ProcessConfigurationsManager $processConfigurationsManager): Response
+ public function __invoke(): Response
{
return $this->render(
'@CleverAgeUiProcess/admin/process/list.html.twig',
[
- 'processes' => $processConfigurationsManager->getPublicProcesses(),
+ 'processes' => $this->processConfigurationsManager->getPublicProcesses(),
'IntlFormatterService' => $this->intlFormatter,
]
);
diff --git a/src/Controller/Admin/Process/UploadAndExecuteAction.php b/src/Controller/Admin/Process/UploadAndExecuteAction.php
index 8392263..8f0691f 100644
--- a/src/Controller/Admin/Process/UploadAndExecuteAction.php
+++ b/src/Controller/Admin/Process/UploadAndExecuteAction.php
@@ -37,9 +37,11 @@
#[IsGranted('ROLE_USER')]
class UploadAndExecuteAction extends AbstractController
{
+ public function __construct(private readonly RequestStack $requestStack, private readonly MessageBusInterface $messageBus)
+ {
+ }
+
public function __invoke(
- RequestStack $requestStack,
- MessageBusInterface $messageBus,
string $uploadDirectory,
#[ValueResolver('process')] ProcessConfiguration $processConfiguration,
): Response {
@@ -49,15 +51,15 @@ public function __invoke(
$form = $this->createForm(
ProcessUploadFileType::class,
null,
- ['process_code' => $requestStack->getMainRequest()?->get('process')]
+ ['process_code' => $this->requestStack->getMainRequest()?->request->get('process')]
);
- $form->handleRequest($requestStack->getMainRequest());
+ $form->handleRequest($this->requestStack->getMainRequest());
if ($form->isSubmitted() && $form->isValid()) {
/** @var UploadedFile $file */
$file = $form->getData();
$savedFilepath = \sprintf('%s/%s.%s', $uploadDirectory, Uuid::v4(), $file->getClientOriginalExtension());
(new Filesystem())->dumpFile($savedFilepath, $file->getContent());
- $messageBus->dispatch(
+ $this->messageBus->dispatch(
new ProcessExecuteMessage(
$form->getConfig()->getOption('process_code'),
$savedFilepath
diff --git a/src/Controller/Admin/ProcessExecutionCrudController.php b/src/Controller/Admin/ProcessExecutionCrudController.php
index 1fa21b2..ebb7862 100644
--- a/src/Controller/Admin/ProcessExecutionCrudController.php
+++ b/src/Controller/Admin/ProcessExecutionCrudController.php
@@ -22,7 +22,6 @@
use EasyCorp\Bundle\EasyAdminBundle\Config\Actions;
use EasyCorp\Bundle\EasyAdminBundle\Config\Crud;
use EasyCorp\Bundle\EasyAdminBundle\Config\Filters;
-use EasyCorp\Bundle\EasyAdminBundle\Context\AdminContext;
use EasyCorp\Bundle\EasyAdminBundle\Controller\AbstractCrudController;
use EasyCorp\Bundle\EasyAdminBundle\Field\ArrayField;
use EasyCorp\Bundle\EasyAdminBundle\Field\DateTimeField;
@@ -109,7 +108,7 @@ public function configureActions(Actions $actions): Actions
);
}
- public function showLogs(AdminContext $adminContext): RedirectResponse
+ public function showLogs(): RedirectResponse
{
/** @var AdminUrlGenerator $adminUrlGenerator */
$adminUrlGenerator = $this->container->get(AdminUrlGenerator::class);
@@ -133,11 +132,10 @@ public function showLogs(AdminContext $adminContext): RedirectResponse
return $this->redirect($url);
}
- public function downloadLogFile(
- AdminContext $context,
- ): Response {
+ public function downloadLogFile(): Response
+ {
/** @var ProcessExecution $processExecution */
- $processExecution = $context->getEntity()->getInstance();
+ $processExecution = $this->getContext()->getEntity()->getInstance();
$filepath = $this->getLogFilePath($processExecution);
$basename = basename($filepath);
$content = file_get_contents($filepath);
diff --git a/src/Controller/Admin/ProcessScheduleCrudController.php b/src/Controller/Admin/ProcessScheduleCrudController.php
index 5501aff..3870271 100644
--- a/src/Controller/Admin/ProcessScheduleCrudController.php
+++ b/src/Controller/Admin/ProcessScheduleCrudController.php
@@ -57,13 +57,13 @@ public function configureCrud(Crud $crud): Crud
public function configureActions(Actions $actions): Actions
{
return $actions
- ->update(Crud::PAGE_INDEX, Action::NEW, fn (Action $action) => $action->setIcon('fa fa-plus')
+ ->update(Crud::PAGE_INDEX, Action::NEW, static fn (Action $action) => $action->setIcon('fa fa-plus')
->setLabel(false)
- ->addCssClass(''))->update(Crud::PAGE_INDEX, Action::EDIT, fn (Action $action) => $action->setIcon('fa fa-edit')
+ ->addCssClass(''))->update(Crud::PAGE_INDEX, Action::EDIT, static fn (Action $action) => $action->setIcon('fa fa-edit')
->setLabel(false)
- ->addCssClass('text-warning'))->update(Crud::PAGE_INDEX, Action::DELETE, fn (Action $action) => $action->setIcon('fa fa-trash-o')
+ ->addCssClass('text-warning'))->update(Crud::PAGE_INDEX, Action::DELETE, static fn (Action $action) => $action->setIcon('fa fa-trash-o')
->setLabel(false)
- ->addCssClass(''))->update(Crud::PAGE_INDEX, Action::BATCH_DELETE, fn (Action $action) => $action->setLabel('Delete')
+ ->addCssClass(''))->update(Crud::PAGE_INDEX, Action::BATCH_DELETE, static fn (Action $action) => $action->setLabel('Delete')
->addCssClass(''));
}
@@ -74,7 +74,7 @@ public static function getEntityFqcn(): string
public function configureFields(string $pageName): iterable
{
- $choices = array_map(fn (ProcessConfiguration $configuration) => [$configuration->getCode()], $this->processConfigurationsManager->getPublicProcesses());
+ $choices = array_map(static fn (ProcessConfiguration $configuration) => [$configuration->getCode()], $this->processConfigurationsManager->getPublicProcesses());
return [
FormField::addTab('General'),
@@ -90,7 +90,7 @@ public function configureFields(string $pageName): iterable
->setVirtual(true)
->hideOnForm()
->hideOnDetail()
- ->formatValue(fn ($value, ProcessSchedule $entity) => ProcessScheduleType::CRON === $entity->getType()
+ ->formatValue(static fn ($value, ProcessSchedule $entity) => ProcessScheduleType::CRON === $entity->getType()
? CronExpressionTrigger::fromSpec($entity->getExpression() ?? '')
->getNextRunDate(new \DateTimeImmutable())
?->format('c')
diff --git a/src/Controller/Admin/Security/LogoutController.php b/src/Controller/Admin/Security/LogoutController.php
index 9ddd963..ecfd5ce 100644
--- a/src/Controller/Admin/Security/LogoutController.php
+++ b/src/Controller/Admin/Security/LogoutController.php
@@ -20,10 +20,14 @@
class LogoutController extends AbstractController
{
+ public function __construct(private readonly Security $security)
+ {
+ }
+
#[Route('/process/logout', name: 'process_logout')]
- public function __invoke(Security $security): Response
+ public function __invoke(): Response
{
- $security->logout();
+ $this->security->logout();
return $this->redirectToRoute('process_login');
}
diff --git a/src/Controller/Admin/UserCrudController.php b/src/Controller/Admin/UserCrudController.php
index 02ccdd3..8ade166 100644
--- a/src/Controller/Admin/UserCrudController.php
+++ b/src/Controller/Admin/UserCrudController.php
@@ -17,7 +17,6 @@
use EasyCorp\Bundle\EasyAdminBundle\Config\Action;
use EasyCorp\Bundle\EasyAdminBundle\Config\Actions;
use EasyCorp\Bundle\EasyAdminBundle\Config\Crud;
-use EasyCorp\Bundle\EasyAdminBundle\Context\AdminContext;
use EasyCorp\Bundle\EasyAdminBundle\Controller\AbstractCrudController;
use EasyCorp\Bundle\EasyAdminBundle\Field\ChoiceField;
use EasyCorp\Bundle\EasyAdminBundle\Field\EmailField;
@@ -40,8 +39,10 @@
#[IsGranted('ROLE_USER')]
class UserCrudController extends AbstractCrudController
{
- /** @param array $roles */
- public function __construct(private readonly array $roles)
+ /**
+ * @param array $roles
+ */
+ public function __construct(private readonly array $roles, private readonly AdminUrlGenerator $adminUrlGenerator)
{
}
@@ -93,18 +94,19 @@ public function configureFields(string $pageName): iterable
public function configureActions(Actions $actions): Actions
{
return $actions
- ->update(Crud::PAGE_INDEX, Action::NEW, fn (Action $action) => $action->setIcon('fa fa-plus')
+ ->update(Crud::PAGE_INDEX, Action::NEW, static fn (Action $action) => $action->setIcon('fa fa-plus')
->setLabel(false)
- ->addCssClass(''))->update(Crud::PAGE_INDEX, Action::EDIT, fn (Action $action) => $action->setIcon('fa fa-edit')
+ ->addCssClass(''))->update(Crud::PAGE_INDEX, Action::EDIT, static fn (Action $action) => $action->setIcon('fa fa-edit')
->setLabel(false)
- ->addCssClass('text-warning'))->update(Crud::PAGE_INDEX, Action::DELETE, fn (Action $action) => $action->setIcon('fa fa-trash-o')
+ ->addCssClass('text-warning'))->update(Crud::PAGE_INDEX, Action::DELETE, static fn (Action $action) => $action->setIcon('fa fa-trash-o')
->setLabel(false)
- ->addCssClass(''))->update(Crud::PAGE_INDEX, Action::BATCH_DELETE, fn (Action $action) => $action->setLabel('Delete')
+ ->addCssClass(''))->update(Crud::PAGE_INDEX, Action::BATCH_DELETE, static fn (Action $action) => $action->setLabel('Delete')
->addCssClass(''))->add(Crud::PAGE_EDIT, Action::new('generateToken')->linkToCrudAction('generateToken'));
}
- public function generateToken(AdminContext $adminContext, AdminUrlGenerator $adminUrlGenerator): Response
+ public function generateToken(): Response
{
+ $adminContext = $this->getContext();
/** @var User $user */
$user = $adminContext->getEntity()->getInstance();
$token = md5(uniqid(date('YmdHis')));
@@ -116,7 +118,7 @@ public function generateToken(AdminContext $adminContext, AdminUrlGenerator $adm
$this->addFlash('success', 'New token generated '.$token.' (keep it in secured area. This token will never be displayed anymore)');
return $this->redirect(
- $adminUrlGenerator
+ $this->adminUrlGenerator
->setController(self::class)
->setAction(Action::EDIT)
->setEntityId($user->getId())
diff --git a/src/Controller/ProcessExecuteController.php b/src/Controller/ProcessExecuteController.php
index dc36f94..2ac555d 100644
--- a/src/Controller/ProcessExecuteController.php
+++ b/src/Controller/ProcessExecuteController.php
@@ -28,13 +28,14 @@
#[Route(path: '/http/process/execute', name: 'http_process_execute', methods: ['POST'])]
class ProcessExecuteController extends AbstractController
{
+ public function __construct(private readonly ValidatorInterface $validator, private readonly MessageBusInterface $bus, private readonly ProcessManager $processManager)
+ {
+ }
+
public function __invoke(
#[ValueResolver('http_process_execution')] HttpProcessExecution $httpProcessExecution,
- ValidatorInterface $validator,
- MessageBusInterface $bus,
- ProcessManager $processManager,
): JsonResponse {
- $violations = $validator->validate($httpProcessExecution);
+ $violations = $this->validator->validate($httpProcessExecution);
if ($violations->count() > 0) {
$violationsMessages = [];
foreach ($violations as $violation) {
@@ -43,7 +44,7 @@ public function __invoke(
throw new UnprocessableEntityHttpException(implode('. ', $violationsMessages));
}
if ($httpProcessExecution->queue) {
- $bus->dispatch(
+ $this->bus->dispatch(
new ProcessExecuteMessage(
$httpProcessExecution->code ?? '',
$httpProcessExecution->input,
@@ -54,20 +55,19 @@ public function __invoke(
);
return new JsonResponse('Process has been added to queue. It will start as soon as possible.');
- } else {
- try {
- $processManager->execute(
- $httpProcessExecution->code ?? '',
- $httpProcessExecution->input,
- \is_string($httpProcessExecution->context)
- ? json_decode($httpProcessExecution->context, true)
- : $httpProcessExecution->context
- );
- } catch (\Throwable $e) {
- return new JsonResponse($e->getMessage(), Response::HTTP_INTERNAL_SERVER_ERROR);
- }
-
- return new JsonResponse('Process has been proceed well.');
}
+ try {
+ $this->processManager->execute(
+ $httpProcessExecution->code ?? '',
+ $httpProcessExecution->input,
+ \is_string($httpProcessExecution->context)
+ ? json_decode($httpProcessExecution->context, true)
+ : $httpProcessExecution->context
+ );
+ } catch (\Throwable $e) {
+ return new JsonResponse($e->getMessage(), Response::HTTP_INTERNAL_SERVER_ERROR);
+ }
+
+ return new JsonResponse('Process has been proceed well.');
}
}
diff --git a/src/Entity/LogRecord.php b/src/Entity/LogRecord.php
index 2a9c25f..d20b261 100644
--- a/src/Entity/LogRecord.php
+++ b/src/Entity/LogRecord.php
@@ -51,7 +51,7 @@ public function getId(): ?int
public function __construct(
\Monolog\LogRecord $record,
#[ORM\ManyToOne(targetEntity: ProcessExecution::class, cascade: ['all'])]
- #[ORM\JoinColumn(name: 'process_execution_id', referencedColumnName: 'id', onDelete: 'CASCADE', nullable: false)]
+ #[ORM\JoinColumn(name: 'process_execution_id', referencedColumnName: 'id', nullable: false, onDelete: 'CASCADE')]
private readonly ProcessExecution $processExecution,
) {
$this->channel = (string) (new UnicodeString($record->channel))->truncate(64);
@@ -65,4 +65,9 @@ public function contextIsEmpty(): bool
{
return [] !== $this->context;
}
+
+ public function getProcessExecution(): ProcessExecution
+ {
+ return $this->processExecution;
+ }
}
diff --git a/src/Entity/ProcessSchedule.php b/src/Entity/ProcessSchedule.php
index 2132202..8eea928 100644
--- a/src/Entity/ProcessSchedule.php
+++ b/src/Entity/ProcessSchedule.php
@@ -87,12 +87,7 @@ public function setContext(array $context): void
$this->context = $context;
}
- /**
- * PHP 8.1 Fatal error: Null can not be used as a standalone type.
- *
- * @phpstan-ignore missingType.return
- */
- public function getNextExecution()
+ public function getNextExecution(): null
{
return null;
}
diff --git a/src/EventSubscriber/ProcessEventSubscriber.php b/src/EventSubscriber/ProcessEventSubscriber.php
index 66e3f4f..ed90faa 100644
--- a/src/EventSubscriber/ProcessEventSubscriber.php
+++ b/src/EventSubscriber/ProcessEventSubscriber.php
@@ -22,15 +22,12 @@
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\Uid\Uuid;
-/**
- * PHP 8.2 : Replace by readonly class.
- */
-final class ProcessEventSubscriber implements EventSubscriberInterface
+final readonly class ProcessEventSubscriber implements EventSubscriberInterface
{
public function __construct(
- private readonly ProcessHandler $processHandler,
- private readonly DoctrineProcessHandler $doctrineProcessHandler,
- private readonly ProcessExecutionManager $processExecutionManager,
+ private ProcessHandler $processHandler,
+ private DoctrineProcessHandler $doctrineProcessHandler,
+ private ProcessExecutionManager $processExecutionManager,
) {
}
diff --git a/src/Form/Type/LaunchType.php b/src/Form/Type/LaunchType.php
index 3c876bc..3881cf6 100644
--- a/src/Form/Type/LaunchType.php
+++ b/src/Form/Type/LaunchType.php
@@ -59,8 +59,8 @@ public function buildForm(FormBuilderInterface $builder, array $options): void
]
);
$builder->get('context')->addModelTransformer(new CallbackTransformer(
- fn ($data) => $data ?? [],
- fn ($data) => array_column($data ?? [], 'value', 'key'),
+ static fn ($data) => $data ?? [],
+ static fn ($data) => array_column($data ?? [], 'value', 'key'),
));
}
diff --git a/src/Http/Model/HttpProcessExecution.php b/src/Http/Model/HttpProcessExecution.php
index 7ae3e92..3c78a4a 100644
--- a/src/Http/Model/HttpProcessExecution.php
+++ b/src/Http/Model/HttpProcessExecution.php
@@ -20,21 +20,18 @@
use Symfony\Component\Validator\Constraints\Sequentially;
use Symfony\Component\Validator\Constraints\Type;
-/**
- * PHP 8.2 : Replace by readonly class.
- */
-final class HttpProcessExecution
+final readonly class HttpProcessExecution
{
/**
* @param string|array $context
*/
public function __construct(
#[Sequentially(constraints: [new NotNull(message: 'Process code is required.'), new IsValidProcessCode()])]
- public readonly ?string $code = null,
- public readonly ?string $input = null,
+ public ?string $code = null,
+ public ?string $input = null,
#[AtLeastOneOf(constraints: [new Json(), new Type('array')])]
- public readonly string|array $context = [],
- public readonly bool $queue = true,
+ public string|array $context = [],
+ public bool $queue = true,
) {
}
}
diff --git a/src/Http/ValueResolver/HttpProcessExecuteValueResolver.php b/src/Http/ValueResolver/HttpProcessExecuteValueResolver.php
index d1689b2..fd31642 100644
--- a/src/Http/ValueResolver/HttpProcessExecuteValueResolver.php
+++ b/src/Http/ValueResolver/HttpProcessExecuteValueResolver.php
@@ -22,14 +22,13 @@
use Symfony\Component\HttpKernel\ControllerMetadata\ArgumentMetadata;
use Symfony\Component\Serializer\SerializerInterface;
-/**
- * PHP 8.2 : Replace by readonly class.
- */
#[AsTargetedValueResolver('http_process_execution')]
-class HttpProcessExecuteValueResolver implements ValueResolverInterface
+readonly class HttpProcessExecuteValueResolver implements ValueResolverInterface
{
- public function __construct(private readonly string $storageDir, private readonly SerializerInterface $serializer)
- {
+ public function __construct(
+ private string $storageDir,
+ private SerializerInterface $serializer,
+ ) {
}
/**
@@ -37,26 +36,46 @@ public function __construct(private readonly string $storageDir, private readonl
*/
public function resolve(Request $request, ArgumentMetadata $argument): iterable
{
- $all = $request->request->all();
try {
- if ([] === $all) {
+ $hasRequestData = $request->request->count() > 0 || $request->files->count() > 0;
+
+ if (!$hasRequestData) {
+ $content = $request->getContent();
+ if (empty($content)) {
+ return [new HttpProcessExecution()];
+ }
+
$httpProcessExecution = $this->serializer->deserialize(
- $request->getContent(),
+ $content,
HttpProcessExecution::class,
'json'
);
} else {
- $input = $request->get('input', $request->files->get('input'));
+ $input = $request->request->get('input') ?? $request->query->get('input');
+
+ if (null === $input) {
+ $input = $request->files->get('input');
+ }
+
if ($input instanceof UploadedFile) {
$uploadFileName = $this->storageDir.\DIRECTORY_SEPARATOR.date('YmdHis').'_'.uniqid().'_'.$input->getClientOriginalName();
(new Filesystem())->dumpFile($uploadFileName, $input->getContent());
$input = $uploadFileName;
}
+
+ $code = $request->request->get('code') ?? $request->query->get('code');
+ $context = $request->request->all('context');
+ if ([] === $context) {
+ $context = $request->query->all('context');
+ }
+
+ $queue = $request->request->getBoolean('queue', true);
+
$httpProcessExecution = new HttpProcessExecution(
- $request->get('code'),
+ (string) $code,
$input,
- $request->get('context', []),
- $request->request->getBoolean('queue', true),
+ $context,
+ $queue
);
}
diff --git a/src/Http/ValueResolver/ProcessConfigurationValueResolver.php b/src/Http/ValueResolver/ProcessConfigurationValueResolver.php
index ef06496..9412d3f 100644
--- a/src/Http/ValueResolver/ProcessConfigurationValueResolver.php
+++ b/src/Http/ValueResolver/ProcessConfigurationValueResolver.php
@@ -20,13 +20,10 @@
use Symfony\Component\HttpKernel\Controller\ValueResolverInterface;
use Symfony\Component\HttpKernel\ControllerMetadata\ArgumentMetadata;
-/**
- * PHP 8.2 : Replace by readonly class.
- */
#[AsTargetedValueResolver('process')]
-class ProcessConfigurationValueResolver implements ValueResolverInterface
+readonly class ProcessConfigurationValueResolver implements ValueResolverInterface
{
- public function __construct(private readonly ProcessConfigurationRegistry $registry)
+ public function __construct(private ProcessConfigurationRegistry $registry)
{
}
@@ -35,6 +32,6 @@ public function __construct(private readonly ProcessConfigurationRegistry $regis
*/
public function resolve(Request $request, ArgumentMetadata $argument): iterable
{
- return [$this->registry->getProcessConfiguration($request->get('process'))];
+ return [$this->registry->getProcessConfiguration((string) $request->request->get('process'))];
}
}
diff --git a/src/Manager/ProcessConfigurationsManager.php b/src/Manager/ProcessConfigurationsManager.php
index 00ad111..eb365fc 100644
--- a/src/Manager/ProcessConfigurationsManager.php
+++ b/src/Manager/ProcessConfigurationsManager.php
@@ -20,37 +20,33 @@
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Component\Validator\Constraint;
-/**
- * PHP 8.2 : Replace by readonly class.
- */
/**
* @phpstan-type UiOptions array{
* 'source': ?string,
* 'target': ?string,
* 'ui_launch_mode': ?string,
- * 'run_confirmation_modal': bool,
* 'entrypoint_type': string,
* 'constraints': Constraint[],
* 'run': 'null|bool',
* 'default': array{'input': mixed, 'context': array{array{'key': 'int|text', 'value':'int|text'}}}
* }
*/
-final class ProcessConfigurationsManager
+final readonly class ProcessConfigurationsManager
{
- public function __construct(private readonly ProcessConfigurationRegistry $registry)
+ public function __construct(private ProcessConfigurationRegistry $registry)
{
}
/** @return ProcessConfiguration[] */
public function getPublicProcesses(): array
{
- return array_filter($this->getConfigurations(), fn (ProcessConfiguration $cfg) => $cfg->isPublic());
+ return array_filter($this->getConfigurations(), static fn (ProcessConfiguration $cfg) => $cfg->isPublic());
}
/** @return ProcessConfiguration[] */
public function getPrivateProcesses(): array
{
- return array_filter($this->getConfigurations(), fn (ProcessConfiguration $cfg) => !$cfg->isPublic());
+ return array_filter($this->getConfigurations(), static fn (ProcessConfiguration $cfg) => !$cfg->isPublic());
}
/**
@@ -75,7 +71,10 @@ public function getUiOptions(string $processCode): ?array
private function resolveUiOptions(array $options): array
{
$resolver = new OptionsResolver();
- $resolver->setDefault('ui', function (OptionsResolver $uiResolver): void {
+ $resolver->setDefault('ui', []);
+ $resolver->setAllowedTypes('ui', 'array');
+ $resolver->setNormalizer('ui', static function (Options $options, array $ui): array {
+ $uiResolver = new OptionsResolver();
$uiResolver->setDefaults(
[
'source' => null,
@@ -84,24 +83,20 @@ private function resolveUiOptions(array $options): array
'ui_launch_mode' => 'modal',
'constraints' => [],
'run' => null,
- 'default' => function (OptionsResolver $defaultResolver) {
+ 'default' => static function (OptionsResolver $defaultResolver) {
$defaultResolver->setDefault('input', null);
- $defaultResolver->setDefault('context', function (OptionsResolver $contextResolver) {
+ $defaultResolver->setDefault('context', static function (OptionsResolver $contextResolver) {
$contextResolver->setPrototype(true);
$contextResolver->setRequired(['key', 'value']);
});
},
]
);
- $uiResolver->setDeprecated(
- 'run',
- 'cleverage/ui-process-bundle',
- '2',
- 'run ui option is deprecated. Use public option instead to hide a process from UI'
- );
$uiResolver->setAllowedValues('entrypoint_type', ['text', 'file']);
- $uiResolver->setNormalizer('constraints', fn (Options $options, array $values): array => (new ConstraintLoader())->buildConstraints($values));
+ $uiResolver->setNormalizer('constraints', static fn (Options $options, array $values): array => (new ConstraintLoader())->buildConstraints($values));
$uiResolver->setAllowedValues('ui_launch_mode', ['modal', null, 'form']);
+
+ return $uiResolver->resolve($ui);
});
/**
* @var array{'ui': UiOptions} $options
diff --git a/src/Message/CronProcessMessage.php b/src/Message/CronProcessMessage.php
index a8449d7..8e94c09 100644
--- a/src/Message/CronProcessMessage.php
+++ b/src/Message/CronProcessMessage.php
@@ -15,12 +15,9 @@
use CleverAge\UiProcessBundle\Entity\ProcessSchedule;
-/**
- * PHP 8.2 : Replace by readonly class.
- */
-final class CronProcessMessage
+final readonly class CronProcessMessage
{
- public function __construct(public readonly ProcessSchedule $processSchedule)
+ public function __construct(public ProcessSchedule $processSchedule)
{
}
}
diff --git a/src/Message/CronProcessMessageHandler.php b/src/Message/CronProcessMessageHandler.php
index 285742a..13ab26c 100644
--- a/src/Message/CronProcessMessageHandler.php
+++ b/src/Message/CronProcessMessageHandler.php
@@ -16,20 +16,17 @@
use Symfony\Component\Messenger\Attribute\AsMessageHandler;
use Symfony\Component\Messenger\MessageBusInterface;
-/**
- * PHP 8.2 : Replace by readonly class.
- */
#[AsMessageHandler]
-final class CronProcessMessageHandler
+final readonly class CronProcessMessageHandler
{
- public function __construct(private readonly MessageBusInterface $bus)
+ public function __construct(private MessageBusInterface $bus)
{
}
public function __invoke(CronProcessMessage $message): void
{
$schedule = $message->processSchedule;
- $context = array_merge(...array_map(fn ($ctx) => [$ctx['key'] => $ctx['value']], $schedule->getContext()));
+ $context = array_merge(...array_map(static fn ($ctx) => [$ctx['key'] => $ctx['value']], $schedule->getContext()));
$this->bus->dispatch(
new ProcessExecuteMessage($schedule->getProcess() ?? '', $schedule->getInput(), $context)
);
diff --git a/src/Message/ProcessExecuteHandler.php b/src/Message/ProcessExecuteHandler.php
index 3443541..a76c0e1 100644
--- a/src/Message/ProcessExecuteHandler.php
+++ b/src/Message/ProcessExecuteHandler.php
@@ -17,13 +17,10 @@
use CleverAge\UiProcessBundle\Monolog\Handler\ProcessHandler;
use Symfony\Component\Messenger\Attribute\AsMessageHandler;
-/**
- * PHP 8.2 : Replace by readonly class.
- */
#[AsMessageHandler]
-class ProcessExecuteHandler
+readonly class ProcessExecuteHandler
{
- public function __construct(private readonly ProcessManager $manager, private readonly ProcessHandler $processHandler)
+ public function __construct(private ProcessManager $manager, private ProcessHandler $processHandler)
{
}
diff --git a/src/Message/ProcessExecuteMessage.php b/src/Message/ProcessExecuteMessage.php
index 39c45bb..84fddb0 100644
--- a/src/Message/ProcessExecuteMessage.php
+++ b/src/Message/ProcessExecuteMessage.php
@@ -13,15 +13,12 @@
namespace CleverAge\UiProcessBundle\Message;
-/**
- * PHP 8.2 : Replace by readonly class.
- */
-class ProcessExecuteMessage
+readonly class ProcessExecuteMessage
{
/**
* @param mixed[] $context
*/
- public function __construct(public readonly string $code, public readonly mixed $input, public readonly array $context = [])
+ public function __construct(public string $code, public mixed $input, public array $context = [])
{
}
}
diff --git a/src/Monolog/Handler/ProcessHandler.php b/src/Monolog/Handler/ProcessHandler.php
index b1f94da..8ddcc6a 100644
--- a/src/Monolog/Handler/ProcessHandler.php
+++ b/src/Monolog/Handler/ProcessHandler.php
@@ -21,13 +21,15 @@
class ProcessHandler extends StreamHandler
{
private Level $reportIncrementLevel = Level::Error;
+ private bool $filenameSet = false;
public function __construct(
private readonly string $directory,
private readonly ProcessExecutionManager $processExecutionManager,
int|string|Level $level = Level::Debug,
) {
- parent::__construct($this->directory, $level);
+ // Initialize with php://memory as placeholder - actual file will be set via setFilename()
+ parent::__construct('php://memory', $level);
}
/**
@@ -40,27 +42,33 @@ public function setReportIncrementLevel(string $level): void
public function hasFilename(): bool
{
- return $this->directory !== $this->url;
+ return $this->filenameSet;
}
public function setFilename(string $filename): void
{
+ $this->close();
$this->url = \sprintf('%s/%s', $this->directory, $filename);
+ $this->filenameSet = true;
}
public function close(): void
{
- $this->url = $this->directory;
parent::close();
+ $this->filenameSet = false;
}
public function getFilename(): ?string
{
- return $this->url;
+ return $this->filenameSet ? $this->url : null;
}
- public function write(LogRecord $record): void
+ protected function write(LogRecord $record): void
{
+ if (!$this->filenameSet) {
+ // Skip writing if no filename has been set yet
+ return;
+ }
parent::write($record);
if ($record->level->value >= $this->reportIncrementLevel->value) {
$this->processExecutionManager->increment($record->level->name);
diff --git a/src/Scheduler/CronScheduler.php b/src/Scheduler/CronScheduler.php
index 48bc202..b12fd20 100644
--- a/src/Scheduler/CronScheduler.php
+++ b/src/Scheduler/CronScheduler.php
@@ -22,15 +22,12 @@
use Symfony\Component\Scheduler\ScheduleProviderInterface;
use Symfony\Component\Validator\Validator\ValidatorInterface;
-/**
- * PHP 8.2 : Replace by readonly class.
- */
-class CronScheduler implements ScheduleProviderInterface
+readonly class CronScheduler implements ScheduleProviderInterface
{
public function __construct(
- private readonly ProcessScheduleRepository $repository,
- private readonly ValidatorInterface $validator,
- private readonly LoggerInterface $logger,
+ private ProcessScheduleRepository $repository,
+ private ValidatorInterface $validator,
+ private LoggerInterface $logger,
) {
}
diff --git a/src/Security/HttpProcessExecutionAuthenticator.php b/src/Security/HttpProcessExecutionAuthenticator.php
index 85734f9..cfb91c9 100644
--- a/src/Security/HttpProcessExecutionAuthenticator.php
+++ b/src/Security/HttpProcessExecutionAuthenticator.php
@@ -34,7 +34,7 @@ public function __construct(private readonly EntityManagerInterface $entityManag
public function supports(Request $request): ?bool
{
- return 'http_process_execute' === $request->get('_route') && $request->isMethod(Request::METHOD_POST);
+ return 'http_process_execute' === $request->request->get('_route') && $request->isMethod(Request::METHOD_POST);
}
public function authenticate(Request $request): Passport
diff --git a/src/Twig/Runtime/ProcessExecutionExtensionRuntime.php b/src/Twig/Runtime/ProcessExecutionExtensionRuntime.php
index 90e4967..592f1e4 100644
--- a/src/Twig/Runtime/ProcessExecutionExtensionRuntime.php
+++ b/src/Twig/Runtime/ProcessExecutionExtensionRuntime.php
@@ -18,14 +18,11 @@
use CleverAge\UiProcessBundle\Repository\ProcessExecutionRepository;
use Twig\Extension\RuntimeExtensionInterface;
-/**
- * PHP 8.2 : Replace by readonly class.
- */
-class ProcessExecutionExtensionRuntime implements RuntimeExtensionInterface
+readonly class ProcessExecutionExtensionRuntime implements RuntimeExtensionInterface
{
public function __construct(
- private readonly ProcessExecutionRepository $processExecutionRepository,
- private readonly ProcessConfigurationsManager $processConfigurationsManager,
+ private ProcessExecutionRepository $processExecutionRepository,
+ private ProcessConfigurationsManager $processConfigurationsManager,
) {
}
diff --git a/templates/admin/process/launch.html.twig b/templates/admin/process/launch.html.twig
index 88d0f7b..7e4e560 100644
--- a/templates/admin/process/launch.html.twig
+++ b/templates/admin/process/launch.html.twig
@@ -1,5 +1,5 @@
-{% extends ea.templatePath('layout') %}
-{% trans_default_domain ea.i18n.translationDomain %}
+{% extends ea().templatePath('layout') %}
+{% trans_default_domain ea().i18n.translationDomain %}
{% block main %}
{% form_theme form '@EasyAdmin/crud/form_theme.html.twig' %}
diff --git a/templates/admin/process/list.html.twig b/templates/admin/process/list.html.twig
index 2a34372..6a1432c 100644
--- a/templates/admin/process/list.html.twig
+++ b/templates/admin/process/list.html.twig
@@ -1,6 +1,6 @@
{# @var urlGenerator \EasyCorp\Bundle\EasyAdminBundle\Router\AdminUrlGenerator #}
-{% extends ea.templatePath('layout') %}
-{% trans_default_domain ea.i18n.translationDomain %}
+{% extends ea().templatePath('layout') %}
+{% trans_default_domain ea().i18n.translationDomain %}
{% block content_title %}{{ 'Processes'|trans }}{% endblock %}