-
-
Notifications
You must be signed in to change notification settings - Fork 404
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feature #1487 [make:schedule] a new command for creating recurring Sy…
…mfony Schedules
- Loading branch information
Showing
9 changed files
with
368 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,140 @@ | ||
<?php | ||
|
||
/* | ||
* This file is part of the Symfony MakerBundle package. | ||
* | ||
* (c) Fabien Potencier <fabien@symfony.com> | ||
* | ||
* For the full copyright and license information, please view the LICENSE | ||
* file that was distributed with this source code. | ||
*/ | ||
|
||
namespace Symfony\Bundle\MakerBundle\Maker; | ||
|
||
use Symfony\Bundle\MakerBundle\ConsoleStyle; | ||
use Symfony\Bundle\MakerBundle\DependencyBuilder; | ||
use Symfony\Bundle\MakerBundle\FileManager; | ||
use Symfony\Bundle\MakerBundle\Generator; | ||
use Symfony\Bundle\MakerBundle\InputConfiguration; | ||
use Symfony\Bundle\MakerBundle\Str; | ||
use Symfony\Bundle\MakerBundle\Util\UseStatementGenerator; | ||
use Symfony\Component\Console\Command\Command; | ||
use Symfony\Component\Console\Input\InputInterface; | ||
use Symfony\Component\Finder\Finder; | ||
use Symfony\Component\Process\Process; | ||
use Symfony\Component\Scheduler\Attribute\AsSchedule; | ||
use Symfony\Component\Scheduler\RecurringMessage; | ||
use Symfony\Component\Scheduler\Schedule; | ||
use Symfony\Component\Scheduler\ScheduleProviderInterface; | ||
use Symfony\Contracts\Cache\CacheInterface; | ||
|
||
/** | ||
* @author Jesse Rushlow <jr@rushlow.dev> | ||
* | ||
* @internal | ||
*/ | ||
final class MakeSchedule extends AbstractMaker | ||
{ | ||
private string $scheduleName; | ||
private ?string $message = null; | ||
|
||
public function __construct( | ||
private FileManager $fileManager, | ||
private Finder $finder = new Finder(), | ||
) { | ||
} | ||
|
||
public static function getCommandName(): string | ||
{ | ||
return 'make:schedule'; | ||
} | ||
|
||
public static function getCommandDescription(): string | ||
{ | ||
return 'Create a scheduler component'; | ||
} | ||
|
||
public function configureCommand(Command $command, InputConfiguration $inputConfig): void | ||
{ | ||
$command | ||
->setHelp(file_get_contents(__DIR__.'/../Resources/help/MakeScheduler.txt')) | ||
; | ||
} | ||
|
||
public function interact(InputInterface $input, ConsoleStyle $io, Command $command): void | ||
{ | ||
if (!class_exists(AsSchedule::class)) { | ||
$io->writeln('Running composer require symfony/scheduler'); | ||
$process = Process::fromShellCommandline('composer require symfony/scheduler'); | ||
$process->run(); | ||
$io->writeln('Scheduler successfully installed!'); | ||
} | ||
|
||
// Loop over existing src/Message/* and ask which message the user would like to schedule | ||
$availableMessages = ['Empty Schedule']; | ||
$messageDir = $this->fileManager->getRootDirectory().'/src/Message'; | ||
|
||
if ($this->fileManager->fileExists($messageDir)) { | ||
$finder = $this->finder->in($this->fileManager->getRootDirectory().'/src/Message'); | ||
|
||
foreach ($finder->files() as $file) { | ||
$availableMessages[] = $file->getFilenameWithoutExtension(); | ||
} | ||
} | ||
|
||
$scheduleNameHint = 'MainSchedule'; | ||
|
||
// If the count is 1, no other messages were found - don't ask to create a message | ||
if (1 !== \count($availableMessages)) { | ||
$selectedMessage = $io->choice('Select which message', $availableMessages); | ||
|
||
if ('Empty Schedule' !== $selectedMessage) { | ||
$this->message = $selectedMessage; | ||
|
||
// We don't want SomeMessageSchedule, so remove the "Message" suffix to give us SomeSchedule | ||
$scheduleNameHint = sprintf('%sSchedule', Str::removeSuffix($selectedMessage, 'Message')); | ||
} | ||
} | ||
|
||
// Ask the name of the new schedule | ||
$this->scheduleName = $io->ask(question: 'What should we call the new schedule?', default: $scheduleNameHint); | ||
} | ||
|
||
public function generate(InputInterface $input, ConsoleStyle $io, Generator $generator): void | ||
{ | ||
$scheduleClassDetails = $generator->createClassNameDetails( | ||
$this->scheduleName, | ||
'Scheduler\\', | ||
); | ||
|
||
$useStatements = new UseStatementGenerator([ | ||
AsSchedule::class, | ||
RecurringMessage::class, | ||
Schedule::class, | ||
ScheduleProviderInterface::class, | ||
CacheInterface::class, | ||
]); | ||
|
||
if (null !== $this->message) { | ||
$useStatements->addUseStatement('App\\Message\\'.$this->message); | ||
} | ||
|
||
$generator->generateClass( | ||
$scheduleClassDetails->getFullName(), | ||
'scheduler/Schedule.tpl.php', | ||
[ | ||
'use_statements' => $useStatements, | ||
'has_custom_message' => null !== $this->message, | ||
'message_class_name' => $this->message, | ||
], | ||
); | ||
|
||
$generator->writeChanges(); | ||
|
||
$this->writeSuccessMessage($io); | ||
} | ||
|
||
public function configureDependencies(DependencyBuilder $dependencies): void | ||
{ | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
The <info>%command.name%</info> command generates a schedule to automate repeated | ||
tasks using Symfony's Scheduler Component. | ||
|
||
If the Scheduler Component is not installed, <info>%command.name%</info> will | ||
install it automatically using composer. You can of course do this manually by | ||
running <info>composer require symfony/scheduler</info>. | ||
|
||
<info>php %command.full_name%</info> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
<?= "<?php\n" ?> | ||
|
||
namespace <?= $namespace; ?>; | ||
|
||
<?= $use_statements; ?> | ||
|
||
#[AsSchedule] | ||
final class <?= $class_name; ?> implements ScheduleProviderInterface | ||
{ | ||
public function __construct( | ||
private CacheInterface $cache, | ||
) { | ||
} | ||
|
||
public function getSchedule(): Schedule | ||
{ | ||
return (new Schedule()) | ||
->add( | ||
<?php if ($has_custom_message): ?> | ||
// @TODO - Modify the frequency to suite your needs | ||
RecurringMessage::every('1 hour', new <?= $message_class_name; ?>()), | ||
<?php else: ?> | ||
// @TODO - Create a Message to schedule | ||
// RecurringMessage::every('1 hour', new App\Message\Message()), | ||
<?php endif ?> | ||
) | ||
->stateful($this->cache) | ||
; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,86 @@ | ||
<?php | ||
|
||
/* | ||
* This file is part of the Symfony MakerBundle package. | ||
* | ||
* (c) Fabien Potencier <fabien@symfony.com> | ||
* | ||
* For the full copyright and license information, please view the LICENSE | ||
* file that was distributed with this source code. | ||
*/ | ||
|
||
namespace Symfony\Bundle\MakerBundle\Tests\Maker; | ||
|
||
use Symfony\Bundle\MakerBundle\Maker\MakeSchedule; | ||
use Symfony\Bundle\MakerBundle\Test\MakerTestCase; | ||
use Symfony\Bundle\MakerBundle\Test\MakerTestRunner; | ||
|
||
class MakeScheduleTest extends MakerTestCase | ||
{ | ||
protected function getMakerClass(): string | ||
{ | ||
return MakeSchedule::class; | ||
} | ||
|
||
public function getTestDetails(): \Generator | ||
{ | ||
yield 'it_generates_a_schedule' => [$this->createMakerTest() | ||
->run(function (MakerTestRunner $runner) { | ||
$output = $runner->runMaker([ | ||
'', // use default schedule name "MainSchedule" | ||
]); | ||
|
||
$this->assertStringContainsString('Success', $output); | ||
|
||
self::assertFileEquals( | ||
\dirname(__DIR__).'/fixtures/make-schedule/expected/DefaultScheduleEmpty.php', | ||
$runner->getPath('src/Scheduler/MainSchedule.php') | ||
); | ||
}), | ||
]; | ||
|
||
yield 'it_generates_a_schedule_select_empty' => [$this->createMakerTest() | ||
->preRun(function (MakerTestRunner $runner) { | ||
$runner->copy( | ||
'make-schedule/standard_setup', | ||
'' | ||
); | ||
}) | ||
->run(function (MakerTestRunner $runner) { | ||
$output = $runner->runMaker([ | ||
0, // Select "Empty Schedule" | ||
'MySchedule', // Go with the default name "MainSchedule" | ||
]); | ||
|
||
$this->assertStringContainsString('Success', $output); | ||
|
||
self::assertFileEquals( | ||
\dirname(__DIR__).'/fixtures/make-schedule/expected/MyScheduleEmpty.php', | ||
$runner->getPath('src/Scheduler/MySchedule.php') | ||
); | ||
}), | ||
]; | ||
|
||
yield 'it_generates_a_schedule_select_existing_message' => [$this->createMakerTest() | ||
->preRun(function (MakerTestRunner $runner) { | ||
$runner->copy( | ||
'make-schedule/standard_setup', | ||
'' | ||
); | ||
}) | ||
->run(function (MakerTestRunner $runner) { | ||
$output = $runner->runMaker([ | ||
1, // Select "MyMessage" from choice | ||
'', // Go with the default name "MessageFixtureSchedule" | ||
]); | ||
|
||
$this->assertStringContainsString('Success', $output); | ||
|
||
self::assertFileEquals( | ||
\dirname(__DIR__).'/fixtures/make-schedule/expected/MyScheduleWithMessage.php', | ||
$runner->getPath('src/Scheduler/MessageFixtureSchedule.php') | ||
); | ||
}), | ||
]; | ||
} | ||
} |
29 changes: 29 additions & 0 deletions
29
tests/fixtures/make-schedule/expected/DefaultScheduleEmpty.php
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
<?php | ||
|
||
namespace App\Scheduler; | ||
|
||
use Symfony\Component\Scheduler\Attribute\AsSchedule; | ||
use Symfony\Component\Scheduler\RecurringMessage; | ||
use Symfony\Component\Scheduler\Schedule; | ||
use Symfony\Component\Scheduler\ScheduleProviderInterface; | ||
use Symfony\Contracts\Cache\CacheInterface; | ||
|
||
#[AsSchedule] | ||
final class MainSchedule implements ScheduleProviderInterface | ||
{ | ||
public function __construct( | ||
private CacheInterface $cache, | ||
) { | ||
} | ||
|
||
public function getSchedule(): Schedule | ||
{ | ||
return (new Schedule()) | ||
->add( | ||
// @TODO - Create a Message to schedule | ||
// RecurringMessage::every('1 hour', new App\Message\Message()), | ||
) | ||
->stateful($this->cache) | ||
; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
<?php | ||
|
||
namespace App\Scheduler; | ||
|
||
use Symfony\Component\Scheduler\Attribute\AsSchedule; | ||
use Symfony\Component\Scheduler\RecurringMessage; | ||
use Symfony\Component\Scheduler\Schedule; | ||
use Symfony\Component\Scheduler\ScheduleProviderInterface; | ||
use Symfony\Contracts\Cache\CacheInterface; | ||
|
||
#[AsSchedule] | ||
final class MySchedule implements ScheduleProviderInterface | ||
{ | ||
public function __construct( | ||
private CacheInterface $cache, | ||
) { | ||
} | ||
|
||
public function getSchedule(): Schedule | ||
{ | ||
return (new Schedule()) | ||
->add( | ||
// @TODO - Create a Message to schedule | ||
// RecurringMessage::every('1 hour', new App\Message\Message()), | ||
) | ||
->stateful($this->cache) | ||
; | ||
} | ||
} |
30 changes: 30 additions & 0 deletions
30
tests/fixtures/make-schedule/expected/MyScheduleWithMessage.php
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
<?php | ||
|
||
namespace App\Scheduler; | ||
|
||
use App\Message\MessageFixture; | ||
use Symfony\Component\Scheduler\Attribute\AsSchedule; | ||
use Symfony\Component\Scheduler\RecurringMessage; | ||
use Symfony\Component\Scheduler\Schedule; | ||
use Symfony\Component\Scheduler\ScheduleProviderInterface; | ||
use Symfony\Contracts\Cache\CacheInterface; | ||
|
||
#[AsSchedule] | ||
final class MessageFixtureSchedule implements ScheduleProviderInterface | ||
{ | ||
public function __construct( | ||
private CacheInterface $cache, | ||
) { | ||
} | ||
|
||
public function getSchedule(): Schedule | ||
{ | ||
return (new Schedule()) | ||
->add( | ||
// @TODO - Modify the frequency to suite your needs | ||
RecurringMessage::every('1 hour', new MessageFixture()), | ||
) | ||
->stateful($this->cache) | ||
; | ||
} | ||
} |
11 changes: 11 additions & 0 deletions
11
tests/fixtures/make-schedule/standard_setup/src/Message/MessageFixture.php
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
<?php | ||
|
||
namespace App\Message; | ||
|
||
final class MessageFixture | ||
{ | ||
public function __construct( | ||
public string $message = 'Howdy!', | ||
) { | ||
} | ||
} |