Include task scheduler in core

This commit is contained in:
Alexander Skvortsov 2021-03-16 23:04:08 -04:00 committed by Alexander Skvortsov
parent 7a2dbf8f9b
commit 512b756804
7 changed files with 157 additions and 5 deletions

View File

@ -25,10 +25,12 @@
"components/font-awesome": "^5.14.0",
"dflydev/fig-cookies": "^3.0.0",
"doctrine/dbal": "^2.7",
"dragonmantank/cron-expression": "^3.1.0",
"franzl/whoops-middleware": "^2.0.0",
"illuminate/bus": "^8.0",
"illuminate/cache": "^8.0",
"illuminate/config": "^8.0",
"illuminate/console": "^8.0",
"illuminate/container": "^8.0",
"illuminate/contracts": "^8.0",
"illuminate/database": "^8.0",

View File

@ -14,6 +14,9 @@ use Flarum\Database\Console\ResetCommand;
use Flarum\Foundation\AbstractServiceProvider;
use Flarum\Foundation\Console\CacheClearCommand;
use Flarum\Foundation\Console\InfoCommand;
use Illuminate\Console\Scheduling\Schedule as LaravelSchedule;
use Illuminate\Console\Scheduling\ScheduleListCommand;
use Illuminate\Console\Scheduling\ScheduleRunCommand;
class ConsoleServiceProvider extends AbstractServiceProvider
{
@ -22,13 +25,42 @@ class ConsoleServiceProvider extends AbstractServiceProvider
*/
public function register()
{
// Used by Laravel to proxy artisan commands to its binary.
// Flarum uses a similar binary, but it's called flarum.
if (! defined('ARTISAN_BINARY')) {
define('ARTISAN_BINARY', 'flarum');
}
$this->container->singleton(LaravelSchedule::class, function () {
return $this->container->make(Schedule::class);
});
$this->container->singleton('flarum.console.commands', function () {
return [
CacheClearCommand::class,
InfoCommand::class,
MigrateCommand::class,
ResetCommand::class,
ScheduleListCommand::class,
ScheduleRunCommand::class
];
});
$this->container->singleton('flarum.console.scheduled', function () {
return [];
});
}
/**
* {@inheritDoc}
*/
public function boot()
{
$schedule = $this->container->make(LaravelSchedule::class);
foreach ($this->container->make('flarum.console.scheduled') as $scheduled) {
$event = $schedule->command($scheduled['command'], $scheduled['args']);
$scheduled['callback']($event);
}
}
}

View File

@ -0,0 +1,40 @@
<?php
/*
* This file is part of Flarum.
*
* For detailed copyright and license information, please view the
* LICENSE file that was distributed with this source code.
*/
namespace Flarum\Console;
use Flarum\Foundation\Config;
use Illuminate\Console\Scheduling\Schedule as LaravelSchedule;
use Illuminate\Support\Collection;
class Schedule extends LaravelSchedule
{
public function dueEvents($container)
{
return (new Collection($this->events))->filter->isDue(new FakeApp($container));
}
}
class FakeApp
{
public function __construct($container)
{
$this->config = $container->make(Config::class);
}
public function isDownForMaintenance()
{
return $this->config->inMaintenanceMode();
}
public function environment()
{
return '';
}
}

View File

@ -15,6 +15,7 @@ use Illuminate\Contracts\Container\Container;
class Console implements ExtenderInterface
{
protected $addCommands = [];
protected $scheduled = [];
/**
* Add a command to the console.
@ -28,10 +29,38 @@ class Console implements ExtenderInterface
return $this;
}
/**
* Schedule a command to run on an interval.
*
* @param string $command ::class attribute of command class, which must extend Flarum\Console\AbstractCommand
* @param callable|string $callback
*
* The callback can be a closure or invokable class, and should accept:
* - \Illuminate\Console\Scheduling\Event $event
*
* The callback should apply relevant methods to $event, and does not need to return anything.
*
* @see https://laravel.com/api/8.x/Illuminate/Console/Scheduling/Event.html
* @see https://laravel.com/docs/8.x/scheduling#schedule-frequency-options
* for more information on available methods and what they do.
*
* @param array $args An array of args to call the command with.
*/
public function schedule(string $command, $callback, $args = [])
{
$this->scheduled[] = compact('args', 'callback', 'command');
return $this;
}
public function extend(Container $container, Extension $extension = null)
{
$container->extend('flarum.console.commands', function ($existingCommands) {
return array_merge($existingCommands, $this->addCommands);
});
$container->extend('flarum.console.scheduled', function ($existingScheduled) {
return array_merge($existingScheduled, $this->scheduled);
});
}
}

