255, 'char' => 255, 'int' => 11, ); public static function config($args) { $file = strtolower(array_shift($args)); if (empty($file)) { throw new Exception('No config filename has been provided.'); } $config = array(); // load the config if ($paths = \Finder::search('config', $file, '.php', true)) { // Reverse the file list so that we load the core configs first and // the app can override anything. $paths = array_reverse($paths); foreach ($paths as $path) { $config = \Fuel::load($path) + $config; } } unset($path); // We always pass in fields to a config, so lets sort them out here. foreach ($args as $conf) { // Each paramater for a config is seperated by the : character $parts = explode(":", $conf); // We must have the 'name:value' if nothing else! if (count($parts) >= 2) { $config[$parts[0]] = $parts[1]; } } $overwrite = (\Cli::option('o') or \Cli::option('overwrite')); // strip whitespace and add tab $export = str_replace(array(' ', 'array ('), array("\t", 'array('), var_export($config, true)); $content = ' \'active\' ); $this->template->title = \'' . \Inflector::humanize($name) .' » ' . \Inflector::humanize($action) . '\'; $this->template->content = View::forge(\''.$filename.'/' . $action .'\', $data); }'.PHP_EOL; } $extends = \Cli::option('extends', 'Controller_Template'); $prefix = \Config::get('controller_prefix', 'Controller_'); // Build Controller $controller = <<content = "{$class_name} » {$action}"; } } PRESENTER; // Write presenter static::create($presenter_filepath.DS.$action.'.php', $presenter, 'presenter'); } } // Generate with test? $with_test = \Cli::option('with-test'); if ($with_presenter and $with_test) { static::_create_test('Presenter', $class_name, $base_path); } $build and static::build(); } public static function model($args, $build = true) { $singular = \Inflector::singularize(\Str::lower(array_shift($args))); if (empty($singular) or strpos($singular, ':')) { throw new Exception("Command is invalid.".PHP_EOL."\tphp oil g model [: |: |..]"); } if (empty($args)) { throw new Exception('No fields have been provided, the model will not know how to build the table.'); } $plural = \Cli::option('singular') ? $singular : \Inflector::pluralize($singular); $filename = trim(str_replace(array('_', '-'), DS, $singular), DS); $base_path = APPPATH; if ($module = \Cli::option('module')) { if ( ! ($base_path = \Module::exists($module)) ) { throw new Exception('Module '.$module.' was not found within any of the defined module paths'); } $module_namespace = ucwords($module); } $filepath = $base_path.'classes'.DS.'model'.DS.$filename.'.php'; // Uppercase each part of the class name and remove hyphens $class_name = \Inflector::classify(str_replace(array('\\', '/'), '_', $singular), false); // Turn foo:string into "id", "foo", $properties = implode(",\n\t\t", array_map(function($field) { // Only take valid fields if (($field = strstr($field, ':', true))) { return "'".$field."'"; } }, $args)); // Add a comma to the end of the list $properties = "\n\t\t" . $properties . ","; $contents = ''; // Generate with test? $with_test = \Cli::option('with-test'); if ($with_test) { static::_create_test('Model', $class_name, $base_path); } if (\Cli::option('crud')) { // Make sure an id is present strpos($properties, "'id'") === false and $properties = "'id',".$properties; if ( ! \Cli::option('no-properties')) { $contents = << '$created_at', CONTENTS; } else { $created_at = ''; } if(($updated_at = \Cli::option('updated-at')) and is_string($updated_at)) { $updated_at = << '$updated_at', CONTENTS; } else { $updated_at = ''; } $contents .= << array( 'events' => array('before_insert'), 'mysql_timestamp' => $mysql_timestamp,$created_at ), 'Orm\Observer_UpdatedAt' => array( 'events' => array('before_update'), 'mysql_timestamp' => $mysql_timestamp,$updated_at ), ); CONTENTS; } if (\Cli::option('soft-delete')) { if($deleted_at !== 'deleted_at') { $deleted_at = << '{$deleted_at}', CONTENTS; } else { $deleted_at = ''; } $contents .= << $mysql_timestamp,$deleted_at ); CONTENTS; } elseif (\Cli::option('temporal')) { if($temporal_start !== 'temporal_start') { $start_column = << '{$temporal_start}', CONTENTS; } else { $start_column = ''; } if($temporal_end !== 'temporal_end') { $end_column = << '{$temporal_end}', CONTENTS; } else { $end_column = ''; } $contents .= << $mysql_timestamp,$start_column$end_column ); protected static \$_primary_key = array('id', '{$temporal_start}', '{$temporal_end}'); CONTENTS; } elseif (\Cli::option('nestedset')) { if($left_id !== 'left_id') { $left_field = << '{$left_id}', CONTENTS; } else { $left_field = ''; } if($right_id !== 'right_id') { $right_field = << '{$right_id}', CONTENTS; } else { $right_field = ''; } if($tree_id) { $tree_field = << '{$tree_id}', CONTENTS; } else { $tree_field = ''; } if($title) { $title_field = << '{$title}', CONTENTS; } else { $title_field = ''; } if($read_only = \Cli::option('read-only') and is_string($read_only)) { $read_only = explode(',', $read_only); $read_only = "'" . implode("', '", $read_only) . "'"; $read_only = << array($read_only), CONTENTS; } else { $read_only = ''; } if (! empty($left_field) or ! empty($right_field) or ! empty($tree_field) or ! empty($title_field)) { $fields = array($left_field, $right_field, $tree_field, $title_field, $read_only); $fields = array_filter($fields); $fields = implode("\n", $fields); $contents .= << 1) { \Cli::write('Your app has multiple module paths defined. Please choose the appropriate path from the list below', 'yellow', 'blue'); $options = array(); foreach ($module_paths as $key => $path) { $idx = $key+1; \Cli::write('['.$idx.'] '.$path); $options[] = $idx; } $path_idx = \Cli::prompt('Please choose the desired module path', $options); $base = $module_paths[$path_idx - 1]; } $module_path = $base.$module_name.DS; static::$create_folders[] = $module_path; static::$create_folders[] = $module_path.'classes/'; if ( ($folders = \Cli::option('folders')) !== true ) { $folders = explode(',', $folders); foreach ($folders as $folder) { static::$create_folders[] = $module_path.$folder; } } static::$create_folders && static::build(); } public static function views($args, $subfolder, $build = true) { $controller = strtolower(array_shift($args)); $controller_title = \Inflector::humanize($controller); $base_path = APPPATH; if ($module = \Cli::option('module')) { if ( ! ($base_path = \Module::exists($module)) ) { throw new Exception('Module '.$module.' was not found within any of the defined module paths'); } } $view_dir = $base_path.'views/'.trim(str_replace(array('_', '-'), DS, $controller), DS).DS; $args or $args = array('index'); // Make the directory for these views to be store in is_dir($view_dir) or static::$create_folders[] = $view_dir; // Add the default template if it doesn't exist if ( ! is_file($app_template = $base_path.'views/template.php') ) { static::create($app_template, file_get_contents(\Package::exists('oil').'views/scaffolding/template.php'), 'view'); } $subnav = ''; foreach($args as $nav_item) { $subnav .= "\t
  • \n"; } foreach ($args as $action) { $view_title = (\Cli::option('with-presenter') or \Cli::option('with-viewmodel')) ? '' : \Inflector::humanize($action); $view = << {$subnav}

    {$view_title}

    VIEW; // Generate with test? $with_test = \Cli::option('with-test'); if ($with_test) { static::_create_test('View', $controller, $base_path, $nav_item); } // Create this view static::create($view_dir.$action.'.php', $view, 'view'); } $build and static::build(); } public static function migration($args, $build = true) { // Get the migration name $migration_name = \Str::lower(str_replace(array('-', '/'), '_', array_shift($args))); if (empty($migration_name) or strpos($migration_name, ':')) { throw new Exception("Command is invalid.".PHP_EOL."\tphp oil g migration [: |: |..]"); } $base_path = APPPATH; // Check if a migration with this name already exists if ($module = \Cli::option('module')) { if ( ! ($base_path = \Module::exists($module)) ) { throw new Exception('Module '.$module.' was not found within any of the defined module paths'); } } $migrations = new \GlobIterator($base_path.'migrations/*_'.$migration_name.'*'); try { $duplicates = array(); foreach($migrations as $migration) { // check if it's really a duplicate $part = explode('_', basename($migration->getFilename(), '.php'), 2); if ($part[1] != $migration_name) { $part = substr($part[1], strlen($migration_name)+1); if ( ! is_numeric($part)) { // not a numbered suffix, but the same base classname continue; } } $duplicates[] = $migration->getPathname(); } } catch (\LogicException $e) { throw new Exception("Unable to read existing migrations. Path does not exist, or you may have an 'open_basedir' defined"); } if (count($duplicates) > 0) { // Don't override a file if (\Cli::option('s', \Cli::option('skip')) === true) { return; } // Tear up the file path and name to get the last duplicate $file_name = pathinfo(end($duplicates), PATHINFO_FILENAME); // Override the (most recent) migration with the same name by using its number if (\Cli::option('f', \Cli::option('force')) === true) { list($number) = explode('_', $file_name); } // Name clashes but this is done by hand. Assume they know what they're doing and just increment the file elseif (static::$scaffolding === false) { // Increment the name of this $migration_name = \Str::increment(substr($file_name, 4), 2); } } // See if the action exists $methods = get_class_methods(__NAMESPACE__ . '\Generate_Migration_Actions'); // For empty migrations that dont have actions $migration = array('', ''); // Loop through the actions and act on a matching action appropriately foreach ($methods as $method_name) { // If the miration name starts with the name of the action method if (substr($migration_name, 0, strlen($method_name)) === $method_name) { /** * Create an array of the subject the migration is about * * - In a migration named 'create_users' the subject is 'users' since thats what we want to create * So it would be the second object in the array * array(false, 'users') * * - In a migration named 'add_name_to_users' the object is 'name' and the subject is 'users'. * So again 'users' would be the second object, but 'name' would be the first * array('name', 'users') * */ $subjects = array(false, false); $matches = explode('_', str_replace($method_name . '_', '', $migration_name)); // create_{table} if (count($matches) == 1) { $subjects = array(false, $matches[0]); } // add_{field}_to_{table} elseif (count($matches) == 3 && $matches[1] == 'to') { $subjects = array($matches[0], $matches[2]); } // delete_{field}_from_{table} elseif (count($matches) == 3 && $matches[1] == 'from') { $subjects = array($matches[0], $matches[2]); } // rename_field_{field}_to_{field}_in_{table} (with underscores in field names) elseif (count($matches) >= 5 && in_array('to', $matches) && in_array('in', $matches)) { $subjects = array( implode('_', array_slice($matches, array_search('in', $matches)+1)), implode('_', array_slice($matches, 0, array_search('to', $matches))), implode('_', array_slice($matches, array_search('to', $matches)+1, array_search('in', $matches)-array_search('to', $matches)-1)), ); } // rename_table elseif ($method_name == 'rename_table') { $subjects = array( implode('_', array_slice($matches, 0, array_search('to', $matches))), implode('_', array_slice($matches, array_search('to', $matches)+1)), ); } // create_{table} or drop_{table} (with underscores in table name) elseif (count($matches) !== 0) { $name = str_replace(array('create_', 'add_', 'drop_', '_to_'), array('create-', 'add-', 'drop-', '-to-'), $migration_name); if (preg_match('/^(create|drop|add)\-([a-z0-9\_]*)(\-to\-)?([a-z0-9\_]*)?$/i', $name, $deep_matches)) { switch ($deep_matches[1]) { case 'create' : case 'drop' : $subjects = array(false, $deep_matches[2]); break; case 'add' : $subjects = array($deep_matches[2], $deep_matches[4]); break; } } } // There is no subject here so just carry on with a normal empty migration else { break; } // We always pass in fields to a migration, so lets sort them out here. $fields = array(); foreach ($args as $field) { $field_array = array(); // Each paramater for a field is seperated by the : character $parts = explode(":", $field); // We must have the 'name:type' if nothing else! if (count($parts) >= 2) { $field_array['name'] = array_shift($parts); foreach ($parts as $part_i => $part) { preg_match('/([a-z0-9_-]+)(?:\[([0-9a-z_\-\,\s]+)\])?/i', $part, $part_matches); array_shift($part_matches); if (count($part_matches) < 1) { // Move onto the next part, something is wrong here... continue; } $option_name = ''; // This is the name of the option to be passed to the action in a field $option = $part_matches; // The first option always has to be the field type if ($part_i == 0) { $option_name = 'type'; $type = $option[0]; if ($type === 'string') { $type = 'varchar'; } elseif ($type === 'integer') { $type = 'int'; } if ( ! in_array($type, array('text', 'blob', 'datetime', 'date', 'timestamp', 'time'))) { if ( ! isset($option[1]) || $option[1] == NULL) { if (isset(self::$_default_constraints[$type])) { $field_array['constraint'] = self::$_default_constraints[$type]; } } else { // should support field_name:enum[value1,value2] if ($type === 'enum') { $values = explode(',', $option[1]); $option[1] = '"'.implode('","', $values).'"'; $field_array['constraint'] = $option[1]; } // should support field_name:decimal[10,2] elseif (in_array($type, array('decimal', 'float'))) { $field_array['constraint'] = $option[1]; } else { $field_array['constraint'] = (int) $option[1]; } } } $option = $type; } else { // This allows you to put any number of :option or :option[val] into your field and these will... // ... always be passed through to the action making it really easy to add extra options for a field $option_name = array_shift($option); if (count($option) > 0) { $option = $option[0]; } else { $option = true; } } // deal with some special cases switch ($option_name) { case 'auto_increment': case 'null': case 'unsigned': $option = (bool) $option; break; } $field_array[$option_name] = $option; } $fields[] = $field_array; } else { // Invalid field passed in continue; } } // Call the magic action which returns an array($up, $down) for the migration $migration = call_user_func(__NAMESPACE__ . "\Generate_Migration_Actions::{$method_name}", $subjects, $fields); } } // Build the migration list($up, $down)=$migration; // If we don't have any, bail out if (empty($up) and empty($down)) { throw new \Exception('No migration could be generated. Please verify your command syntax.'); exit; } $migration_name = ucfirst(strtolower($migration_name)); $migration = << [ | |..] php oil g model [: |: |..] php oil g migration [: |: |..] php oil g scaffold [: |: |..] php oil g scaffold/template_subfolder [: |: |..] php oil g config [: |: |..] php oil g task [ | |..] php oil g package Note that the next two lines are equivalent: php oil g scaffold ... php oil g scaffold/orm ... Documentation: http://docs.fuelphp.com/packages/oil/generate.html HELP; \Cli::write($output); } public static function package($args, $build = true) { $name = str_replace(array('/', '_', '-'), '', \Str::lower(array_shift($args))); $class_name = ucfirst($name); $vcs = \Cli::option('vcs', \Cli::option('v', false)); $path = \Cli::option('path', \Cli::option('p', PKGPATH)); $drivers = \Cli::option('drivers', \Cli::option('d', '')); if (empty($name)) { throw new \Exception('No package name has been provided.'); } if ( ! in_array($path, \Config::get('package_paths')) and ! in_array(realpath($path), \Config::get('package_paths')) ) { throw new \Exception('Given path is not a valid package path.'); } \Str::ends_with($path, DS) or $path .= DS; $path .= $name . DS; if (is_dir($path)) { throw new \Exception('Package already exists.'); } if ($vcs) { $output = << \$config); \$config = \Arr::merge(static::\$_defaults, \Config::get('{$name}', array()), \$config); \$class = '\\{$class_name}\\{$class_name}_' . ucfirst(strtolower(\$config['driver'])); if( ! class_exists(\$class, true)) { throw new \FuelException('Could not find {$class_name} driver: ' . ucfirst(strtolower(\$config['driver'])); } \$driver = new \$class(\$config); static::\$_instances[\$instance] = \$driver; return \$driver; } /** * Return a specific driver, or the default instance (is created if necessary) * * @param string \$instance * @return {$class_name} instance */ public static function instance(\$instance = null) { if (\$instance !== null) { if ( ! array_key_exists(\$instance, static::\$_instances)) { return false; } return static::\$_instances[\$instance]; } if (static::\$_instance === null) { static::\$_instance = static::forge(); } return static::\$_instance; } } CLASS; static::create($path . 'classes' . DS . $name . '.php', $output); $output = <<config = \$config; } /** * Get a driver config setting. * * @param string \$key the config key * @param mixed \$default the default value * @return mixed the config setting value */ public function get_config(\$key, \$default = null) { return \Arr::get(\$this->config, \$key, \$default); } /** * Set a driver config setting. * * @param string \$key the config key * @param mixed \$value the new config value * @return object \$this for chaining */ public function set_config(\$key, \$value) { \Arr::set(\$this->config, \$key, \$value); return \$this; } } DRIVER; static::create($path . 'classes' . DS . $name . DS . 'driver.php', $output); $bootstrap = "\n\t'{$class_name}\\\\{$class_name}_Driver' => __DIR__ . '/classes/{$name}/driver.php',"; if (is_array($drivers)) { foreach ($drivers as $driver) { $driver = \Str::lower($driver); $driver_name = ucfirst($driver); $output = <<config = \$config; } /** * Get a config setting. * * @param string \$key the config key * @param mixed \$default the default value * @return mixed the config setting value */ public function get_config(\$key, \$default = null) { return \Arr::get(\$this->config, \$key, \$default); } /** * Set a config setting. * * @param string \$key the config key * @param mixed \$value the new config value * @return object \$this for chaining */ public function set_config(\$key, \$value) { \Arr::set(\$this->config, \$key, \$value); return \$this; } } CLASS; static::create($path . 'classes' . DS . $name . '.php', $output); $bootstrap = ""; } $output = << __DIR__ . '/classes/{$name}.php', '{$class_name}\\\\{$class_name}Exception' => __DIR__ . '/classes/{$name}.php', {$bootstrap} )); CLASS; static::create($path . 'bootstrap.php', $output); $build and static::build(); } public static function create($filepath, $contents, $type = 'file') { $directory = dirname($filepath); is_dir($directory) or static::$create_folders[] = $directory; // Check if a file exists then work out how to react if (is_file($filepath)) { // Don't override a file if (\Cli::option('s', \Cli::option('skip')) === true) { // Don't bother trying to make this, carry on camping return; } // If we aren't skipping it, tell em to use -f if (\Cli::option('f', \Cli::option('force')) === null) { throw new Exception($filepath .' already exists, use -f or --force to override.'); exit; } } static::$create_files[] = array( 'path' => $filepath, 'contents' => $contents, 'type' => $type, ); } public static function build() { foreach (static::$create_folders as $folder) { is_dir($folder) or mkdir($folder, 0755, TRUE); } $result = true; foreach (static::$create_files as $file) { \Cli::write("\tCreating {$file['type']}: {$file['path']}", 'green'); if ( ! $handle = @fopen($file['path'], 'w+')) { throw new Exception('Cannot open file: '. $file['path']); } $result = @fwrite($handle, $file['contents']); // Write $somecontent to our opened file. if ($result === false) { throw new Exception('Cannot write to file: '. $file['path']); } @fclose($handle); @chmod($file['path'], 0666); } return $result; } public static function class_name($name) { return str_replace(array(' ', '-'), '_', ucwords(str_replace('_', ' ', $name))); } // Helper methods private static function _find_migration_number() { $base_path = APPPATH; if ($module = \Cli::option('module')) { if ( ! ($base_path = \Module::exists($module)) ) { throw new Exception('Module ' . $module . ' was not found within any of the defined module paths'); } } $files = new \GlobIterator($base_path .'migrations/*_*.php'); try { $migrations = array(); foreach($files as $file) { $migrations[] = $file->getPathname(); } sort($migrations); list($last) = explode('_', basename(end($migrations))); } catch (\LogicException $e) { throw new Exception("Unable to read existing migrations. Path does not exist, or you may have an 'open_basedir' defined"); } return str_pad($last + 1, 3, '0', STR_PAD_LEFT); } private static function _update_current_version($version) { if (is_file($app_path = APPPATH.'config'.DS.'migrations.php')) { $contents = file_get_contents($app_path); } elseif (is_file($core_path = COREPATH.'config'.DS.'migrations.php')) { $contents = file_get_contents($core_path); } else { throw new \Exception('Config file core/config/migrations.php'); exit; } $contents = preg_replace("#('version'[ \t]+=>)[ \t]+([0-9]+),#i", "$1 $version,", $contents); static::create($app_path, $contents, 'config'); } private static function _create_test($type, $class_name, $base_path, $nav_item = '') { $filepath = $base_path.strtolower('tests'.DS.$type.DS.ucwords($class_name)); if ( ! empty($nav_item) and $type === 'View') { $filepath = $filepath.DS.strtolower($nav_item); $class_name = $class_name.'_'.ucwords($nav_item); } $output = <<