Skip to content

Instantly share code, notes, and snippets.

@Ellrion
Last active September 12, 2017 08:00
Show Gist options
  • Save Ellrion/1a3ef7bc2e988e3fb80782e66d363fb7 to your computer and use it in GitHub Desktop.
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)
<?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;
}
}
<?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();
}
}
@Ellrion
Copy link
Author

Ellrion commented Apr 5, 2017

ability:list

ability:list 1
ability:list 2
ability:list 3

schedule:list

schedule:list

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment