123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365 |
- <?php
- /**
- * Interface that all minion tasks must implement
- *
- * @package Kohana/Minion
- * @author Kohana Team
- * @copyright (c) Kohana Team
- * @license https://koseven.ga/LICENSE.md
- */
- abstract class Kohana_Minion_Task {
- /**
- * The separator used to separate different levels of tasks
- * @var string
- */
- public static $task_separator = ':';
- /**
- * Converts a task (e.g. db:migrate to a class name)
- *
- * @param string Task name
- * @return string Class name
- */
- public static function convert_task_to_class_name($task)
- {
- $task = trim($task);
- if (empty($task))
- return '';
- return 'Task_'.implode('_', array_map('ucfirst', explode(Minion_Task::$task_separator, $task)));
- }
- /**
- * Gets the task name of a task class / task object
- *
- * @param string|Minion_Task The task class / object
- * @return string The task name
- */
- public static function convert_class_to_task($class)
- {
- if (is_object($class))
- {
- $class = get_class($class);
- }
- return strtolower(str_replace('_', Minion_Task::$task_separator, substr($class, 5)));
- }
- /**
- * Factory for loading minion tasks
- *
- * @param array An array of command line options. It should contain the 'task' key
- * @throws Minion_Exception_InvalidTask
- * @return Minion_Task The Minion task
- */
- public static function factory($options)
- {
- if (($task = Arr::get($options, 'task')) !== NULL)
- {
- unset($options['task']);
- }
- else if (($task = Arr::get($options, 0)) !== NULL)
- {
- // The first positional argument (aka 0) may be the task name
- unset($options[0]);
- }
- else
- {
- // If we didn't get a valid task, generate the help
- $task = 'help';
- }
- $class = Minion_Task::convert_task_to_class_name($task);
- if ( ! class_exists($class))
- {
- throw new Minion_Exception_InvalidTask(
- "Task ':task' is not a valid minion task",
- [':task' => $class]
- );
- }
- $class = new $class;
- if ( ! $class instanceof Minion_Task)
- {
- throw new Minion_Exception_InvalidTask(
- "Task ':task' is not a valid minion task",
- [':task' => $class]
- );
- }
- $class->set_options($options);
- // Show the help page for this task if requested
- if (array_key_exists('help', $options))
- {
- $class->_method = '_help';
- }
- return $class;
- }
- /**
- * The list of options this task accepts and their default values.
- *
- * protected $_options = array(
- * 'limit' => 4,
- * 'table' => NULL,
- * );
- *
- * @var array
- */
- protected $_options = [];
- /**
- * Populated with the accepted options for this task.
- * This array is automatically populated based on $_options.
- *
- * @var array
- */
- protected $_accepted_options = [];
- protected $_method = '_execute';
- protected function __construct()
- {
- // Populate $_accepted_options based on keys from $_options
- $this->_accepted_options = array_keys($this->_options);
- }
- /**
- * The file that get's passes to Validation::errors() when validation fails
- * @var string|NULL
- */
- protected $_errors_file = 'validation';
- /**
- * Gets the task name for the task
- *
- * @return string
- */
- public function __toString()
- {
- static $task_name = NULL;
- if ($task_name === NULL)
- {
- $task_name = Minion_Task::convert_class_to_task($this);
- }
- return $task_name;
- }
- /**
- * Sets options for this task
- *
- * $param array the array of options to set
- * @return this
- */
- public function set_options(array $options)
- {
- foreach ($options as $key => $value)
- {
- $this->_options[$key] = $value;
- }
- return $this;
- }
- /**
- * Get the options that were passed into this task with their defaults
- *
- * @return array
- */
- public function get_options()
- {
- return (array) $this->_options;
- }
- /**
- * Get a set of options that this task can accept
- *
- * @return array
- */
- public function get_accepted_options()
- {
- return (array) $this->_accepted_options;
- }
- /**
- * Adds any validation rules/labels for validating _options
- *
- * public function build_validation(Validation $validation)
- * {
- * return parent::build_validation($validation)
- * ->rule('paramname', 'not_empty'); // Require this param
- * }
- *
- * @param Validation the validation object to add rules to
- *
- * @return Validation
- */
- public function build_validation(Validation $validation)
- {
- // Add a rule to each key making sure it's in the task
- foreach ($validation->data() as $key => $value)
- {
- $validation->rule($key, [$this, 'valid_option'], [':validation', ':field']);
- }
- return $validation;
- }
- /**
- * Returns $_errors_file
- *
- * @return string
- */
- public function get_errors_file()
- {
- return $this->_errors_file;
- }
- /**
- * Execute the task with the specified set of options
- *
- * @return null
- */
- public function execute()
- {
- $options = $this->get_options();
- // Validate $options
- $validation = Validation::factory($options);
- $validation = $this->build_validation($validation);
- if ( $this->_method != '_help' AND ! $validation->check())
- {
- echo View::factory('minion/error/validation')
- ->set('task', Minion_Task::convert_class_to_task($this))
- ->set('errors', $validation->errors($this->get_errors_file()));
- }
- else
- {
- // Finally, run the task
- $method = $this->_method;
- echo $this->{$method}($options);
- }
- }
- abstract protected function _execute(array $params);
- /**
- * Outputs help for this task
- *
- * @return null
- */
- protected function _help(array $params)
- {
- $tasks = $this->_compile_task_list(Kohana::list_files('classes/task'));
- $inspector = new ReflectionClass($this);
- list($description, $tags) = $this->_parse_doccomment($inspector->getDocComment());
- $view = View::factory('minion/help/task')
- ->set('description', $description)
- ->set('tags', (array) $tags)
- ->set('task', Minion_Task::convert_class_to_task($this));
- echo $view;
- }
- public function valid_option(Validation $validation, $option)
- {
- if ( ! in_array($option, $this->_accepted_options))
- {
- $validation->error($option, 'minion_option');
- }
- }
- /**
- * Parses a doccomment, extracting both the comment and any tags associated
- *
- * Based on the code in Kodoc::parse()
- *
- * @param string The comment to parse
- * @return array First element is the comment, second is an array of tags
- */
- protected function _parse_doccomment($comment)
- {
- // Normalize all new lines to \n
- $comment = str_replace(["\r\n", "\n"], "\n", $comment);
- // Remove the phpdoc open/close tags and split
- $comment = array_slice(explode("\n", $comment), 1, -1);
- // Tag content
- $tags = [];
- foreach ($comment as $i => $line)
- {
- // Remove all leading whitespace
- $line = preg_replace('/^\s*\* ?/m', '', $line);
- // Search this line for a tag
- if (preg_match('/^@(\S+)(?:\s*(.+))?$/', $line, $matches))
- {
- // This is a tag line
- unset($comment[$i]);
- $name = $matches[1];
- $text = isset($matches[2]) ? $matches[2] : '';
- $tags[$name] = $text;
- }
- else
- {
- $comment[$i] = (string) $line;
- }
- }
- $comment = trim(implode("\n", $comment));
- return [$comment, $tags];
- }
- /**
- * Compiles a list of available tasks from a directory structure
- *
- * @param array Directory structure of tasks
- * @param string prefix
- * @return array Compiled tasks
- */
- protected function _compile_task_list(array $files, $prefix = '')
- {
- $output = [];
- foreach ($files as $file => $path)
- {
- $file = substr($file, strrpos($file, DIRECTORY_SEPARATOR) + 1);
- if (is_array($path) AND count($path))
- {
- $task = $this->_compile_task_list($path, $prefix.$file.Minion_Task::$task_separator);
- if ($task)
- {
- $output = array_merge($output, $task);
- }
- }
- else
- {
- $output[] = strtolower($prefix.substr($file, 0, -strlen(EXT)));
- }
- }
- return $output;
- }
- }
|