Last active
September 12, 2017 08:00
-
-
Save Ellrion/1a3ef7bc2e988e3fb80782e66d363fb7 to your computer and use it in GitHub Desktop.
List of schedule tascks and list of abilities commands for Laravel (See comments)
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
<?php | |
namespace App\Console\Commands\Foundation; | |
use App\Console\Commands\Command; | |
use App\User; | |
use Illuminate\Contracts\Auth\Access\Gate; | |
class AbilitiesListCommand extends Command | |
{ | |
/** | |
* The name and signature of the console command. | |
* | |
* @var string | |
*/ | |
protected $signature = 'ability:list | |
{user? : The ID of the user for ability checking} | |
{--M|model=* : The `ModelClass:id` for checking policy methods}'; | |
/** | |
* The console command description. | |
* | |
* @var string | |
*/ | |
protected $description = 'List all registered abilities'; | |
/** | |
* @var \Illuminate\Contracts\Auth\Access\Gate | |
*/ | |
protected $gate; | |
/** | |
* @var | |
*/ | |
protected $user; | |
/** | |
* List of model for checking policy methods. | |
* | |
* @var array | |
*/ | |
protected $models = []; | |
/** | |
* {@inheritdoc} | |
*/ | |
public function handle(Gate $gate) | |
{ | |
$this->initGate($gate); | |
$this->initModels(); | |
$this->output->title('Abilities list'); | |
collect() | |
->merge($this->extractBaseAbilities()) | |
->merge($this->extractPoliciesAbilities()) | |
->each([$this, 'outputAbility']); | |
$this->output->newLine(); | |
} | |
/** | |
* @param object $ability | |
*/ | |
public function outputAbility($ability) | |
{ | |
if (null === $this->user) { | |
$this->line("* {$ability->ability}"); | |
} elseif (null === $ability->resolved) { | |
$this->line("[?] {$ability->ability}"); | |
} elseif (true === $ability->resolved) { | |
$this->info("[+] {$ability->ability}"); | |
} else { | |
$this->warn("[-] {$ability->ability}"); | |
} | |
} | |
/** | |
* @param Gate $gate | |
*/ | |
protected function initGate(Gate $gate) | |
{ | |
$this->gate = $gate; | |
if (! $this->hasArgument('user')) { | |
return; | |
} | |
$this->user = User::find($this->argument('user')); | |
$this->gate = $this->gate->forUser($this->user); | |
} | |
/** | |
* | |
*/ | |
protected function initModels() | |
{ | |
$models = (array) $this->option('model'); | |
foreach ($models as $model) { | |
list($class, $id) = explode(':', $model, 2); | |
$this->models[$class] = compact('class', 'id'); | |
} | |
} | |
/** | |
* @return \Illuminate\Support\Collection | |
*/ | |
protected function extractBaseAbilities() | |
{ | |
$reflected_gate = new \ReflectionObject($this->gate); | |
$abilities = $reflected_gate->getProperty('abilities'); | |
$abilities->setAccessible(true); | |
return collect($abilities->getValue($this->gate)) | |
->keys() | |
->transform(function ($ability) { | |
return $this->makeResolvedBaseAbility($ability); | |
}); | |
} | |
/** | |
* @return \Illuminate\Support\Collection | |
*/ | |
protected function extractPoliciesAbilities() | |
{ | |
$reflected_gate = new \ReflectionObject($this->gate); | |
$abilities = collect(); | |
$policies = $reflected_gate->getProperty('policies'); | |
$policies->setAccessible(true); | |
$policies = $policies->getValue($this->gate); | |
foreach ($policies as $class => $policy) { | |
$abilities = $abilities->merge($this->extractPolicyAbilities($class, $policy)); | |
} | |
return $abilities; | |
} | |
/** | |
* @param string $modelClass | |
* @param string $policyClass | |
* @return \Illuminate\Support\Collection | |
*/ | |
protected function extractPolicyAbilities($modelClass, $policyClass) | |
{ | |
$abilities = collect(); | |
$reflected_policy = new \ReflectionClass($policyClass); | |
$methods = $reflected_policy->getMethods(\ReflectionMethod::IS_PUBLIC); | |
foreach ($methods as $method) { | |
$ability = str_replace_first('_', '-', snake_case($method->getName(), '_')); | |
$abilities->push($this->makeResolvedPolicyAbility($modelClass, $policyClass, $ability)); | |
} | |
return $abilities; | |
} | |
/** | |
* @param string $ability | |
* @return object | |
*/ | |
protected function makeResolvedBaseAbility($ability) | |
{ | |
$resolved = null; | |
if (null !== $this->user) { | |
$resolved = $this->resolveBaseAbility($ability); | |
} | |
return (object) compact('ability', 'resolved'); | |
} | |
/** | |
* @param string $modelClass | |
* @param string $policyClass | |
* @param string $ability | |
* @return object | |
*/ | |
protected function makeResolvedPolicyAbility($modelClass, $policyClass, $ability) | |
{ | |
$resolved = null; | |
if (null !== $this->user) { | |
$resolved = $this->resolvePolicyAbility($modelClass, $policyClass, $ability); | |
} | |
$ability = strtolower(class_basename($modelClass)) . ':' . $ability; | |
return (object) compact('ability', 'resolved'); | |
} | |
/** | |
* @param string $ability | |
* @return bool|null | |
*/ | |
protected function resolveBaseAbility($ability) | |
{ | |
try { | |
return $this->gate->check($ability); | |
} catch (\Throwable $e) { | |
return null; | |
} | |
} | |
/** | |
* @param string $modelClass | |
* @param string $policyClass | |
* @param string $ability | |
* @return bool|null | |
*/ | |
protected function resolvePolicyAbility($modelClass, $policyClass, $ability) | |
{ | |
$base_class = class_basename($modelClass); | |
$formatted_class = strtolower($base_class); | |
try { | |
return $this->gate->check($ability, $modelClass); | |
} catch (\Throwable $e) { | |
$model = $this->getModel($modelClass, [$base_class, $formatted_class]); | |
if (null === $model) { | |
return null; | |
} | |
try { | |
return $this->gate->check($ability, $model); | |
} catch (\Throwable $e) { | |
return null; | |
} | |
} | |
return null; | |
} | |
/** | |
* @param $class | |
* @param $aliases | |
* @return null|\Illuminate\Database\Eloquent\Model | |
*/ | |
protected function getModel($class, $aliases) | |
{ | |
$classes = array_merge([$class], $aliases); | |
foreach ($classes as $class_alias) { | |
if (isset($this->models[$class_alias])) { | |
$instance = $this->models[$class_alias]['instance'] ?? $class::find($this->models[$class_alias]['id']); | |
return $this->models[$class_alias]['instance'] = $instance; | |
} | |
} | |
return null; | |
} | |
} |
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
<?php | |
namespace App\Console\Commands\Foundation; | |
use App\Console\Commands\Command; | |
use Cron\CronExpression; | |
use Illuminate\Console\Scheduling\Event; | |
use Illuminate\Console\Scheduling\Schedule; | |
use Illuminate\Support\Collection; | |
class ScheduleListCommand extends Command | |
{ | |
/** | |
* The name and signature of the console command. | |
* | |
* @var string | |
*/ | |
protected $signature = 'schedule:list | |
{--f|full-command : Show full schedule command text} | |
{--s|time-sort : Sort list by datetime of nex call}'; | |
/** | |
* The console command description. | |
* | |
* @var string | |
*/ | |
protected $description = 'List all scheduled tasks'; | |
/** | |
* The schedule instance. | |
* | |
* @var \Illuminate\Console\Scheduling\Schedule | |
*/ | |
protected $schedule; | |
/** | |
* Create a new command instance. | |
* | |
* @param \Illuminate\Console\Scheduling\Schedule $schedule | |
*/ | |
public function __construct(Schedule $schedule) | |
{ | |
$this->schedule = $schedule; | |
parent::__construct(); | |
} | |
/** | |
* Execute the console command. | |
* | |
* @return mixed | |
*/ | |
public function handle() | |
{ | |
if (count($this->schedule->events()) === 0) { | |
$this->info('No Scheduled Commands Found'); | |
return; | |
} | |
$table = collect($this->schedule->events()) | |
->sortBy(function (Event $event) { | |
if ($this->option('time-sort')) { | |
return $this->getCommandNextRunTime($event->getExpression()); | |
} | |
return 0; | |
}) | |
->map(function (Event $event) { | |
return [ | |
'description' => $event->description ?: 'N/A', | |
'command' => $this->prepareCommandToDisplay($event), | |
'expression' => $event->getExpression(), | |
'next' => $this->getCommandNextRunTime($event)->format('H:i:s Y-m-d'), | |
'timezone' => $event->timezone ?: config('app.timezone'), | |
'overlaps' => $event->withoutOverlapping ? 'No' : 'Yes', | |
'maintenance' => $event->evenInMaintenanceMode ? 'Execute' : 'Skip', | |
]; | |
}); | |
$this->table( | |
['Description', 'Command', 'Schedule', 'Upcoming', 'Timezone', 'Overlaps?', 'In Maintenance?'], | |
$table | |
); | |
} | |
/** | |
* Possible change command text for simple view. | |
* | |
* @param \Illuminate\Console\Scheduling\Event $event | |
* @return string | |
*/ | |
protected function prepareCommandToDisplay(Event $event) | |
{ | |
if ($this->option('full-command')) { | |
return $event->buildCommand(); | |
} | |
//for laravel < 5.4.24 see str_after realisation | |
return ltrim(strtok(str_after($event->command, "'artisan'"), ' ')); | |
} | |
/** | |
* Get next time command run datetime. | |
* | |
* @param \Illuminate\Console\Scheduling\Event $event | |
* @return \DateTime | |
*/ | |
protected function getCommandNextRunTime(Event $event) | |
{ | |
return CronExpression::factory($event->getExpression())->getNextRunDate(); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
ability:list
schedule:list