View File

@ -14,6 +14,7 @@ use Flarum\Foundation\Config;
use Flarum\Foundation\ErrorHandling\Registry;
use Flarum\Foundation\ErrorHandling\Reporter;
use Flarum\Foundation\Paths;
use Illuminate\Contracts\Cache\Factory as CacheFactory;
use Illuminate\Contracts\Debug\ExceptionHandler as ExceptionHandling;
use Illuminate\Contracts\Queue\Factory;
use Illuminate\Contracts\Queue\Queue;
@ -82,7 +83,7 @@ class QueueServiceProvider extends AbstractServiceProvider
// Bind a simple cache manager that returns the cache store.
$this->container->singleton('cache', function ($container) {
return new class($container) {
return new class($container) implements CacheFactory {
public function __construct($container)
{
$this->container = $container;
@ -93,6 +94,13 @@ class QueueServiceProvider extends AbstractServiceProvider
return $this->container['cache.store'];
}
// We have to define this explicitly
// so that we implement the interface.
public function store($name = null)
{
return $this->__call($name, null);
}
public function __call($name, $arguments)
{
return call_user_func_array([$this->driver(), $name], $arguments);

View File

@ -9,6 +9,7 @@
use Flarum\Foundation\Paths;
use Illuminate\Container\Container;
use Illuminate\Contracts\Config\Repository;
if (! function_exists('resolve')) {
/**
@ -24,7 +25,6 @@ if (! function_exists('resolve')) {
}
}
// The following are all deprecated perpetually.
// They are needed by some laravel components we use (e.g. task scheduling)
// They should NOT be used in extension code.
@ -47,7 +47,7 @@ if (! function_exists('app')) {
}
}
if (!function_exists('base_path')) {
if (! function_exists('base_path')) {
/**
* @deprecated perpetually.
*
@ -62,7 +62,7 @@ if (!function_exists('base_path')) {
}
}
if (!function_exists('public_path')) {
if (! function_exists('public_path')) {
/**
* @deprecated perpetually.
*
@ -77,7 +77,7 @@ if (!function_exists('public_path')) {
}
}
if (!function_exists('storage_path')) {
if (! function_exists('storage_path')) {
/**
* @deprecated perpetually.
*
@ -108,3 +108,13 @@ if (! function_exists('event')) {
return resolve('events')->dispatch($event, $payload, $halt);
}
}
if (! function_exists('config')) {
/**
* @deprecated do not use, will be transferred to flarum/laravel-helpers.
*/
function config(string $key, $default = null)
{
return resolve(Repository::class)->get($key, $default);
}
}

View File

@ -43,6 +43,37 @@ class ConsoleTest extends ConsoleTestCase
$this->assertEquals('Custom Command.', $this->runCommand($input));
}
/**
* @test
*/
public function scheduled_command_doesnt_exist_by_default()
{
$input = [
'command' => 'schedule:list'
];
$this->assertStringNotContainsString('cache:clear', $this->runCommand($input));
}
/**
* @test
*/
public function scheduled_command_exists_when_added()
{
$this->extend(
(new Extend\Console())
->schedule('cache:clear', function ($event) {
$event->everyMinute();
})
);
$input = [
'command' => 'schedule:list'
];
$this->assertStringContainsString('cache:clear', $this->runCommand($input));
}
}
class CustomCommand extends AbstractCommand