Skip to content

Commit

Permalink
Implemented a basic scheduler for managing crontab and repeating task…
Browse files Browse the repository at this point in the history
…s on the server
  • Loading branch information
reinvanoyen committed Jul 9, 2020
1 parent a6b29be commit 4a09c48
Show file tree
Hide file tree
Showing 12 changed files with 486 additions and 82 deletions.
3 changes: 2 additions & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@
"nyholm/psr7-server": "dev-master",
"psr/http-server-handler": "^1.0@dev",
"psr/http-server-middleware": "^1.0@dev",
"vlucas/phpdotenv": "^4.1@dev"
"vlucas/phpdotenv": "^4.1@dev",
"dragonmantank/cron-expression": "dev-master"
},
"autoload": {
"psr-4": {
Expand Down
69 changes: 1 addition & 68 deletions src/Console/Input/ConsoleInput.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,16 +11,6 @@
*/
class ConsoleInput extends Input
{
/**
* @var array $rawArguments
*/
private $rawArguments = [];

/**
* @var array $missingArguments
*/
private $missingArguments = [];

/**
* @param Signature $signature
*/
Expand Down Expand Up @@ -52,64 +42,7 @@ private function parse()

array_shift($this->rawArguments);

// First we check if any subcommand was requested
if (isset($this->rawArguments[0])) {
foreach ($this->getSignature()->getSubCommands() as $command) {
if ($this->rawArguments[0] === $command->getName()) {
$this->setSubCommand($command->getName());
break;
}
}
}

// Then we parse out the options
foreach ($this->getSignature()->getOptions() as $option) {

$definitions = [
'-'.$option->getName(),
'--'.$option->getName(),
];

if ($alias = $option->getAlias()) {
$definitions[] = '-'.$alias;
$definitions[] = '--'.$alias;
}

foreach ($definitions as $definition) {
$optionPosition = array_search($definition, $this->rawArguments);

if ($optionPosition !== false) {

// We found the option in the list of given arguments
if (
isset($this->rawArguments[$optionPosition + 1]) &&
substr($this->rawArguments[$optionPosition + 1], 0, strlen('-')) !== '-'
) {
// We also found a value for the option
// We remove the value of the option from the argument list
$optionValue = $this->rawArguments[$optionPosition + 1];
$this->setOption($option->getName(), $optionValue);
array_splice($this->rawArguments, $optionPosition + 1, 1);

} else {

$this->setOption($option->getName(), $option->getDefault());
}

array_splice($this->rawArguments, $optionPosition, 1);
break;
}
}
}

// Now we loop all arguments and make sure they are present
foreach ($this->getSignature()->getArguments() as $position => $argument) {
if (isset($this->rawArguments[$position])) {
$this->setArgument($argument->getName(), $this->rawArguments[$position]);
} else {
$this->missingArguments[] = $argument->getName();
}
}
$this->parseRawArguments();
}

/**
Expand Down
75 changes: 75 additions & 0 deletions src/Console/Input/Input.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,16 @@
*/
abstract class Input implements InputInterface
{
/**
* @var array $rawArguments
*/
protected $rawArguments = [];

/**
* @var array $missingArguments
*/
protected $missingArguments = [];

/**
* Holds the given arguments
*
Expand Down Expand Up @@ -161,4 +171,69 @@ public function getSignature(): Signature
{
return $this->signature;
}

/**
* Parse the raw arguments
*/
protected function parseRawArguments()
{
// First we check if any subcommand was requested
if (isset($this->rawArguments[0])) {
foreach ($this->getSignature()->getSubCommands() as $command) {
if ($this->rawArguments[0] === $command->getName()) {
$this->setSubCommand($command->getName());
break;
}
}
}

// Then we parse out the options
foreach ($this->getSignature()->getOptions() as $option) {

$definitions = [
'-'.$option->getName(),
'--'.$option->getName(),
];

if ($alias = $option->getAlias()) {
$definitions[] = '-'.$alias;
$definitions[] = '--'.$alias;
}

foreach ($definitions as $definition) {
$optionPosition = array_search($definition, $this->rawArguments);

if ($optionPosition !== false) {

// We found the option in the list of given arguments
if (
isset($this->rawArguments[$optionPosition + 1]) &&
substr($this->rawArguments[$optionPosition + 1], 0, strlen('-')) !== '-'
) {
// We also found a value for the option
// We remove the value of the option from the argument list
$optionValue = $this->rawArguments[$optionPosition + 1];
$this->setOption($option->getName(), $optionValue);
array_splice($this->rawArguments, $optionPosition + 1, 1);

} else {

$this->setOption($option->getName(), $option->getDefault());
}

array_splice($this->rawArguments, $optionPosition, 1);
break;
}
}
}

// Now we loop all arguments and make sure they are present
foreach ($this->getSignature()->getArguments() as $position => $argument) {
if (isset($this->rawArguments[$position])) {
$this->setArgument($argument->getName(), $this->rawArguments[$position]);
} else {
$this->missingArguments[] = $argument->getName();
}
}
}
}
26 changes: 13 additions & 13 deletions src/Contracts/Console/InputInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,22 +10,22 @@
*/
interface InputInterface
{
public function setSignature(Signature $signature);
public function getSignature(): Signature;
public function setSignature(Signature $signature);
public function getSignature(): Signature;

public function validate();
public function validate();

public function getArguments();
public function getArgument(string $name);
public function getArguments();
public function getArgument(string $name);

public function hasArgument(string $name): bool;
public function setArgument(string $name, $value);
public function hasArgument(string $name): bool;
public function setArgument(string $name, $value);

public function getOptions();
public function getOption(string $name);
public function setOption(string $name, $value);
public function getOptions();
public function getOption(string $name);
public function setOption(string $name, $value);

public function hasSubCommand(): bool;
public function getSubCommand();
public function setSubCommand(string $name);
public function hasSubCommand(): bool;
public function getSubCommand();
public function setSubCommand(string $name);
}
21 changes: 21 additions & 0 deletions src/Contracts/Scheduler/JobInterface.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<?php

namespace Oak\Contracts\Scheduler;

interface JobInterface
{
/**
* @return string
*/
public function getCronExpression(): string;

/**
* @return string
*/
public function getCommand(): string;

/**
* @return string
*/
public function execute(): string;
}
26 changes: 26 additions & 0 deletions src/Contracts/Scheduler/SchedulerInterface.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
<?php

namespace Oak\Contracts\Scheduler;

use Oak\Contracts\Console\OutputInterface;

interface SchedulerInterface
{
/**
* @param string $command
* @return JobInterface
*/
public function run(string $command): JobInterface;

/**
* @param JobInterface $job
* @return mixed
*/
public function isDue(JobInterface $job);

/**
* @param OutputInterface $output
* @return mixed
*/
public function runSchedule(OutputInterface $output);
}
47 changes: 47 additions & 0 deletions src/Scheduler/Console/SchedulerCommand.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
<?php

namespace Oak\Scheduler\Console;

use Oak\Console\Command\Command;
use Oak\Console\Command\Signature;
use Oak\Contracts\Console\InputInterface;
use Oak\Contracts\Console\OutputInterface;
use Oak\Contracts\Container\ContainerInterface;
use Oak\Contracts\Scheduler\SchedulerInterface;

class SchedulerCommand extends Command
{
/**
* @var SchedulerInterface $scheduler
*/
private $scheduler;

/**
* SchedulerCommand constructor.
* @param SchedulerInterface $scheduler
* @param ContainerInterface $app
*/
public function __construct(SchedulerInterface $scheduler, ContainerInterface $app)
{
$this->scheduler = $scheduler;

parent::__construct($app);
}

/**
* @param Signature $signature
* @return Signature
*/
protected function createSignature(Signature $signature): Signature
{
return $signature
->setName('scheduler')
->addSubCommand(TickCommand::class)
;
}

public function execute(InputInterface $input, OutputInterface $output)
{
$this->scheduler->runSchedule($output);
}
}
49 changes: 49 additions & 0 deletions src/Scheduler/Console/TickCommand.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
<?php

namespace Oak\Scheduler\Console;

use Oak\Console\Command\Command;
use Oak\Console\Command\Signature;
use Oak\Contracts\Console\InputInterface;
use Oak\Contracts\Console\OutputInterface;
use Oak\Contracts\Container\ContainerInterface;
use Oak\Contracts\Scheduler\SchedulerInterface;

class TickCommand extends Command
{
/**
* @var SchedulerInterface $scheduler
*/
private $scheduler;

/**
* SchedulerCommand constructor.
* @param SchedulerInterface $scheduler
* @param ContainerInterface $app
*/
public function __construct(SchedulerInterface $scheduler, ContainerInterface $app)
{
$this->scheduler = $scheduler;

parent::__construct($app);
}

/**
* @param Signature $signature
* @return Signature
*/
protected function createSignature(Signature $signature): Signature
{
return $signature
->setName('tick')
;
}

public function execute(InputInterface $input, OutputInterface $output)
{
while (true) {
$this->scheduler->runSchedule($output);
sleep(60);
}
}
}
Loading

0 comments on commit 4a09c48

Please sign in to comment.