From d10f9694f1b8963c06687bd9ac85cf05953e1bbd Mon Sep 17 00:00:00 2001 From: ignace nyamagana butera Date: Fri, 14 Jan 2022 16:33:48 +0100 Subject: [PATCH] Adding Registering alias feature to the package (#132) --- src/Cron/CronExpression.php | 74 ++++++++++++++++++++++++++++++- tests/Cron/CronExpressionTest.php | 57 ++++++++++++++++++++++++ 2 files changed, 130 insertions(+), 1 deletion(-) diff --git a/src/Cron/CronExpression.php b/src/Cron/CronExpression.php index fa2acf1a..b13f3d48 100644 --- a/src/Cron/CronExpression.php +++ b/src/Cron/CronExpression.php @@ -10,6 +10,7 @@ use DateTimeZone; use Exception; use InvalidArgumentException; +use LogicException; use RuntimeException; use Webmozart\Assert\Assert; @@ -73,6 +74,77 @@ class CronExpression self::MINUTE, ]; + /** + * @var array + */ + private static $registeredAliases = self::MAPPINGS; + + /** + * Registered a user defined CRON Expression Alias. + * + * @throws LogicException If the expression or the alias name are invalid + * or if the alias is already registered. + */ + public static function registerAlias(string $alias, string $expression): void + { + try { + new self($expression); + } catch (InvalidArgumentException $exception) { + throw new LogicException("The expression `$expression` is invalid", 0, $exception); + } + + $shortcut = strtolower($alias); + if (1 !== preg_match('/^@\w+$/', $shortcut)) { + throw new LogicException("The alias `$alias` is invalid. It must start with an `@` character and contain alphanumeric (letters, numbers, regardless of case) plus underscore (_)."); + } + + if (isset(self::$registeredAliases[$shortcut])) { + throw new LogicException("The alias `$alias` is already registered."); + } + + self::$registeredAliases[$shortcut] = $expression; + } + + /** + * Unregistered a user defined CRON Expression Alias. + * + * @throws LogicException If the user tries to unregister a built-in alias + */ + public static function unregisterAlias(string $alias): bool + { + $shortcut = strtolower($alias); + if (isset(self::MAPPINGS[$shortcut])) { + throw new LogicException("The alias `$alias` is a built-in alias; it can not be unregistered."); + } + + if (!isset(self::$registeredAliases[$shortcut])) { + return false; + } + + unset(self::$registeredAliases[$shortcut]); + + return true; + } + + /** + * Tells whether a CRON Expression alias is registered. + */ + public static function supportsAlias(string $alias): bool + { + return isset(self::$registeredAliases[strtolower($alias)]); + } + + /** + * Returns all registered aliases as an associated array where the aliases are the key + * and their associated expressions are the values. + * + * @return array + */ + public static function getAliases(): array + { + return self::$registeredAliases; + } + /** * @deprecated since version 3.0.2, use __construct instead. */ @@ -109,7 +181,7 @@ public static function isValidExpression(string $expression): bool public function __construct(string $expression, FieldFactoryInterface $fieldFactory = null) { $shortcut = strtolower($expression); - $expression = self::MAPPINGS[$shortcut] ?? $expression; + $expression = self::$registeredAliases[$shortcut] ?? $expression; $this->fieldFactory = $fieldFactory ?: new FieldFactory(); $this->setExpression($expression); diff --git a/tests/Cron/CronExpressionTest.php b/tests/Cron/CronExpressionTest.php index 61be75cf..6036c1d1 100644 --- a/tests/Cron/CronExpressionTest.php +++ b/tests/Cron/CronExpressionTest.php @@ -10,6 +10,7 @@ use DateTimeImmutable; use DateTimeZone; use InvalidArgumentException; +use LogicException; use PHPUnit\Framework\TestCase; use Webmozart\Assert\Assert; @@ -724,4 +725,60 @@ public function testIssue128() $prev = $e->getPreviousRunDate(new \DateTime('2022-08-20 03:44:02'), 1); $this->assertEquals($expected, $prev); } + + public function testItCanRegisterAnValidExpression(): void + { + CronExpression::registerAlias('@every', '* * * * *'); + + self::assertCount(8, CronExpression::getAliases()); + self::assertArrayHasKey('@every', CronExpression::getAliases()); + self::assertTrue(CronExpression::supportsAlias('@every')); + self::assertEquals(new CronExpression('@every'), new CronExpression('* * * * *')); + + self::assertTrue(CronExpression::unregisterAlias('@every')); + self::assertFalse(CronExpression::unregisterAlias('@every')); + + self::assertCount(7, CronExpression::getAliases()); + self::assertArrayNotHasKey('@every', CronExpression::getAliases()); + self::assertFalse(CronExpression::supportsAlias('@every')); + + $this->expectException(LogicException::class); + new CronExpression('@every'); + } + + public function testItWillFailToRegisterAnInvalidExpression(): void + { + $this->expectException(LogicException::class); + + CronExpression::registerAlias('@every', 'foobar'); + } + + public function testItWillFailToRegisterAnInvalidName(): void + { + $this->expectException(LogicException::class); + + CronExpression::registerAlias('every', '* * * * *'); + } + + public function testItWillFailToRegisterAnInvalidName2(): void + { + $this->expectException(LogicException::class); + + CronExpression::registerAlias('@évery', '* * * * *'); + } + + public function testItWillFailToRegisterAValidNameTwice(): void + { + CronExpression::registerAlias('@Ev_eR_y', '* * * * *'); + + $this->expectException(LogicException::class); + CronExpression::registerAlias('@eV_Er_Y', '2 2 2 2 2'); + } + + public function testItWillFailToUnregisterADefaultExpression(): void + { + $this->expectException(LogicException::class); + + CronExpression::unregisterAlias('@daily'); + } }