diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index e5f2867..adb237b 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -21,14 +21,17 @@ jobs: - php-version: 8.0 symfony-version: 5.4.* stability: prefer-stable - - php-version: 8.0 - symfony-version: 6.0.* - stability: prefer-stable - php-version: 8.1 - symfony-version: 6.2.* + symfony-version: 6.4.* stability: prefer-stable - php-version: 8.2 - symfony-version: 6.2.* + symfony-version: 6.4.* + stability: prefer-stable + - php-version: 8.3 + symfony-version: 6.4.* + stability: prefer-stable + - php-version: 8.3 + symfony-version: 7.0.* stability: prefer-stable name: PHP ${{ matrix.php-version }} Test with Symfony ${{ matrix.symfony-version }} and ${{ matrix.stability }} diff --git a/Annotation/Cron.php b/Annotation/Cron.php index 0357531..c997d8b 100644 --- a/Annotation/Cron.php +++ b/Annotation/Cron.php @@ -2,15 +2,19 @@ namespace MyBuilder\Bundle\CronosBundle\Annotation; +use Attribute; use Doctrine\Common\Annotations\Annotation; +use Doctrine\Common\Annotations\Annotation\NamedArgumentConstructor; /** * Cron annotation which we can parse to generate a cron file * * @Annotation + * @NamedArgumentConstructor() * @Target("CLASS") */ -class Cron extends Annotation +#[Attribute(Attribute::IS_REPEATABLE | Attribute::TARGET_CLASS)] +class Cron { public string $minute; public string $hour; @@ -29,4 +33,29 @@ class Cron extends Annotation public ?string $params = null; public ?string $executor = null; + + public function __construct(string $minute, + string $hour, + ?string $server, + ?string $dayOfMonth = null, + ?string $dayOfWeek = null, + ?string $comment = null, + ?string $logFile = null, + ?string $errorFile = null, + ?bool $noLogs = null, + ?string $params = null, + ?string $executor = null) + { + $this->minute = $minute; + $this->hour = $hour; + $this->server = $server; + $this->dayOfMonth = $dayOfMonth; + $this->dayOfWeek = $dayOfWeek; + $this->comment = $comment; + $this->logFile = $logFile; + $this->errorFile = $errorFile; + $this->noLogs = $noLogs; + $this->params = $params; + $this->executor = $executor; + } } diff --git a/Command/CommandBase.php b/Command/CommandBase.php index c649e6e..f6b4599 100644 --- a/Command/CommandBase.php +++ b/Command/CommandBase.php @@ -8,13 +8,14 @@ use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Input\InputOption; use Symfony\Component\Console\Output\OutputInterface; -use Symfony\Component\DependencyInjection\ContainerAwareInterface; -use Symfony\Component\DependencyInjection\ContainerAwareTrait; use Symfony\Component\DependencyInjection\ContainerInterface; -class CommandBase extends Command implements ContainerAwareInterface +class CommandBase extends Command { - use ContainerAwareTrait; + public function __construct(private ContainerInterface $container) + { + parent::__construct(); + } protected function addServerOption(): void { @@ -36,31 +37,12 @@ protected function configureCronExport(InputInterface $input, OutputInterface $o return $cron; } - /** @throws \LogicException */ - protected function getContainer(): ContainerInterface - { - if (null === $this->container) { - $application = $this->getApplication(); - - if (null === $application) { - throw new \LogicException('The container cannot be retrieved as the application instance is not yet set.'); - } - - $this->container = $application->getKernel()->getContainer(); - - if (null === $this->container) { - throw new \LogicException('The container cannot be retrieved as the kernel has shut down.'); - } - } - - return $this->container; - } - private function exportCron($options): Cron { $commands = $this->getApplication()->all(); + /** @var AnnotationCronExporter $exporter */ - $exporter = $this->getContainer()->get('mybuilder.cronos_bundle.annotation_cron_exporter'); + $exporter = $this->container->get('mybuilder.cronos_bundle.annotation_cron_exporter'); return $exporter->export($commands, $options); } diff --git a/Exporter/AnnotationCronExporter.php b/Exporter/AnnotationCronExporter.php index 82e3bff..ca3dad1 100644 --- a/Exporter/AnnotationCronExporter.php +++ b/Exporter/AnnotationCronExporter.php @@ -60,7 +60,7 @@ private function parseAnnotations(CronFormatter $cron, Command $command, array $ return $cron; } - private function annotationBelongsToServer(Annotation $annotation, string $serverName): bool + private function annotationBelongsToServer($annotation, string $serverName): bool { return $annotation instanceof CronAnnotation diff --git a/README.md b/README.md index 4eaa516..1bdd02b 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # Cronos Bundle -A bundle for Symfony 4/5/6 that allows you to use `@Cron` annotations to configure when cron should run your console commands. +A bundle for Symfony 4/5/6/7 that allows you to use `@Cron` annotations or `#[Cron]` attribute to configure when cron should run your console commands. Uses the [Cronos](https://github.com/mybuilder/cronos) library to do the actual output and updating. @@ -16,7 +16,7 @@ $ composer require mybuilder/cronos-bundle ### Enable the bundle -If you do not use Symfony Flex, enable the bundle in the `config/bundles.php` for Symfony 4/5/6: +If you do not use Symfony Flex, enable the bundle in the `config/bundles.php` for Symfony 4/5/6/7: ```php return [ @@ -62,9 +62,10 @@ This example says it should be run on the web server, every 5 minutes, and we do ```php /** * Command for sending our email messages from the database. - * + * * @Cron(minute="/5", noLogs=true, server="web") */ +#[Cron(minute: "/5", noLogs: true, server: "web") class SendQueuedEmailsCommand extends Command {} ``` @@ -76,17 +77,17 @@ You should read the [general cron info](https://en.wikipedia.org/wiki/Cron) for **Please note** You CANNOT use `*/` in the annotations, if you want `*/5` just put `/5` and [Cronos](https://github.com/mybuilder/cronos) will automatically change it to `*/5`. -### Annotation examples - -| annotation | description | -|----------------------------------------------------------|-------------------------------------------| -| `@Cron(minute="/5")` | Every 5 minutes | -| `@Cron(minute="5")` | At the 5th minute of each hour | -| `@Cron(minute="5", hour="8")` | 5 minutes past 8am every day | -| `@Cron(minute="5", hour="8", dayOfWeek="0")` | 5 minutes past 8am every Sunday | -| `@Cron(minute="5", hour="8", dayOfMonth="1")` | 5 minutes past 8am on first of each month | -| `@Cron(minute="5", hour="8", dayOfMonth="1", month="1")` | 5 minutes past 8am on first of of January | -| `@Cron(minute="/5", params="--user=barman")` | Every 5 minutes, with a custom param | +### Attributes examples + +| attribute | description | +|----------------------------------------------------------------|-------------------------------------------| +| `#[Cron(minute: "/5")]` | Every 5 minutes | +| `#[Cron(minute: "5")]` | At the 5th minute of each hour | +| `#[Cron(minute: "5", hour: "8")]` | 5 minutes past 8am every day | +| `#[Cron(minute: "5", hour: "8", dayOfWeek: "0")]` | 5 minutes past 8am every Sunday | +| `#[Cron(minute: "5", hour: "8", dayOfMonth: "1")]` | 5 minutes past 8am on first of each month | +| `#[Cron(minute: "5", hour: "8", dayOfMonth: "1", month: "1")]` | 5 minutes past 8am on first of of January | +| `#[Cron(minute: "/5", params: "--user=barman")]` | Every 5 minutes, with a custom param | ## Building the cron diff --git a/Tests/Command/DumpCommandTest.php b/Tests/Command/DumpCommandTest.php index a40a467..c367ebd 100644 --- a/Tests/Command/DumpCommandTest.php +++ b/Tests/Command/DumpCommandTest.php @@ -21,8 +21,8 @@ protected function setUp(): void $application = new Application($kernel); - $application->add(new DumpCommand()); - $application->add(new ReplaceCommand()); + $application->add(new DumpCommand(self::getContainer())); + $application->add(new ReplaceCommand(self::getContainer())); $application->add(new TestCommand()); $this->command = $application->find('cronos:dump'); diff --git a/Tests/Fixtures/Command/TestCommand.php b/Tests/Fixtures/Command/TestCommand.php index efdae9d..72d6e16 100644 --- a/Tests/Fixtures/Command/TestCommand.php +++ b/Tests/Fixtures/Command/TestCommand.php @@ -12,6 +12,9 @@ * @Cron(minute="/5", hour="/3", server="batch") * @Cron(minute="41", hour="10", dayOfMonth="1", server="test", executor="php -d mbstring.func_overload=0") */ +#[Cron(minute: "27", hour: "0", dayOfWeek: "6", server: "web")] +#[Cron(minute: "/5", hour: "/3", server: "batch")] +#[Cron(minute: "41", hour: "10", dayOfMonth: "1", server: "test", executor: "php -d mbstring.func_overload=0")] class TestCommand extends Command { protected function configure(): void diff --git a/Tests/Fixtures/app/config/test.yml b/Tests/Fixtures/app/config/test.yml index 949e790..4d1055a 100644 --- a/Tests/Fixtures/app/config/test.yml +++ b/Tests/Fixtures/app/config/test.yml @@ -1,5 +1,6 @@ framework: secret: asdgsgr + test: true my_builder_cronos: exporter: diff --git a/composer.json b/composer.json index f78aef0..155dbea 100644 --- a/composer.json +++ b/composer.json @@ -18,14 +18,14 @@ "require": { "php": ">=8.0.2", "mybuilder/cronos": "^3.0 || ^4.0", - "doctrine/annotations": "^1.11", - "symfony/console": "^4.4.20 || ^5.4 || ^6.0", - "symfony/config": "^4.4.20 || ^5.4 || ^6.0", - "symfony/dependency-injection": "^4.4.20 || ^5.4 || ^6.0", - "symfony/framework-bundle": "^4.4.20 || ^5.4 || ^6.0", - "symfony/http-kernel": "^4.4.20 || ^5.4 || ^6.0", - "symfony/property-access": "^4.4.20 || ^5.4 || ^6.0", - "symfony/yaml": "^4.4.20 || ^5.4 || ^6.0" + "doctrine/annotations": "^2.0", + "symfony/console": "^4.4.20 || ^5.4 || ^6.0 || ^7.0", + "symfony/config": "^4.4.20 || ^5.4 || ^6.0 || ^7.0", + "symfony/dependency-injection": "^4.4.20 || ^5.4 || ^6.0 || ^7.0", + "symfony/framework-bundle": "^4.4.20 || ^5.4 || ^6.0 || ^7.0", + "symfony/http-kernel": "^4.4.20 || ^5.4 || ^6. || ^7.00", + "symfony/property-access": "^4.4.20 || ^5.4 || ^6.0 || ^7.0", + "symfony/yaml": "^4.4.20 || ^5.4 || ^6.0 || ^7.0" }, "require-dev": { "phpunit/phpunit": "^9.5.27"