├── .editorconfig ├── .gitignore ├── CONTRIBUTING.md ├── LICENSE.txt ├── README.md ├── bin └── eecli ├── box.json ├── composer.json ├── sample.eecli.php ├── src ├── Application.php ├── CodeIgniter │ ├── BootableInterface.php │ ├── ConsoleOutput.php │ ├── Controller │ │ ├── AdminContentController.php │ │ ├── ContentFilesController.php │ │ ├── DesignController.php │ │ └── MembersController.php │ ├── Cp.php │ └── Functions.php ├── Command │ ├── AbstractCreateFieldCommand.php │ ├── AbstractCreateFieldFieldpackOptionsCommand.php │ ├── AbstractCreateFieldNativeOptionsCommand.php │ ├── ClearCeCacheCommand.php │ ├── ClearEECacheCommand.php │ ├── ClearStashCacheCommand.php │ ├── Command.php │ ├── ConsoleCommand.php │ ├── Contracts │ │ ├── Conditional.php │ │ ├── ExemptFromBootstrap.php │ │ ├── HasExamples.php │ │ ├── HasLongDescription.php │ │ ├── HasOptionExamples.php │ │ └── HasRuntimeOptions.php │ ├── CreateCategoryCommand.php │ ├── CreateCategoryGroupCommand.php │ ├── CreateChannelCommand.php │ ├── CreateFieldAssetsCommand.php │ ├── CreateFieldCheckboxesCommand.php │ ├── CreateFieldDateCommand.php │ ├── CreateFieldFieldpackCheckboxesCommand.php │ ├── CreateFieldFieldpackDropdownCommand.php │ ├── CreateFieldFieldpackListCommand.php │ ├── CreateFieldFieldpackMultiselectCommand.php │ ├── CreateFieldFieldpackPillCommand.php │ ├── CreateFieldFieldpackRadioCommand.php │ ├── CreateFieldFieldpackSwitchCommand.php │ ├── CreateFieldFileCommand.php │ ├── CreateFieldGridCommand.php │ ├── CreateFieldGroupCommand.php │ ├── CreateFieldMatrixCommand.php │ ├── CreateFieldMultiselectCommand.php │ ├── CreateFieldPlayaCommand.php │ ├── CreateFieldRadioCommand.php │ ├── CreateFieldRelationshipCommand.php │ ├── CreateFieldRteCommand.php │ ├── CreateFieldSelectCommand.php │ ├── CreateFieldStoreProductDetailsCommand.php │ ├── CreateFieldTextCommand.php │ ├── CreateFieldTextareaCommand.php │ ├── CreateFieldWygwamCommand.php │ ├── CreateGlobalVariableCommand.php │ ├── CreateMemberCommand.php │ ├── CreateMemberGroupCommand.php │ ├── CreateSnippetCommand.php │ ├── CreateStatusCommand.php │ ├── CreateStatusGroupCommand.php │ ├── CreateTemplateCommand.php │ ├── CreateTemplateGroupCommand.php │ ├── CreateUploadPrefCommand.php │ ├── DbDumpCommand.php │ ├── DeleteEntryCommand.php │ ├── DeleteGlobalVariableCommand.php │ ├── DeleteSnippetCommand.php │ ├── DeleteTemplateCommand.php │ ├── DeleteTemplateGroupCommand.php │ ├── GenerateAddonCommand.php │ ├── GenerateCommandCommand.php │ ├── GenerateHtaccessCommand.php │ ├── GithubAddonInstallerCommand.php │ ├── InitCommand.php │ ├── ShowActionsCommand.php │ ├── ShowCategoryGroupsCommand.php │ ├── ShowConfigCommand.php │ ├── ShowFieldGroupsCommand.php │ ├── ShowFieldsCommand.php │ ├── ShowMembersCommand.php │ ├── ShowTemplatesCommand.php │ ├── ShowVersionCommand.php │ ├── SyncTemplatesCommand.php │ └── UpdateAddonsCommand.php ├── Console │ └── GlobalArgvInput.php ├── Db │ ├── ConnectionTester.php │ ├── MysqlTester.php │ └── MysqliTester.php ├── Handlebars │ └── Loader │ │ └── FilesystemLoader.php ├── bootstrap.php ├── stub.php └── templates │ ├── Command.php.handlebars │ └── htaccess.handlebars └── tests.sh /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | end_of_line = lf 5 | charset = utf-8 6 | trim_trailing_whitespace = true 7 | indent_style = space 8 | indent_size = 4 9 | 10 | [**.php] 11 | insert_final_newline = true 12 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | vendor/ 2 | composer.lock 3 | eecli.phar 4 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | Please send pull requests to the [develop branch](https://github.com/rsanchez/eecli/tree/develop). Please be sure to follow the [PSR-1](http://www.php-fig.org/psr/psr-1/) coding standard and the [PSR-2](http://www.php-fig.org/psr/psr-2/) style guide. If your pull request requires a change in documentation, please add a comment to your pull request with the updated and/or new wiki page document. -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 Rob Sanchez 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # eecli 2 | 3 | `eecli` is a command line interface for ExpressionEngine 2. It can be used to: 4 | 5 | * aid in development, like creating new channels or generating a custom addon. 6 | * run post-deployment tasks on your staging/production server(s), like clearing cache. 7 | * automate critical tasks, like database backup 8 | * build your own custom CLI commands, like import scripts or cron jobs 9 | * debug using an interactive shell 10 | 11 | ![Screencast of a few example commands](https://github.com/rsanchez/eecli/wiki/images/home.gif) 12 | 13 | ## Installation 14 | 15 | The preferred installation method is to install globally with [Composer](https://getcomposer.org/). Refer the official composer documentation for more information on [installing Composer globally](https://getcomposer.org/doc/00-intro.md#globally). Run this at the command line: 16 | 17 | ``` 18 | $ composer global require eecli/eecli 19 | ``` 20 | 21 | Make sure your global Composer installation's bin folder is added to your PATH in your `~/.bash_profile` (or `~/.profile` or `~/.bashrc` or `~/.zshrc`) so that you may run the binary `eecli` from the command line: 22 | 23 | ``` 24 | export PATH=~/.composer/vendor/bin:$PATH 25 | ``` 26 | 27 | For more installation methods, please see the [full Installation guide](https://github.com/rsanchez/eecli/wiki/Installation) in the Wiki. 28 | 29 | ## Usage 30 | 31 | ``` 32 | $ eecli [options] [argument1] [argument2] 33 | ``` 34 | 35 | To see a list of available commands, simply type eecli at the root of your project installation: 36 | 37 | ``` 38 | $ eecli 39 | ``` 40 | 41 | For detailed information on a specific command, use the help command: 42 | 43 | ``` 44 | $ eecli help 45 | ``` 46 | 47 | To generate a new config file, use the init command: 48 | 49 | ``` 50 | $ eecli init 51 | ``` 52 | 53 | ## Documentation 54 | 55 | For more details on installation, configuration and a command reference, see the [Wiki](https://github.com/rsanchez/eecli/wiki). 56 | 57 | ## Requirements 58 | 59 | * PHP 5.3+ 60 | * ExpressionEngine 2.5 - 2.10 (Does *not* work with ExpressionEngine 3). 61 | 62 | ## Contributing 63 | 64 | See [CONTRIBUTING](https://github.com/rsanchez/eecli/blob/master/CONTRIBUTING.md) for more information. 65 | 66 | ## License 67 | 68 | `eecli` is released under the MIT License. See the bundled [LICENSE file](https://github.com/rsanchez/eecli/blob/master/LICENSE.txt). -------------------------------------------------------------------------------- /bin/eecli: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env php 2 | =5.3.0", 18 | "eecli/addon-templates": "~1.0", 19 | "eecli/github-addon-installer": "~1.1", 20 | "illuminate/console": "~4.2|~5", 21 | "symfony/event-dispatcher": "~2.5|~3.0", 22 | "eecli/bootstrap": "~1.3", 23 | "d11wtq/boris": "~1.0", 24 | "xamin/handlebars.php": "~0.10", 25 | "symfony/finder": "~2.5|~3.0", 26 | "doctrine/instantiator": "~1.0,>=1.0.2", 27 | "symfony/process": "~2.5|~3.0" 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /sample.eecli.php: -------------------------------------------------------------------------------- 1 | /system 21 | */ 22 | 'system_path' => __DIR__.'/system', 23 | 24 | /** 25 | * Spoof $_SERVER variables 26 | * 27 | * This array will be merged with $_SERVER. 28 | * 29 | * When using php from the command line, 30 | * things like HTTP_HOST and DOCUMENT_ROOT 31 | * do not get set. 32 | * 33 | * Useful if you check for $_SERVER items 34 | * at runtime, like changing DB 35 | * credentials based on HTTP_HOST 36 | * in your config.php. 37 | * 38 | * You can also set these at the command line: 39 | * 40 | * HTTP_HOST="foo.dev" eecli update:addons 41 | */ 42 | 'server' => array( 43 | 'HTTP_HOST' => 'localhost', 44 | 'DOCUMENT_ROOT' => __DIR__, 45 | 'REQUEST_URI' => '/', 46 | 'REMOTE_ADDR' => '127.0.0.1', 47 | 'HTTP_USER_AGENT' => 'eecli', 48 | ), 49 | 50 | /** 51 | * Assign variables to config 52 | */ 53 | 'assign_to_config' => array( 54 | #'foo' => 'bar', 55 | ), 56 | 57 | /** 58 | * Custom commands 59 | * 60 | * An array of Command class names of 61 | * custom commands. 62 | */ 63 | 'commands' => array( 64 | #'\\Your\\Custom\\Command', 65 | ), 66 | 67 | /** 68 | * Custom command directories 69 | * 70 | * An array of directories, keyed by a namespace prefix, 71 | * which will be crawled for Command classes. 72 | */ 73 | 'commandDirs' => array( 74 | /* 75 | '\\Your\\Namespace' => '/path/to/commands', 76 | */ 77 | ), 78 | 79 | /** 80 | * Event Callbacks 81 | * 82 | * An array of callback functions to be 83 | * invoked on the specified event. 84 | */ 85 | 'callbacks' => array( 86 | /* 87 | 'bootstrap.before' => function ($app) { 88 | }, 89 | 'bootstrap.after' => function ($app) { 90 | }, 91 | */ 92 | ), 93 | 94 | /** 95 | * The default addon author name used when generating addons. 96 | */ 97 | 'addon_author_name' => '', 98 | 99 | /** 100 | * The default addon author URL used when generating addons. 101 | */ 102 | 'addon_author_url' => '', 103 | ); 104 | -------------------------------------------------------------------------------- /src/CodeIgniter/BootableInterface.php: -------------------------------------------------------------------------------- 1 | app = $app; 35 | 36 | $this->output = $output; 37 | 38 | // you need to load the template library to override the fatal error 39 | ee()->load->library('template', null, 'TMPL'); 40 | } 41 | 42 | /** 43 | * Reset errorMessage and successMessage to null 44 | * @return void 45 | */ 46 | public function resetMessages() 47 | { 48 | $this->errorMessage = null; 49 | $this->successMessage = null; 50 | } 51 | 52 | /** 53 | * Suppress any header-setting 54 | * @param string $header 55 | * @param boolean $replace 56 | */ 57 | public function set_header($header, $replace = true) 58 | { 59 | } 60 | 61 | /** 62 | * {@inheritdoc} 63 | */ 64 | public function fatal_error($errorMessage = '', $useLang = true) 65 | { 66 | $errorMessage = str_replace('« Back', '', $errorMessage); 67 | 68 | $errorMessage = strip_tags($errorMessage); 69 | 70 | $this->output->writeln("{$errorMessage}"); 71 | 72 | exit; 73 | } 74 | 75 | /** 76 | * Get a success message 77 | * @return string|null 78 | */ 79 | public function getSuccessMessage() 80 | { 81 | return $this->successMessage; 82 | } 83 | 84 | /** 85 | * Get an error message 86 | * @return string|null 87 | */ 88 | public function getErrorMessage() 89 | { 90 | return $this->errorMessage; 91 | } 92 | 93 | /** 94 | * {@inheritdoc} 95 | */ 96 | public function send_ajax_response($data, $error = false) 97 | { 98 | $this->resetMessages(); 99 | 100 | $property = $error ? 'errorMessage' : 'successMessage'; 101 | 102 | if (is_scalar($data)) { 103 | $this->{$property} = $data; 104 | } elseif (! empty($data['error'])) { 105 | $this->errorMessage = $data['error']; 106 | } elseif (! empty($data['message_failure'])) { 107 | $this->errorMessage = $data['message_failure']; 108 | } elseif (! empty($data['success'])) { 109 | $this->successMessage = $data['success']; 110 | } elseif (! empty($data['message_success'])) { 111 | $this->successMessage = $data['message_success']; 112 | } elseif (is_array($data) && is_string(current($data))) { 113 | $this->{$property} = implode(PHP_EOL, $data); 114 | } else { 115 | $this->{$property} = print_r($data, true); 116 | } 117 | } 118 | 119 | /** 120 | * {@inheritdoc} 121 | */ 122 | public function show_message($data, $xhtml = true) 123 | { 124 | $this->resetMessages(); 125 | 126 | if (isset($data['content'])) { 127 | $this->successMessage = strip_tags($data['content']); 128 | } else { 129 | $this->successMessage = ''; 130 | } 131 | } 132 | 133 | /** 134 | * {@inheritdoc} 135 | */ 136 | public function show_user_error($type, $errors, $heading = '') 137 | { 138 | $this->resetMessages(); 139 | 140 | if (! is_array($errors)) { 141 | $errors = array($errors); 142 | } 143 | 144 | foreach ($errors as $error) { 145 | $this->app->addError($error); 146 | } 147 | 148 | $this->errorMessage = implode(PHP_EOL, $errors); 149 | } 150 | } 151 | -------------------------------------------------------------------------------- /src/CodeIgniter/Controller/AdminContentController.php: -------------------------------------------------------------------------------- 1 | bootCp(); 15 | 16 | ee()->lang->loadfile('admin'); 17 | ee()->lang->loadfile('admin_content'); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/CodeIgniter/Controller/ContentFilesController.php: -------------------------------------------------------------------------------- 1 | bootCp(); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/CodeIgniter/Controller/DesignController.php: -------------------------------------------------------------------------------- 1 | bootCp(); 15 | 16 | ee()->load->model('template_model'); 17 | 18 | ee()->lang->loadfile('design'); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/CodeIgniter/Controller/MembersController.php: -------------------------------------------------------------------------------- 1 | bootCp(); 15 | 16 | ee()->lang->loadfile('members'); 17 | ee()->load->model('member_model'); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/CodeIgniter/Cp.php: -------------------------------------------------------------------------------- 1 | cp_theme = $theme; 17 | $this->cp_theme_url = $themeUrl; 18 | $this->EE = get_instance(); 19 | } 20 | 21 | /** 22 | * Get the stored view variables 23 | * @return array 24 | */ 25 | public function getVariables() 26 | { 27 | // get cached view vars 28 | $reflector = new \ReflectionClass('EE_Loader'); 29 | 30 | $property = $reflector->getProperty('_ci_cached_vars'); 31 | 32 | $property->setAccessible(true); 33 | 34 | $variables = $property->getValue(ee()->load); 35 | 36 | if (! is_array($variables)) { 37 | return $this->variables; 38 | } 39 | 40 | return array_merge($variables, $this->variables); 41 | } 42 | 43 | /** 44 | * Override the parent class' render method 45 | * 46 | * Don't render anything, simply save the view 47 | * variables for later usage. See getViewData(). 48 | * @param string $view 49 | * @param array $data 50 | * @param boolean $return 51 | * @return void 52 | */ 53 | public function render($view, $data = array(), $return = false) 54 | { 55 | $this->variables = array_merge($this->variables, $data); 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /src/CodeIgniter/Functions.php: -------------------------------------------------------------------------------- 1 | output = $output; 47 | 48 | $this->app = $app; 49 | 50 | // for EE 2.5 51 | $this->EE = get_instance(); 52 | } 53 | 54 | /** 55 | * Suppress redirections and print any messages 56 | * stored in session flashdata 57 | * 58 | * @param string $location 59 | * @param boolean $method 60 | * @param int|null $statusCode 61 | * @return void 62 | */ 63 | public function redirect($location, $method = false, $statusCode = null) 64 | { 65 | $this->successMessage = null; 66 | $this->errorMessage = null; 67 | 68 | $location = str_replace('&', '&', $location); 69 | 70 | if (substr_count($location, '?') > 1) { 71 | $location = substr($location, strpos($location, '?') + 1); 72 | } 73 | 74 | parse_str(parse_url($location, PHP_URL_QUERY), $this->variables); 75 | 76 | $success = ee()->session->flashdata(':new:message_success'); 77 | $failure = ee()->session->flashdata(':new:message_failure'); 78 | 79 | if ($failure) { 80 | $this->app->addError($failure); 81 | 82 | $this->errorMessage = $failure; 83 | } 84 | 85 | if ($success) { 86 | $this->successMessage = $success; 87 | } 88 | } 89 | 90 | /** 91 | * Reset errorMessage and successMessage to null 92 | * @return void 93 | */ 94 | public function resetMessages() 95 | { 96 | $this->errorMessage = null; 97 | $this->successMessage = null; 98 | } 99 | 100 | /** 101 | * Get the flashdata error message 102 | * @return string|null 103 | */ 104 | public function getErrorMessage() 105 | { 106 | return $this->errorMessage; 107 | } 108 | 109 | /** 110 | * Get the flashdata success message 111 | * @return string|null 112 | */ 113 | public function getSuccessMessage() 114 | { 115 | return $this->successMessage; 116 | } 117 | 118 | /** 119 | * Get the redirect query string variables 120 | * @return array 121 | */ 122 | public function getVariables() 123 | { 124 | return $this->variables; 125 | } 126 | } 127 | -------------------------------------------------------------------------------- /src/Command/AbstractCreateFieldCommand.php: -------------------------------------------------------------------------------- 1 | db->select('name') 35 | ->get('fieldtypes'); 36 | 37 | foreach ($query->result() as $row) { 38 | static::$fieldtypesInstalled[$row->name] = true; 39 | } 40 | 41 | $query->free_result(); 42 | } 43 | } 44 | 45 | /** 46 | * {@inheritdoc} 47 | */ 48 | public function isApplicable() 49 | { 50 | static::loadInstalledFieldtypes(); 51 | 52 | return isset(static::$fieldtypesInstalled[$this->getFieldtype()]); 53 | } 54 | 55 | /** 56 | * Array of InputOption objects for this fieldtype 57 | * @return array of \Symfony\Component\Console\Input\InputOption 58 | */ 59 | protected function getFieldtypeOptions() 60 | { 61 | return array(); 62 | } 63 | 64 | /** 65 | * Array of fieldtype settings, to be merge into $_POST 66 | * @return array 67 | */ 68 | protected function getFieldtypeSettings() 69 | { 70 | return array(); 71 | } 72 | 73 | protected function getFieldtypeOptionExamples() 74 | { 75 | return array(); 76 | } 77 | 78 | /** 79 | * {@inheritdoc} 80 | */ 81 | public function __construct() 82 | { 83 | $this->name = 'create:field:'.$this->getFieldtype(); 84 | 85 | parent::__construct(); 86 | } 87 | 88 | /** 89 | * {@inheritdoc} 90 | */ 91 | protected function getArguments() 92 | { 93 | return array( 94 | array( 95 | 'label', // name 96 | InputArgument::REQUIRED, // mode 97 | 'The label of the field.', // description 98 | ), 99 | array( 100 | 'short_name', // name 101 | InputArgument::REQUIRED, // mode 102 | 'The short name of the field.', // description 103 | ), 104 | array( 105 | 'field_group', // name 106 | InputArgument::REQUIRED, // mode 107 | 'The ID or name of the field group.', // description 108 | ), 109 | ); 110 | } 111 | 112 | /** 113 | * {@inheritdoc} 114 | */ 115 | protected function getOptions() 116 | { 117 | return array_merge(array( 118 | array( 119 | 'instructions', 120 | null, 121 | InputOption::VALUE_REQUIRED, 122 | 'Instructions for authors on how or what to enter into this field when submitting an entry.', 123 | '', 124 | ), 125 | array( 126 | 'required', 127 | null, 128 | InputOption::VALUE_NONE, 129 | 'Make this field required', 130 | ), 131 | array( 132 | 'searchable', 133 | null, 134 | InputOption::VALUE_NONE, 135 | 'Make this field searchable', 136 | ), 137 | array( 138 | 'hidden', 139 | null, 140 | InputOption::VALUE_NONE, 141 | 'Make this field hidden', 142 | ), 143 | array( 144 | 'order', 145 | null, 146 | InputOption::VALUE_REQUIRED, 147 | 'Set this field\'s order', 148 | ), 149 | ), $this->getFieldtypeOptions()); 150 | } 151 | 152 | /** 153 | * {@inheritdoc} 154 | */ 155 | protected function fire() 156 | { 157 | $instance = $this->getApplication()->newControllerInstance('\\eecli\\CodeIgniter\\Controller\\AdminContentController'); 158 | 159 | $groupId = $this->argument('field_group'); 160 | 161 | if (! is_numeric($groupId)) { 162 | $query = ee()->db->select('group_id') 163 | ->where('group_name', $groupId) 164 | ->limit(1) 165 | ->get('field_groups'); 166 | 167 | if ($query->num_rows() > 0) { 168 | $groupId = $query->row('group_id'); 169 | } 170 | 171 | $query->free_result(); 172 | } 173 | 174 | $name = $this->argument('short_name'); 175 | 176 | // get field order 177 | $order = $this->option('order'); 178 | 179 | if (! $order && $order !== '0') { 180 | $query = $instance->db->select('field_order') 181 | ->where('group_id', $groupId) 182 | ->order_by('field_order', 'desc') 183 | ->limit(1) 184 | ->get('channel_fields'); 185 | 186 | if ($query->num_rows() > 0) { 187 | $order = $query->row('field_order') + 1; 188 | } 189 | 190 | $query->free_result(); 191 | } 192 | 193 | $_POST = array( 194 | 'site_id' => $instance->config->item('site_id'), 195 | 'group_id' => $groupId, 196 | 'field_label' => $this->argument('label'), 197 | 'field_name' => $name, 198 | 'field_type' => $this->getFieldtype(), 199 | 'field_instructions' => $this->option('instructions'), 200 | 'field_required' => $this->option('required') ? 'y' : 'n', 201 | 'field_search' => $this->option('searchable') ? 'y' : 'n', 202 | 'field_is_hidden' => $this->option('hidden') ? 'y' : 'n', 203 | 'field_order' => $order, 204 | 'field_maxl' => '128', 205 | 'field_ta_rows' => '6', 206 | ); 207 | 208 | $_POST = array_merge($_POST, $this->getFieldtypeSettings()); 209 | 210 | $method = version_compare(APP_VER, '2.7', '<') ? 'field_update' : 'field_edit'; 211 | 212 | $instance->$method(); 213 | 214 | $this->getApplication()->checkForErrors(true); 215 | 216 | $query = ee()->db->select('field_id') 217 | ->where('field_name', $name) 218 | ->where('group_id', $groupId) 219 | ->get('channel_fields'); 220 | 221 | $this->info(sprintf('Field %s (%s) created.', $name, $query->row('field_id'))); 222 | 223 | $query->free_result(); 224 | } 225 | 226 | public function getOptionExamples() 227 | { 228 | $optionExamples = array( 229 | 'instructions' => 'Your instructions here.', 230 | 'order' => '1', 231 | 'content_type' => 'all', 232 | ); 233 | 234 | return array_merge($optionExamples, $this->getFieldtypeOptionExamples()); 235 | } 236 | } 237 | -------------------------------------------------------------------------------- /src/Command/AbstractCreateFieldFieldpackOptionsCommand.php: -------------------------------------------------------------------------------- 1 | getOptionPrefix().'_options' => implode("\n", $this->option('option')), 31 | ); 32 | } 33 | 34 | protected function getOptionPrefix() 35 | { 36 | return $this->getFieldtype(); 37 | } 38 | 39 | protected function getFieldtypeOptionExamples() 40 | { 41 | return array( 42 | 'option' => 'option_value : Option Label', 43 | ); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/Command/AbstractCreateFieldNativeOptionsCommand.php: -------------------------------------------------------------------------------- 1 | getFieldtype().'_field_fmt' => $this->option('format'), 50 | $this->getFieldtype().'_field_show_fmt' => $this->option('show_format') ? 'y' : 'n', 51 | $this->getFieldtype().'_field_list_items' => implode("\n", $this->option('option')), 52 | $this->getFieldtype().'_field_pre_populate' => $this->option('pre_populate') ? 'y' : 'n', 53 | $this->getFieldtype().'_field_pre_populate_id' => $this->option('pre_populate'), 54 | ); 55 | } 56 | 57 | public function getFieldtypeOptionExamples() 58 | { 59 | return array( 60 | 'option' => 'Foo', 61 | 'pre_populate' => '1', 62 | ); 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /src/Command/ClearCeCacheCommand.php: -------------------------------------------------------------------------------- 1 | lang->loadfile('ce_cache', 'ce_cache'); 76 | 77 | $items = $this->argument('items'); 78 | $tags = $this->option('tags'); 79 | $drivers = $this->option('driver'); 80 | $refresh = $this->option('refresh') ? true : false; 81 | $refresh_time = $this->option('refresh_time'); 82 | 83 | 84 | $defaultDrivers = array('file', 'db', 'static', 'apc', 'memcache', 'memcached', 'redis', 'dummy'); 85 | 86 | if ($drivers) { 87 | $invalidDrivers = array_diff($drivers, $defaultDrivers); 88 | 89 | if ($invalidDrivers) { 90 | throw new \RuntimeException('Invalid driver(s) specified: '.implode(', ', $invalidDrivers)); 91 | } 92 | 93 | $drivers = array_intersect($drivers, $defaultDrivers); 94 | } else { 95 | $drivers = $defaultDrivers; 96 | } 97 | 98 | // if there are no arguments, clear all caches 99 | if (! $items) { 100 | require_once PATH_THIRD.'ce_cache/libraries/Ce_cache_factory.php'; 101 | 102 | $drivers = \Ce_cache_factory::factory($drivers); 103 | 104 | foreach ($drivers as $driver) { 105 | $driverName = lang('ce_cache_driver_'.$driver->name()); 106 | 107 | if ($driver->clear() === false) { 108 | $this->error(sprintf(lang('ce_cache_error_cleaning_driver_cache'), $driverName)); 109 | } else { 110 | $this->comment($driverName.' cache cleared.'); 111 | } 112 | } 113 | } else { 114 | require_once PATH_THIRD.'ce_cache/libraries/Ce_cache_break.php'; 115 | 116 | $breaker = new \Ce_cache_break(); 117 | 118 | $name = $tags ? 'Tag' : 'Item'; 119 | 120 | $which = $tags ? 1 : 0; 121 | 122 | $time = $refresh_time ?: 1; 123 | 124 | $defaultArgs = array(array(), array(), $refresh, $time); 125 | 126 | foreach ($items as $item) { 127 | $args = $defaultArgs; 128 | 129 | $args[$which][] = $item; 130 | 131 | call_user_func_array(array($breaker, 'break_cache'), $args); 132 | 133 | $this->comment($name.' '.$item.' cleared.'); 134 | 135 | if ($refresh) { 136 | $this->comment($name.' '.$item.' will be refreshed'); 137 | } 138 | } 139 | } 140 | 141 | $this->info('CE Cache cleared.'); 142 | } 143 | 144 | /** 145 | * {@inheritdoc} 146 | */ 147 | public function getExamples() 148 | { 149 | return array( 150 | 'Clear all caches' => '', 151 | 'Clear a specific item' => 'local/foo/item', 152 | 'Clear specific items' => 'local/foo/item local/bar/item', 153 | 'Clear specific tags' => '--tags foo bar', 154 | 'Clear specific driver' => '--driver="file"', 155 | 'Set cache to refresh after clear' => '--refresh', 156 | 'Set the number of seconds to wait before refreshing and deleting items' => '--refresh-time="2"', 157 | ); 158 | } 159 | 160 | public function getLongDescription() 161 | { 162 | return "Clears the CE Cache.\n\nBe sure to set your [`http_host`](Global Options) when using the `refresh` option, so `eecli` will know your site's URL."; 163 | } 164 | 165 | public function getOptionExamples() 166 | { 167 | return array( 168 | 'driver' => 'file', 169 | 'refresh-time' => '1', 170 | ); 171 | } 172 | } 173 | -------------------------------------------------------------------------------- /src/Command/ClearEECacheCommand.php: -------------------------------------------------------------------------------- 1 | argument('type') ?: 'all'; 42 | 43 | if (! in_array($type, $validTypes)) { 44 | $this->error('Invalid cache type'); 45 | 46 | return; 47 | } 48 | 49 | ee()->functions->clear_caching($type); 50 | 51 | $suffix = $type === 'all' ? '' : ' '.$type; 52 | 53 | $this->info('EE'.$suffix.' cache cleared.'); 54 | } 55 | 56 | /** 57 | * {@inheritdoc} 58 | */ 59 | public function getExamples() 60 | { 61 | return array( 62 | 'Clear all EE caches' => '', 63 | 'Clear EE page caches' => 'page', 64 | 'Clear EE db caches' => 'db', 65 | 'Clear EE tag caches' => 'tag', 66 | ); 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /src/Command/ClearStashCacheCommand.php: -------------------------------------------------------------------------------- 1 | db->truncate('stash'); 25 | 26 | $this->info('Stash cache cleared.'); 27 | } 28 | 29 | /** 30 | * {@inheritdoc} 31 | */ 32 | public function getExamples() 33 | { 34 | return array( 35 | 'Clear all caches' => '', 36 | ); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/Command/Command.php: -------------------------------------------------------------------------------- 1 | $method(); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/Command/ConsoleCommand.php: -------------------------------------------------------------------------------- 1 | setAliases(array( 25 | 'repl', 26 | )); 27 | } 28 | 29 | /** 30 | * {@inheritdoc} 31 | */ 32 | protected function fire() 33 | { 34 | $requiredExtensions = array('readline', 'posix', 'pcntl'); 35 | 36 | foreach ($requiredExtensions as $extension) { 37 | if (! extension_loaded($extension)) { 38 | throw new \Exception(sprintf('PHP %s extension is required for this command.', $extension)); 39 | } 40 | } 41 | 42 | $boris = new Boris('> '); 43 | 44 | $boris->start(); 45 | } 46 | 47 | /** 48 | * {@inheritdoc} 49 | */ 50 | public function getLongDescription() 51 | { 52 | return << arguments 10 | * 11 | * @return array 12 | */ 13 | public function getExamples(); 14 | } 15 | -------------------------------------------------------------------------------- /src/Command/Contracts/HasLongDescription.php: -------------------------------------------------------------------------------- 1 | option value 10 | * 11 | * @return array 12 | */ 13 | public function getOptionExamples(); 14 | } 15 | -------------------------------------------------------------------------------- /src/Command/Contracts/HasRuntimeOptions.php: -------------------------------------------------------------------------------- 1 | db->where('group_id', $group); 84 | } else { 85 | ee()->db->where('group_name', $group); 86 | } 87 | 88 | $query = ee()->db->select('group_id') 89 | ->get('category_groups'); 90 | 91 | if ($query->num_rows() === 0) { 92 | throw new \RuntimeException('Invalid group.'); 93 | } 94 | 95 | $groupId = $query->row('group_id'); 96 | 97 | $query->free_result(); 98 | 99 | return $groupId; 100 | } 101 | 102 | /** 103 | * Get category fields by group ID 104 | * @param string $groupId 105 | * @return array of \stdClass 106 | */ 107 | protected function getCategoryGroupFields($groupId) 108 | { 109 | $query = ee()->db->where('group_id', $groupId) 110 | ->order_by('field_order', 'asc') 111 | ->get('category_fields'); 112 | 113 | $fields = $query->result(); 114 | 115 | $query->free_result(); 116 | 117 | return $fields; 118 | } 119 | 120 | /** 121 | * {@inheritdoc} 122 | */ 123 | public function getRuntimeOptions(Application $app, InputInterface $input) 124 | { 125 | $group = $input->getArgument('cat_group'); 126 | 127 | $groupId = $this->getCategoryGroupId($group); 128 | 129 | $fields = $this->getCategoryGroupFields($groupId); 130 | 131 | $options = array(); 132 | 133 | foreach ($fields as $field) { 134 | $options[] = new InputOption( 135 | $field->field_name, 136 | null, 137 | InputOption::VALUE_REQUIRED, 138 | $field->field_label 139 | ); 140 | } 141 | 142 | return $options; 143 | } 144 | 145 | /** 146 | * {@inheritdoc} 147 | */ 148 | protected function fire() 149 | { 150 | $instance = $this->getApplication()->newControllerInstance('\\eecli\\CodeIgniter\\Controller\\AdminContentController'); 151 | 152 | $name = $this->argument('name'); 153 | 154 | $group = $this->argument('cat_group'); 155 | 156 | $groupId = $this->getCategoryGroupId($group); 157 | 158 | $fields = $this->getCategoryGroupFields($groupId); 159 | 160 | $_SERVER['CONTENT_LENGTH'] = 0; 161 | 162 | $_POST = array( 163 | 'group_id' => $groupId, 164 | 'cat_name' => $name, 165 | 'cat_url_title' => $this->option('url_title'), 166 | 'cat_description' => $this->option('description'), 167 | 'cat_image_hidden_file' => '', 168 | 'cat_image_hidden_dir' => '', 169 | 'cat_image_directory' => '', 170 | 'parent_id' => $this->option('parent_id'), 171 | ); 172 | 173 | foreach ($fields as $field) { 174 | $_POST['field_ft_'.$field->field_id] = $field->field_default_fmt; 175 | 176 | $value = $this->option($field->field_name); 177 | 178 | if ($field->field_required === 'y' && empty($value)) { 179 | $this->error(sprintf('The --%s option is required for this category group.', $field->field_name)); 180 | 181 | return; 182 | } 183 | 184 | $_POST['field_id_'.$field->field_id] = $value; 185 | } 186 | 187 | $instance->category_update(); 188 | 189 | $this->getApplication()->checkForErrors(true); 190 | 191 | $query = $instance->db->select('cat_id') 192 | ->where('cat_name', $name) 193 | ->where('group_id', $groupId) 194 | ->order_by('cat_id', 'desc') 195 | ->get('categories'); 196 | 197 | $this->info(sprintf('Category %s (%s) created.', $name, $query->row('cat_id'))); 198 | 199 | $query->free_result(); 200 | } 201 | 202 | /** 203 | * {@inheritdoc} 204 | */ 205 | public function getExamples() 206 | { 207 | return array( 208 | 'Create a category in the specfied group (by ID)' => '"16th Century" 1', 209 | 'Create a category in the specified group (by name)' => 'Prehistoric "Time Periods"', 210 | 'Create a category with a custom url title' => '--url_title="16th" "16th Century" 1', 211 | 'Create a category with the specified parent_id' => '--parent_id=12 "1920s" 1', 212 | 'Create a category with the specified description' => '--description="The Roaring 20s" "1920s" 1', 213 | 'Create a category with one (or more) custom category fields' => '--your_category_field="The Roaring 20s" "1920s" 1', 214 | ); 215 | } 216 | 217 | public function getOptionExamples() 218 | { 219 | return array( 220 | 'url_title' => 'your_category', 221 | 'description' => 'Your description here.', 222 | 'parent_id' => '1', 223 | ); 224 | } 225 | } 226 | -------------------------------------------------------------------------------- /src/Command/CreateCategoryGroupCommand.php: -------------------------------------------------------------------------------- 1 | getApplication()->newControllerInstance('\\eecli\\CodeIgniter\\Controller\\AdminContentController'); 40 | 41 | $name = $this->argument('name'); 42 | 43 | $_POST = array( 44 | 'group_name' => $name, 45 | 'field_html_formatting' => 'all', 46 | 'exclude_group' => '0', 47 | ); 48 | 49 | ee()->update_category_group(); 50 | 51 | $this->getApplication()->checkForErrors(true); 52 | 53 | $query = ee()->db->select('group_id') 54 | ->where('group_name', $name) 55 | ->where('site_id', ee()->config->item('site_id')) 56 | ->get('category_groups'); 57 | 58 | $this->info(sprintf('Category group %s (%s) created.', $name, $query->row('group_id'))); 59 | 60 | $query->free_result(); 61 | } 62 | 63 | public function getExamples() 64 | { 65 | return array( 66 | 'Create a category group' => '"Art and Science"', 67 | ); 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /src/Command/CreateFieldAssetsCommand.php: -------------------------------------------------------------------------------- 1 | option('upload_dir'); 70 | 71 | // validate these as ee:1, etc 72 | if ($dirs) { 73 | foreach ($dirs as $dir) { 74 | if (! preg_match('/^(ee|s3|rs|gc):(\d+)$/', $dir)) { 75 | throw new \RuntimeException('Upload dir is not in the proper format. ex. ee:1, sc:2'); 76 | } 77 | } 78 | } 79 | 80 | return array( 81 | 'assets' => array( 82 | 'filedirs' => $dirs ?: array('all'), 83 | 'view' => $this->option('view'), 84 | 'thumb_size' => $this->option('thumb_size'), 85 | 'show_cols' => array('folder', 'date', 'size'), 86 | 'show_filenames' => $this->option('show_filenames') ? 'y' : 'n', 87 | 'multi' => $this->option('multiple') ? 'y' : 'n', 88 | ), 89 | ); 90 | } 91 | 92 | public function getExamples() 93 | { 94 | return array( 95 | 'Create an Assets field in field group 1' => '"Your Field Name" your_field_name 1', 96 | 'Create an Assets field that uploads to EE directory 1' => '--upload_dir="ee:1" "Your Field Name" your_field_name 1', 97 | 'Create an Assets field that uploads to S3 directory 2' => '--upload_dir="s3:2" "Your Field Name" your_field_name 1', 98 | 'Create an Assets field that allows multiple selections' => '--multiple "Your Field Name" your_field_name 1', 99 | ); 100 | } 101 | 102 | protected function getFieldtypeOptionExamples() 103 | { 104 | return array( 105 | 'upload_dir' => '1', 106 | ); 107 | } 108 | } 109 | -------------------------------------------------------------------------------- /src/Command/CreateFieldCheckboxesCommand.php: -------------------------------------------------------------------------------- 1 | '"Your Field Name" your_field_name 1', 24 | 'Create a Checkboxes field with multiple options' => '--option="Foo" --option="Bar" "Name" name 1', 25 | ); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/Command/CreateFieldDateCommand.php: -------------------------------------------------------------------------------- 1 | '"Your Field Name" your_field_name 1', 26 | ); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/Command/CreateFieldFieldpackCheckboxesCommand.php: -------------------------------------------------------------------------------- 1 | '"Your Field Name" your_field_name 1', 26 | 'Create a Fieldpack Checkboxes field with multiple options' => '--option="foo : Foo" --option="bar : Bar" "Name" name 1', 27 | ); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/Command/CreateFieldFieldpackDropdownCommand.php: -------------------------------------------------------------------------------- 1 | '"Your Field Name" your_field_name 1', 26 | 'Create a Fieldpack Dropdown field with multiple options' => '--option="foo : Foo" --option="bar : Bar" "Name" name 1', 27 | ); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/Command/CreateFieldFieldpackListCommand.php: -------------------------------------------------------------------------------- 1 | '"Your Field Name" your_field_name 1', 26 | ); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/Command/CreateFieldFieldpackMultiselectCommand.php: -------------------------------------------------------------------------------- 1 | '"Your Field Name" your_field_name 1', 26 | 'Create a Fieldpack Multiselect field with multiple options' => '--option="foo : Foo" --option="bar : Bar" "Name" name 1', 27 | ); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/Command/CreateFieldFieldpackPillCommand.php: -------------------------------------------------------------------------------- 1 | '"Your Field Name" your_field_name 1', 31 | 'Create a Fieldpack Pill field with multiple options' => '--option="foo : Foo" --option="bar : Bar" "Name" name 1', 32 | ); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/Command/CreateFieldFieldpackRadioCommand.php: -------------------------------------------------------------------------------- 1 | '"Your Field Name" your_field_name 1', 26 | 'Create a Fieldpack Radio Buttons field with multiple options' => '--option="foo : Foo" --option="bar : Bar" "Name" name 1', 27 | ); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/Command/CreateFieldFieldpackSwitchCommand.php: -------------------------------------------------------------------------------- 1 | array( 73 | 'off_label' => $this->option('off_label'), 74 | 'off_val' => $this->option('off_value'), 75 | 'on_label' => $this->option('on_label'), 76 | 'on_val' => $this->option('on_value'), 77 | 'default' => $this->option('default'), 78 | ), 79 | ); 80 | } 81 | 82 | public function getExamples() 83 | { 84 | return array( 85 | 'Create a Fieldpack Switch field in field group 1' => '"Your Field Name" your_field_name 1', 86 | 'Create a Fieldpack Switch field with options' => '--off_label="Nope" --on_label="Yep" "Name" name 1', 87 | ); 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /src/Command/CreateFieldFileCommand.php: -------------------------------------------------------------------------------- 1 | $this->option('content_type'), 66 | 'file_allowed_directories' => $this->option('upload_dir'), 67 | 'file_show_existing' => $this->option('hide_existing') ? 'n' : 'y', 68 | 'file_num_existing' => $this->option('limit'), 69 | ); 70 | } 71 | 72 | protected function getFieldtypeOptionExamples() 73 | { 74 | return array( 75 | 'upload_dir' => '1', 76 | ); 77 | } 78 | 79 | public function getExamples() 80 | { 81 | return array( 82 | 'Create a File field in field group 1' => '"Your Field Name" your_field_name 1', 83 | 'Create a File field that uploads to directory 1' => '--upload_dir=1 "Your Field Name" your_field_name 1', 84 | 'Create a File field that only allows images' => '--content_type=image "Your Field Name" your_field_name 1', 85 | ); 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /src/Command/CreateFieldGridCommand.php: -------------------------------------------------------------------------------- 1 | $this->option('min_rows'), 53 | 'grid_max_rows' => $this->option('max_rows'), 54 | 'grid' => array( 55 | 'cols' => array(), 56 | ), 57 | ); 58 | } 59 | 60 | protected function getFieldtypeOptionExamples() 61 | { 62 | return array( 63 | 'max_rows' => '3', 64 | ); 65 | } 66 | 67 | public function getExamples() 68 | { 69 | return array( 70 | 'Create a Grid field in field group 1' => '"Your Field Name" your_field_name 1', 71 | 'Create a Grid field with max and min rows' => '--min_rows="1" --max_rows="3" "Name" name 1', 72 | ); 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /src/Command/CreateFieldGroupCommand.php: -------------------------------------------------------------------------------- 1 | getApplication()->newControllerInstance('\\eecli\\CodeIgniter\\Controller\\AdminContentController'); 40 | 41 | $name = $this->argument('name'); 42 | 43 | $_POST = array( 44 | 'group_name' => $name, 45 | ); 46 | 47 | ee()->field_group_update(); 48 | 49 | if (ee()->output->getErrorMessage()) { 50 | $this->error(ee()->output->getErrorMessage()); 51 | 52 | return; 53 | } 54 | 55 | $query = ee()->db->select('group_id') 56 | ->where('group_name', $name) 57 | ->where('site_id', ee()->config->item('site_id')) 58 | ->get('field_groups'); 59 | 60 | $this->info(sprintf('Field group %s (%s) created.', $name, $query->row('group_id'))); 61 | 62 | $query->free_result(); 63 | } 64 | 65 | public function getExamples() 66 | { 67 | return array( 68 | 'Create a field group' => 'Blog', 69 | ); 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /src/Command/CreateFieldMatrixCommand.php: -------------------------------------------------------------------------------- 1 | array( 53 | 'min_rows' => $this->option('min_rows'), 54 | 'max_rows' => $this->option('max_rows'), 55 | 'col_order' => array(), 56 | 'cols' => array(), 57 | ), 58 | ); 59 | } 60 | 61 | protected function getFieldtypeOptionExamples() 62 | { 63 | return array( 64 | 'max_rows' => '3', 65 | ); 66 | } 67 | 68 | public function getExamples() 69 | { 70 | return array( 71 | 'Create a Matrix field in field group 1' => '"Your Field Name" your_field_name 1', 72 | 'Create a Matrix field with max and min rows' => '--min_rows="1" --max_rows="3" "Name" name 1', 73 | ); 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /src/Command/CreateFieldMultiselectCommand.php: -------------------------------------------------------------------------------- 1 | '"Your Field Name" your_field_name 1', 26 | 'Create a Multiselect field with multiple options' => '--option="Foo" --option="Bar" "Name" name 1', 27 | ); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/Command/CreateFieldPlayaCommand.php: -------------------------------------------------------------------------------- 1 | option('channel') as $channelId) { 121 | if (! is_numeric($channelId)) { 122 | $query = ee()->db->select('channel_id') 123 | ->where('channel_name', $channelId) 124 | ->limit(1) 125 | ->get('channels'); 126 | 127 | if ($query->num_rows() > 0) { 128 | $channelId = $query->row('channel_id'); 129 | } 130 | 131 | $query->free_result(); 132 | } 133 | 134 | $channelIds[] = $channelId; 135 | } 136 | 137 | return array( 138 | 'playa' => array( 139 | 'sites' => $this->option('site') ?: array('any'), 140 | 'channels' => $channelIds ?: array('any'), 141 | 'expired' => $this->option('expired') ? 'y' : 'n', 142 | 'future' => $this->option('future') ? 'y' : 'n', 143 | 'editable' => $this->option('editable') ? 'y' : 'n', 144 | 'cats' => $this->option('category') ?: array('any'), 145 | 'authors' => $this->option('author') ?: array('any'), 146 | 'member_groups' => $this->option('member_group') ?: array('any'), 147 | 'statuses' => $this->option('status') ?: array('any'), 148 | 'limit' => $this->option('limit'), 149 | 'limitby' => 'newest', 150 | 'orderby' => $this->option('order_by'), 151 | 'sort' => strtoupper($this->option('sort')), 152 | 'multi' => $this->option('multiple') ? 'y' : 'n', 153 | ), 154 | ); 155 | } 156 | 157 | protected function getFieldtypeOptionExamples() 158 | { 159 | return array( 160 | 'site' => '1', 161 | 'channel' => '1', 162 | 'category' => '1', 163 | 'author' => '1', 164 | 'member_group' => '1', 165 | 'status' => 'open', 166 | ); 167 | } 168 | 169 | public function getExamples() 170 | { 171 | return array( 172 | 'Create a Playa field in field group 1' => '"Your Field Name" your_field_name 1', 173 | 'Create a Playa field with multiple channels' => '--channel=1 --channel=blog "Your Field Name" your_field_name 1', 174 | 'Create a Playa field with multiple statuses' => '--status=closed --status=open "Your Field Name" your_field_name 1', 175 | 'Create a Playa field with multiple selection' => '--multiple "Your Field Name" your_field_name 1', 176 | ); 177 | } 178 | } 179 | -------------------------------------------------------------------------------- /src/Command/CreateFieldRadioCommand.php: -------------------------------------------------------------------------------- 1 | '"Your Field Name" your_field_name 1', 26 | 'Create a Radio field with multiple options' => '--option="Foo" --option="Bar" "Name" name 1', 27 | ); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/Command/CreateFieldRelationshipCommand.php: -------------------------------------------------------------------------------- 1 | option('author'); 107 | $groupIds = $this->option('member_group'); 108 | 109 | $authors = array(); 110 | 111 | if ($authorIds || $groupIds) { 112 | foreach ($authorIds as $authorId) { 113 | $authors[] = 'm_'.$authorId; 114 | } 115 | foreach ($groupIds as $groupId) { 116 | $authors[] = 'g_'.$groupId; 117 | } 118 | } else { 119 | $authors[] = '--'; 120 | } 121 | 122 | $channelIds = array(); 123 | 124 | foreach ($this->option('channel') as $channelId) { 125 | if (! is_numeric($channelId)) { 126 | $query = ee()->db->select('channel_id') 127 | ->where('channel_name', $channelId) 128 | ->limit(1) 129 | ->get('channels'); 130 | 131 | if ($query->num_rows() > 0) { 132 | $channelId = $query->row('channel_id'); 133 | } 134 | 135 | $query->free_result(); 136 | } 137 | 138 | $channelIds[] = $channelId; 139 | } 140 | 141 | return array( 142 | 'relationship_channels' => $channelIds ?: array('--'), 143 | 'relationship_expired' => $this->option('expired'), 144 | 'relationship_future' => $this->option('future'), 145 | 'relationship_categories' => $this->option('category') ?: array('--'), 146 | 'relationship_authors' => $authors, 147 | 'relationship_statuses' => $this->option('status') ?: array('--'), 148 | 'relationship_limit' => $this->option('limit'), 149 | 'relationship_order_field' => $this->option('order_by'), 150 | 'relationship_order_dir' => $this->option('sort'), 151 | 'relationship_allow_multiple' => $this->option('multiple'), 152 | ); 153 | } 154 | 155 | protected function getFieldtypeOptionExamples() 156 | { 157 | return array( 158 | 'channel' => '1', 159 | 'category' => '1', 160 | 'author' => '1', 161 | 'member_group' => '1', 162 | 'status' => 'open', 163 | ); 164 | } 165 | 166 | public function getExamples() 167 | { 168 | return array( 169 | 'Create a Relationships field in field group 1' => '"Your Field Name" your_field_name 1', 170 | 'Create a Relationships field with multiple channels' => '--channel=1 --channel=blogs "Your Field Name" your_field_name 1', 171 | 'Create a Relationships field with multiple statuses' => '--status=closed --status=open "Your Field Name" your_field_name 1', 172 | 'Create a Relationships field with multiple selection' => '--multiple "Your Field Name" your_field_name 1', 173 | ); 174 | } 175 | } 176 | -------------------------------------------------------------------------------- /src/Command/CreateFieldRteCommand.php: -------------------------------------------------------------------------------- 1 | $this->option('rows'), 53 | 'rte_field_text_direction' => $this->option('text_direction'), 54 | ); 55 | } 56 | 57 | public function getExamples() 58 | { 59 | return array( 60 | 'Create an RTE field in field group 1' => '"Your Field Name" your_field_name 1', 61 | ); 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /src/Command/CreateFieldSelectCommand.php: -------------------------------------------------------------------------------- 1 | '"Your Field Name" your_field_name 1', 26 | 'Create a Select field with multiple options' => '--option="Foo" --option="Bar" "Name" name 1', 27 | ); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/Command/CreateFieldStoreProductDetailsCommand.php: -------------------------------------------------------------------------------- 1 | array( 30 | 'enable_custom_prices' => 0, 31 | 'enable_custom_weights' => 0, 32 | ), 33 | ); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/Command/CreateFieldTextCommand.php: -------------------------------------------------------------------------------- 1 | $this->option('maxlength'), 96 | 'text_field_fmt' => $this->option('format'), 97 | 'text_field_show_fmt' => $this->option('show_format') ? 'y' : 'n', 98 | 'text_field_text_direction' => $this->option('text_direction'), 99 | 'text_field_content_type' => $this->option('content_type'), 100 | 'text_field_show_smileys' => $this->option('show_smileys') ? 'y' : 'n', 101 | 'text_field_show_glossary' => $this->option('show_glossary') ? 'y' : 'n', 102 | 'text_field_show_spellcheck' => $this->option('show_spellcheck') ? 'y' : 'n', 103 | 'text_field_show_file_selector' => $this->option('show_file_selector') ? 'y' : 'n', 104 | ); 105 | } 106 | 107 | public function getExamples() 108 | { 109 | return array( 110 | 'Create a Text field in field group 1' => '"Your Field Name" your_field_name 1', 111 | 'Create a Text field of maxlength 255' => '--max_length=255 "Name" name 1', 112 | 'Create a Text field with format xhtml (none, br, or xhtml)' => '--format=xhtml "Name" name 1', 113 | 'Create a Text field with format selectable on the publish page' => '--show_format "Name" name 1', 114 | 'Create a Text field with RTL text direction' => '--text_direction=rtl "Name" name 1', 115 | 'Create a Text field with a content type (all, numeric, integer, or decimal)' => '--content_type=decimal "Name" name 1', 116 | 'Create a Text field with the smileys button' => '--show_smileys "Name" name 1', 117 | 'Create a Text field with the glossary button' => '--show_glossary "Name" name 1', 118 | 'Create a Text field with the spellcheck button' => '--show_spellcheck "Name" name 1', 119 | 'Create a Text field with the file selector button' => '--show_file_selector "Name" name 1', 120 | ); 121 | } 122 | } 123 | -------------------------------------------------------------------------------- /src/Command/CreateFieldTextareaCommand.php: -------------------------------------------------------------------------------- 1 | $this->option('rows'), 90 | 'textarea_field_fmt' => $this->option('format'), 91 | 'textarea_field_show_fmt' => $this->option('show_format') ? 'y' : 'n', 92 | 'textarea_field_text_direction' => $this->option('text_direction'), 93 | 'textarea_field_show_smileys' => $this->option('show_smileys') ? 'y' : 'n', 94 | 'textarea_field_show_glossary' => $this->option('show_glossary') ? 'y' : 'n', 95 | 'textarea_field_show_spellcheck' => $this->option('show_spellcheck') ? 'y' : 'n', 96 | 'textarea_field_show_file_selector' => $this->option('show_file_selector') ? 'y' : 'n', 97 | ); 98 | } 99 | 100 | public function getExamples() 101 | { 102 | return array( 103 | 'Create a Textarea field in field group 1' => '"Your Field Name" your_field_name 1', 104 | 'Create a Textarea field with 10 rows' => '--rows=10 "Name" name 1', 105 | 'Create a Textarea field with format xhtml (none, br, or xhtml)' => '--format=xhtml "Name" name 1', 106 | 'Create a Textarea field with format selectable on the publish page' => '--show_format "Name" name 1', 107 | 'Create a Textarea field with RTL text direction' => '--text_direction=rtl "Name" name 1', 108 | 'Create a Textarea field with the smileys button' => '--show_smileys "Name" name 1', 109 | 'Create a Textarea field with the glossary button' => '--show_glossary "Name" name 1', 110 | 'Create a Textarea field with the spellcheck button' => '--show_spellcheck "Name" name 1', 111 | 'Create a Textarea field with the file selector button' => '--show_file_selector "Name" name 1', 112 | ); 113 | } 114 | } 115 | -------------------------------------------------------------------------------- /src/Command/CreateFieldWygwamCommand.php: -------------------------------------------------------------------------------- 1 | option('config'); 50 | 51 | if (! $config) { 52 | $query = ee()->db->select('config_id') 53 | ->order_by('config_id', 'asc') 54 | ->limit(1) 55 | ->get('wygwam_configs'); 56 | 57 | $config = $query->row('config_id'); 58 | 59 | $query->free_result(); 60 | 61 | if (! $config) { 62 | throw new \RuntimeException('You must first create a Wygwam configuration.'); 63 | } 64 | } 65 | 66 | return array( 67 | 'wygwam' => array( 68 | 'config' => $config, 69 | 'defer' => $this->option('defer') ? 'y' : 'n', 70 | ), 71 | ); 72 | } 73 | 74 | protected function getFieldtypeOptionExamples() 75 | { 76 | return array( 77 | 'config' => '1', 78 | ); 79 | } 80 | 81 | public function getExamples() 82 | { 83 | return array( 84 | 'Create a Wygwam field in field group 1' => '"Your Field Name" your_field_name 1', 85 | 'Create a Wygwam field with Wygwam configuration 1' => '--config=1 "Name" name 1', 86 | 'Create a Wygwam field with deferred initialization' => '--defer "Name" name 1', 87 | ); 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /src/Command/CreateGlobalVariableCommand.php: -------------------------------------------------------------------------------- 1 | argument('name'); 63 | 64 | $siteId = ee()->config->item('site_id'); 65 | $siteName = ee()->config->item('site_short_name'); 66 | 67 | $contents = $this->argument('data'); 68 | 69 | if ($this->option('stdin')) { 70 | $contents = ''; 71 | 72 | $handle = fopen('php://stdin', 'r'); 73 | 74 | while (($buffer = fgets($handle, 4096)) !== false) { 75 | $contents .= $buffer; 76 | } 77 | } 78 | 79 | $tempContents = $contents ? $contents : '{!--TEMP--}'; 80 | 81 | $this->getApplication()->newControllerInstance('\\eecli\\CodeIgniter\\Controller\\DesignController'); 82 | 83 | $_POST = array( 84 | 'variable_name' => $name, 85 | 'variable_data' => $tempContents, 86 | ); 87 | 88 | ee()->global_variables_create(); 89 | 90 | $query = ee()->db->where('variable_name', $name) 91 | ->where('site_id', $siteId) 92 | ->get('global_variables'); 93 | 94 | // restore the blank contents 95 | if (! $contents) { 96 | ee()->db->update('global_variables', array('variable_data' => ''), array('variable_id' => $query->row('variable_id'))); 97 | } 98 | 99 | ee()->extensions->call('eecli_create_global_variable', $query->row('variable_id'), $query->row('variable_name'), $query->row('variable_data'), $siteId, $siteName); 100 | 101 | $query->free_result(); 102 | 103 | $this->info('Global variable '.$name.' created.'); 104 | } 105 | 106 | public function getLongDescription() 107 | { 108 | return 'Create a global variable. When you have [Sync Snippets](https://github.com/rsanchez/sync_snippets) installed and configured, this command will write a global variable file as well.'; 109 | } 110 | 111 | public function getExamples() 112 | { 113 | return array( 114 | 'Create a blank global variable' => 'your_global_variable_name', 115 | 'Create a global variable with content' => 'your_global_variable_name "your global variable content"', 116 | 'Pipe in content' => '--stdin your_global_variable_name', 117 | ); 118 | } 119 | } 120 | -------------------------------------------------------------------------------- /src/Command/CreateMemberCommand.php: -------------------------------------------------------------------------------- 1 | getApplication()->newControllerInstance('\\eecli\\CodeIgniter\\Controller\\MembersController'); 83 | 84 | $instance->load->helper(array('string', 'security')); 85 | $instance->load->library('stats'); 86 | 87 | $username = $this->argument('username_or_email'); 88 | $password = $this->option('password') ?: random_string('alnum', 16); 89 | $screenName = $this->option('screen_name'); 90 | $email = $this->option('email') ?: $username; 91 | $groupId = $this->option('member_group') ?: $instance->config->item('default_member_group'); 92 | 93 | $_POST = array( 94 | 'username' => $username, 95 | 'password' => $password, 96 | 'password_confirm' => $password, 97 | 'screen_name' => $screenName, 98 | 'email' => $email, 99 | 'group_id' => $groupId, 100 | 'bday_y' => '', 101 | 'bday_m' => '', 102 | 'bday_d' => '', 103 | 'url' => 'http://', 104 | 'location' => '', 105 | 'occupation' => '', 106 | 'interests' => '', 107 | 'aol_im' => '', 108 | 'icq' => '', 109 | 'yahoo_im' => '', 110 | 'msn_im' => '', 111 | 'bio' => '', 112 | ); 113 | 114 | $instance->new_member_form(); 115 | 116 | $this->getApplication()->checkForErrors(true); 117 | 118 | $query = $instance->db->select('member_id') 119 | ->where('username', $username) 120 | ->get('members'); 121 | 122 | $memberId = $query->row('member_id'); 123 | 124 | $query->free_result(); 125 | 126 | $withPassword = $this->option('password') || $this->option('hide_password') ? '' : ' with password '.$password; 127 | 128 | $message = sprintf('Member %s (%s) created%s.', $username, $memberId, $withPassword); 129 | 130 | $this->info($message); 131 | } 132 | 133 | public function getOptionExamples() 134 | { 135 | return array( 136 | 'password' => '997fa90c393a', 137 | 'email' => 'you@yoursite.com', 138 | 'member_group' => '1', 139 | 'screen_name' => 'Your Name', 140 | ); 141 | } 142 | 143 | public function getLongDescription() 144 | { 145 | return 'Create a new member. If you omit a password, one will be generated for you. If you omit an email, the username will be used as the email address. If you omit a member group, the default member group for your system will be used.'; 146 | } 147 | 148 | public function getExamples() 149 | { 150 | return array( 151 | 'Create a member with same username & email' => 'your.email@site.com', 152 | 'Create a member with different username & email' => '--email="your.email@site.com" your_username', 153 | 'Create a member with the specified screen name' => '--screen_name="Your Name" your.email@site.com', 154 | 'Create a member with the specified password' => '--password="so48jf48jss4sk" your.email@site.com', 155 | 'Create a superadmin' => '--member_group=1 your.email@site.com', 156 | ); 157 | } 158 | } 159 | -------------------------------------------------------------------------------- /src/Command/CreateSnippetCommand.php: -------------------------------------------------------------------------------- 1 | argument('name'); 70 | 71 | $siteId = $this->option('global') ? 0 : ee()->config->item('site_id'); 72 | $siteName = $this->option('global') ? 'global_snippets' : ee()->config->item('site_short_name'); 73 | 74 | $contents = $this->argument('contents'); 75 | 76 | if ($this->option('stdin')) { 77 | $contents = ''; 78 | 79 | $handle = fopen('php://stdin', 'r'); 80 | 81 | while (($buffer = fgets($handle, 4096)) !== false) { 82 | $contents .= $buffer; 83 | } 84 | } 85 | 86 | $tempContents = $contents ? $contents : '{!--TEMP--}'; 87 | 88 | $this->getApplication()->newControllerInstance('\\eecli\\CodeIgniter\\Controller\\DesignController'); 89 | 90 | $_POST = array( 91 | 'snippet_name' => $name, 92 | 'snippet_contents' => $tempContents, 93 | 'site_id' => $siteId, 94 | ); 95 | 96 | ee()->snippets_update(); 97 | 98 | if (ee()->output->getErrorMessage()) { 99 | $this->error(ee()->output->getErrorMessage()); 100 | 101 | return; 102 | } 103 | 104 | $query = ee()->db->where('snippet_name', $name) 105 | ->get('snippets'); 106 | 107 | // restore the blank contents 108 | if (! $contents) { 109 | ee()->db->update('snippets', array('snippet_contents' => ''), array('snippet_id' => $query->row('snippet_id'))); 110 | } 111 | 112 | ee()->extensions->call('eecli_create_snippet', $query->row('snippet_id'), $query->row('snippet_name'), $query->row('snippet_contents'), $siteId, $siteName); 113 | 114 | $query->free_result(); 115 | 116 | $this->info('Snippet '.$name.' created.'); 117 | } 118 | 119 | public function getLongDescription() 120 | { 121 | return 'Create a new snippet. When you have [Sync Snippets](https://github.com/rsanchez/sync_snippets) installed and configured, this command will write a snippet file as well.'; 122 | } 123 | 124 | public function getExamples() 125 | { 126 | return array( 127 | 'Create a blank snippet' => 'your_snippet_name', 128 | 'Create a snippet with content' => 'your_snippet_name "your snippet content"', 129 | 'Pipe in content' => '--stdin your_snippet_name', 130 | 'Create a snippet accessible to all sites' => '--global your_snippet_name', 131 | ); 132 | } 133 | } 134 | -------------------------------------------------------------------------------- /src/Command/CreateStatusCommand.php: -------------------------------------------------------------------------------- 1 | getApplication()->newControllerInstance('\\eecli\\CodeIgniter\\Controller\\AdminContentController'); 63 | 64 | $status = $this->argument('status'); 65 | 66 | $group = $this->argument('status_group'); 67 | 68 | if (is_numeric($group)) { 69 | $query = ee()->db->select('group_id') 70 | ->where('group_id', $group) 71 | ->get('status_groups'); 72 | 73 | if ($query->num_rows() === 0) { 74 | throw new \RuntimeException('Invalid group ID.'); 75 | } 76 | 77 | $groupId = $query->row('group_id'); 78 | 79 | $query->free_result(); 80 | } else { 81 | $query = ee()->db->select('group_id') 82 | ->where('group_name', $group) 83 | ->get('status_groups'); 84 | 85 | if ($query->num_rows() === 0) { 86 | throw new \RuntimeException('Invalid group name.'); 87 | } 88 | 89 | $groupId = $query->row('group_id'); 90 | 91 | $query->free_result(); 92 | } 93 | 94 | $color = $this->option('color'); 95 | 96 | if ($color) { 97 | if (! preg_match('/^(#?)[0-9abcdefABCDEF]{6}$/', $color, $match)) { 98 | throw new \RuntimeException('Color must be a six digit hex string.'); 99 | } 100 | 101 | $color = str_replace($match[1], '', $color); 102 | } 103 | 104 | $query = ee()->db->select('status_order') 105 | ->where('group_id', $groupId) 106 | ->order_by('status_order', 'desc') 107 | ->get('statuses'); 108 | 109 | $_POST = array( 110 | 'status_id' => '', 111 | 'old_status' => '', 112 | 'group_id' => $groupId, 113 | 'status' => $status, 114 | 'status_order' => $query->row('status_order') + 1, 115 | 'highlight' => $color ?: '000000', 116 | ); 117 | 118 | $query = ee()->db->select('group_id') 119 | ->where('group_id >', 4) 120 | ->where('site_id', ee()->config->item('site_id')) 121 | ->get('member_groups'); 122 | 123 | foreach ($query->result() as $row) { 124 | $_POST['access_'.$row->group_id] = 'y'; 125 | } 126 | 127 | ee()->status_update(); 128 | 129 | if (ee()->output->getErrorMessage()) { 130 | $this->error(ee()->output->getErrorMessage()); 131 | 132 | return; 133 | } 134 | 135 | $query = ee()->db->select('status_id') 136 | ->where('status', $status) 137 | ->get('statuses'); 138 | 139 | $this->info(sprintf('Status %s (%s) created.', $status, $query->row('status_id'))); 140 | 141 | $query->free_result(); 142 | } 143 | 144 | public function getOptionExamples() 145 | { 146 | return array( 147 | 'color' => '990000', 148 | ); 149 | } 150 | 151 | public function getExamples() 152 | { 153 | return array( 154 | 'Create a status in the specfied group (by ID)' => 'featured 1', 155 | 'Create a status in the specified group (by name)' => 'draft your_group_name', 156 | 'Create a status with a red color' => '--color="FF0000" featured 1', 157 | ); 158 | } 159 | } 160 | -------------------------------------------------------------------------------- /src/Command/CreateStatusGroupCommand.php: -------------------------------------------------------------------------------- 1 | getApplication()->newControllerInstance('\\eecli\\CodeIgniter\\Controller\\AdminContentController'); 41 | 42 | $name = $this->argument('name'); 43 | 44 | $_POST = array( 45 | 'group_name' => $name, 46 | ); 47 | 48 | ee()->status_group_update(); 49 | 50 | if (ee()->output->getErrorMessage()) { 51 | $this->error(ee()->output->getErrorMessage()); 52 | 53 | return; 54 | } 55 | 56 | $query = ee()->db->select('group_id') 57 | ->where('group_name', $name) 58 | ->get('status_groups'); 59 | 60 | $this->info(sprintf('Status group %s (%s) created.', $name, $query->row('group_id'))); 61 | 62 | $query->free_result(); 63 | } 64 | 65 | public function getExamples() 66 | { 67 | return array( 68 | 'Create a status group' => 'your_group_name', 69 | ); 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /src/Command/CreateTemplateCommand.php: -------------------------------------------------------------------------------- 1 | argument('template'); 101 | 102 | $instance = $this->getApplication()->newControllerInstance('\\eecli\\CodeIgniter\\Controller\\DesignController'); 103 | 104 | $instance->load->model('template_model'); 105 | 106 | $templateData = ''; 107 | 108 | if ($this->option('stdin')) { 109 | $handle = fopen('php://stdin', 'r'); 110 | 111 | while (($buffer = fgets($handle, 4096)) !== false) { 112 | $templateData .= $buffer; 113 | } 114 | } 115 | 116 | foreach ($templates as $template) { 117 | if (! preg_match('#^[a-zA-Z0-9_\-]+/[a-zA-Z0-9_\-]+$#', $template)) { 118 | $this->error('Template '.$template.' must be in / format.'); 119 | 120 | continue; 121 | } 122 | 123 | list($groupName, $templateName) = explode('/', $template); 124 | 125 | $query = $instance->db->select('group_id') 126 | ->where('group_name', $groupName) 127 | ->get('template_groups'); 128 | 129 | // create the group if it doesn't exist 130 | if ($query->num_rows() === 0) { 131 | $_POST = array( 132 | 'group_name' => $groupName, 133 | 'is_site_default' => 'n', 134 | 'duplicate_group' => false, 135 | ); 136 | 137 | $instance->new_template_group(); 138 | 139 | if ($this->getApplication()->checkForErrors()) { 140 | continue; 141 | } 142 | 143 | $this->comment('Template group '.$groupName.' created.'); 144 | 145 | $variables = $instance->functions->getVariables(); 146 | 147 | $groupId = $variables['tgpref']; 148 | 149 | // it made an index template, update it if it needs 150 | 151 | if ($instance->config->item('save_tmpl_files') === 'y') { 152 | $query = $instance->db->select('template_id') 153 | ->where('group_id', $groupId) 154 | ->where('template_name', 'index') 155 | ->get('templates'); 156 | 157 | if ($query->num_rows() > 0) { 158 | $_POST = array( 159 | 'template_id' => $query->row('template_id'), 160 | 'template_data' => '', 161 | 'template_notes' => $this->option('notes'), 162 | 'save_template_file' => 'y', 163 | 'save_template_revision' => $instance->config->item('save_tmpl_revisions'), 164 | ); 165 | 166 | $instance->update_template(); 167 | } 168 | 169 | $query->free_result(); 170 | } 171 | } else { 172 | $groupId = $query->row('group_id'); 173 | } 174 | 175 | $query->free_result(); 176 | 177 | $templateExists = $instance->db->where('group_id', $groupId) 178 | ->where('template_name', $templateName) 179 | ->where('site_id', $instance->config->item('site_id')) 180 | ->count_all_results('templates') > 0; 181 | 182 | if ($templateExists) { 183 | $this->error('Template '.$template.' already exists.'); 184 | 185 | continue; 186 | } 187 | 188 | $templateType = $this->option('type'); 189 | 190 | $_POST = array( 191 | 'template_name' => $templateName, 192 | 'group_id' => $groupId, 193 | 'template_type' => $templateType, 194 | 'template_notes' => $this->option('notes'), 195 | ); 196 | 197 | $instance->template = $instance->TMPL; 198 | 199 | $instance->create_new_template(); 200 | 201 | $variables = $instance->cp->getVariables(); 202 | 203 | $templateId = $variables['template_id']; 204 | 205 | $_POST = array( 206 | 'template_id' => $templateId, 207 | 'template_data' => $templateData, 208 | 'template_notes' => $this->option('notes'), 209 | 'save_template_file' => $instance->config->item('save_tmpl_files'), 210 | 'save_template_revision' => $instance->config->item('save_tmpl_revisions'), 211 | ); 212 | 213 | $instance->update_template(); 214 | 215 | if ($this->getApplication()->checkForErrors()) { 216 | continue; 217 | } 218 | 219 | $_POST = array( 220 | 'template_id' => $templateId, 221 | 'template_name' => $templateName, 222 | 'template_type' => $templateType, 223 | 'template_notes' => $this->option('notes'), 224 | 'cache' => $this->option('cache') ? 'y' : 'n', 225 | 'refresh' => $this->option('cache') ?: 0, 226 | 'allow_php' => $this->option('php') ? 'y' : 'n', 227 | 'protect_javascript' => $this->option('protect_js') ? 'y' : 'n', 228 | 'php_parse_location' => $this->option('input') ? 'i' : 'o', 229 | 'hits' => 0, 230 | ); 231 | 232 | $instance->template_edit_ajax(); 233 | 234 | if ($this->getApplication()->checkForErrors()) { 235 | continue; 236 | } 237 | 238 | $this->info(sprintf('Template %s (%s) created.', $template, $templateId)); 239 | } 240 | } 241 | 242 | public function getOptionExamples() 243 | { 244 | return array( 245 | 'cache' => '300', 246 | 'type' => 'webpage', 247 | ); 248 | } 249 | 250 | public function getLongDescription() 251 | { 252 | return 'Create a new template. If the template group does not already exist, it will be created.'; 253 | } 254 | 255 | public function getExamples() 256 | { 257 | return array( 258 | 'Create a template' => 'site/index', 259 | 'Multiple templates' => 'site/index site/foo', 260 | 'With php enabled' => '--php site/index', 261 | 'With php enabled on input' => '--php --input site/index', 262 | 'With caching on (for 300 seconds)' => '--cache=300 site/index', 263 | 'Protect javascript' => '--protect_js site/index', 264 | 'Set a type: webpage, feed, css, js, static, xml' => '--type=xml site/index', 265 | ); 266 | } 267 | } 268 | -------------------------------------------------------------------------------- /src/Command/CreateTemplateGroupCommand.php: -------------------------------------------------------------------------------- 1 | argument('name'); 58 | 59 | $instance = $this->getApplication()->newControllerInstance('\\eecli\\CodeIgniter\\Controller\\DesignController'); 60 | 61 | $instance->load->model('template_model'); 62 | 63 | foreach ($names as $groupName) { 64 | $_POST = array( 65 | 'group_name' => $groupName, 66 | 'is_site_default' => $this->option('default') ? 'y' : 'n', 67 | 'duplicate_group' => false, 68 | ); 69 | 70 | $instance->new_template_group(); 71 | 72 | if ($this->getApplication()->checkForErrors()) { 73 | continue; 74 | } 75 | 76 | $query = ee()->db->select('group_id') 77 | ->where('site_id', ee()->config->item('site_id')) 78 | ->where('group_name', $groupName) 79 | ->limit(1) 80 | ->get('template_groups'); 81 | 82 | $groupId = $query->row('group_id'); 83 | 84 | $query->free_result(); 85 | 86 | if (ee()->config->item('save_tmpl_files') === 'y' && ee()->config->item('tmpl_file_basepath')) { 87 | // find the newly created index template 88 | $query = ee()->db->select('template_id') 89 | ->where('site_id', ee()->config->item('site_id')) 90 | ->where('group_id', $groupId) 91 | ->where('template_name', 'index') 92 | ->limit(1) 93 | ->get('templates'); 94 | 95 | $templateId = $query->row('template_id'); 96 | 97 | $query->free_result(); 98 | 99 | // create the template file for the index template 100 | $fileCreated = $instance->update_template_file(array( 101 | 'template_group' => $groupName, 102 | 'template_id' => $templateId, 103 | 'template_name' => 'index', 104 | 'template_type' => 'webpage', 105 | 'template_data' => '', 106 | )); 107 | 108 | // set the index template to save to file 109 | ee()->db->update('templates', array('save_template_file' => 'y'), array('template_id' => $templateId)); 110 | 111 | if (! $fileCreated) { 112 | $path = ee()->config->slash_item('tmpl_file_basepath').ee()->config->slash_item('site_short_name').$groupName.'.group/'; 113 | 114 | $this->error(sprintf('Could not write to %s', $path)); 115 | } 116 | } 117 | 118 | $this->comment(sprintf('Template group %s (%s) created.', $groupName, $groupId)); 119 | } 120 | } 121 | 122 | public function getLongDescription() 123 | { 124 | return 'Create a new template group. This will also create an index template in the new group(s).'; 125 | } 126 | 127 | public function getExamples() 128 | { 129 | return array( 130 | 'Create a template' => 'site', 131 | 'Multiple groups' => 'site news blog', 132 | 'Create the default group' => '--default site', 133 | ); 134 | } 135 | } 136 | -------------------------------------------------------------------------------- /src/Command/CreateUploadPrefCommand.php: -------------------------------------------------------------------------------- 1 | getApplication()->newControllerInstance('\\eecli\\CodeIgniter\\Controller\\ContentFilesController'); 87 | 88 | $instance->load->library('form_validation'); 89 | $instance->load->model('file_model'); 90 | 91 | $name = $this->argument('name'); 92 | 93 | $_POST = array( 94 | 'name' => $name, 95 | 'server_path' => $this->argument('server_path'), 96 | 'url' => $this->argument('url'), 97 | 'allowed_types' => $this->option('images_only') ? 'img' : 'all', 98 | 'max_size' => $this->option('max_size'), 99 | 'max_width' => $this->option('max_width'), 100 | 'max_height' => $this->option('max_height'), 101 | 'properties' => '', 102 | 'pre_format' => '', 103 | 'post_format' => '', 104 | 'file_properties' => '', 105 | 'file_pre_format' => '', 106 | 'file_post_format' => '', 107 | 'size_short_name_2' => '', 108 | 'size_resize_type_2' => 'none', 109 | 'size_width_2' => '', 110 | 'size_height_2' => '', 111 | 'size_watermark_id_2' => '0', 112 | 'submit' => 'Submit', 113 | ); 114 | 115 | $query = $instance->db->where('site_id', $instance->config->item('site_id')) 116 | ->where('group_id >', 4) 117 | ->get('member_groups'); 118 | 119 | foreach ($query->result() as $row) { 120 | $_POST['access_'.$row->group_id] = 'n'; 121 | } 122 | 123 | $query->free_result(); 124 | 125 | $instance->edit_upload_preferences(); 126 | 127 | $this->getApplication()->checkForErrors(true); 128 | 129 | $this->comment('File upload destination '.$name.' created.'); 130 | } 131 | 132 | /** 133 | * {@inheritdoc} 134 | */ 135 | public function getExamples() 136 | { 137 | return array( 138 | 'Create a file upload destination with default options' => '"My Files" ./uploads/files /uploads/files/', 139 | 'Create a file upload destination with images only' => '--images_only "My Files" ./uploads/files /uploads/files/', 140 | 'Create a file upload destination with max dimensions' => '--images_only --max_width=1024 --max_height=1024 "My Files" ./uploads/files /uploads/files/', 141 | ); 142 | } 143 | } 144 | -------------------------------------------------------------------------------- /src/Command/DbDumpCommand.php: -------------------------------------------------------------------------------- 1 | run(); 74 | 75 | if (! $process->isSuccessful()) { 76 | throw new \RuntimeException('mysqldump could not be found in your $PATH.'); 77 | } 78 | 79 | ee()->load->helper('security'); 80 | 81 | // where to create the file, default to current dir 82 | $path = $this->argument('path') ?: '.'; 83 | 84 | $path = rtrim($path, DIRECTORY_SEPARATOR).DIRECTORY_SEPARATOR; 85 | 86 | $gzip = $this->option('gzip'); 87 | 88 | if ($gzip) { 89 | $process = new Process('gzip --version'); 90 | 91 | $process->run(); 92 | 93 | if (! $process->isSuccessful()) { 94 | throw new \RuntimeException('gzip could not be found in your $PATH.'); 95 | } 96 | } 97 | 98 | $extension = $gzip ? '.sql.gz' : '.sql'; 99 | 100 | $name = $this->option('name'); 101 | 102 | // set a default name [-]- 103 | if (! $name) { 104 | $name = sanitize_filename(ee()->db->database); 105 | 106 | $env = $this->getApplication()->getEnvironment(); 107 | 108 | if ($env) { 109 | $name .= '-'.$env; 110 | } 111 | 112 | $name .= '-'.date('YmdHis'); 113 | } 114 | 115 | $file = $path.$name.$extension; 116 | 117 | // compile the mysqldump command using EE's db credentials 118 | $command = sprintf( 119 | 'MYSQL_PWD=%s mysqldump -u %s -h %s %s %s > %s', 120 | escapeshellarg(ee()->db->password), 121 | escapeshellarg(ee()->db->username), 122 | escapeshellarg(ee()->db->hostname), 123 | escapeshellarg(ee()->db->database), 124 | $gzip ? ' | gzip' : '', 125 | escapeshellarg($file) 126 | ); 127 | 128 | $process = new Process($command); 129 | 130 | $process->setTimeout(3600); 131 | 132 | $process->run(); 133 | 134 | if (! $process->isSuccessful()) { 135 | $this->error('Could not execute mysqldump.'); 136 | 137 | return; 138 | } 139 | 140 | $backups = $this->option('backups'); 141 | 142 | // check if we need to delete any old backups 143 | if (is_numeric($backups)) { 144 | $finder = new Finder(); 145 | 146 | // look for other files in the path that use the 147 | // sql / sql.gz extension 148 | $finder->files() 149 | ->in($path) 150 | ->name('*'.$extension) 151 | ->sortByModifiedTime(); 152 | 153 | // omit the X most recent files 154 | $files = array_slice(array_reverse(iterator_to_array($finder)), $backups); 155 | 156 | // if there are backups beyond our limit, delete them 157 | foreach ($files as $file) { 158 | unlink($file->getRealPath()); 159 | } 160 | } 161 | 162 | $this->info($file.' created.'); 163 | } 164 | 165 | public function getOptionExamples() 166 | { 167 | return array( 168 | 'name' => 'db_backup', 169 | 'backups' => '10', 170 | ); 171 | } 172 | 173 | public function getLongDescription() 174 | { 175 | return 'Dump your database using `mysqldump`. NOTE: your PHP installation must be able to call `mysqldump` via the PHP `system` function. If you have an `ENV` or `ENVIRONMENT` constant defined in your config.php, that name will be used in the sql dump file name.'; 176 | } 177 | 178 | public function getExamples() 179 | { 180 | return array( 181 | 'Create a sql dump file in the current folder' => '','create a sql dump file in the specified folder' => 'backups/', 182 | 'Create a sql dump file, gzipped' => '--gzip', 183 | 'Create a sql dump file, keep the last X backups and delete the rest' => '--backups=10 --gzip backups/', 184 | ); 185 | } 186 | } 187 | -------------------------------------------------------------------------------- /src/Command/DeleteEntryCommand.php: -------------------------------------------------------------------------------- 1 | argument('entry'); 57 | 58 | $siteId = ee()->config->item('site_id'); 59 | $siteName = ee()->config->item('site_short_name'); 60 | 61 | $type = is_numeric($name) ? 'entry_id' : 'url_title'; 62 | 63 | $query = ee()->db->select('entry_id, title') 64 | ->from('channel_titles') 65 | ->where('site_id', $siteId) 66 | ->where($type, $name) 67 | ->get(); 68 | 69 | $name = is_numeric($name) ? $name : "“{$name}”"; 70 | 71 | if ($query->num_rows() === 0) { 72 | $this->error(sprintf('Entry %s not found.', $name)); 73 | 74 | return; 75 | } 76 | 77 | if ($query->num_rows() > 1) { 78 | throw new \RuntimeException("There were multiple entries with $name found"); 79 | } 80 | 81 | ee()->load->library(array('api', 'stats')); 82 | ee()->api->instantiate('channel_entries'); 83 | 84 | $entry_id = $query->row('entry_id'); 85 | $title = $query->row('title'); 86 | 87 | $query->free_result(); 88 | 89 | //set group id to be a super admin 90 | ee()->session->userdata['group_id'] = '1'; 91 | ee()->session->userdata['can_delete_all_entries'] = 'y'; 92 | 93 | if (! $this->option('force') && ! $this->confirm('Are you sure you want to delete? [Yn]', true)) { 94 | $this->error(sprintf('Did not delete entry “%s” (%s)', $title, $entry_id)); 95 | 96 | return; 97 | } 98 | 99 | $delete = ee()->api_channel_entries->delete_entry((int) $entry_id); 100 | 101 | if ($delete) { 102 | $this->info(sprintf('Entry “%s” (%s) deleted.', $title, $entry_id)); 103 | } else { 104 | foreach (ee()->api_channel_entries->errors as $error) { 105 | $this->error($error); 106 | } 107 | } 108 | } 109 | 110 | public function getLongDescription() 111 | { 112 | return 'Delete an entry by entering in an entry_id or url_title. You will be asked to confirm that you want to delete the specified entry, unless you use the `--force` option.'; 113 | } 114 | 115 | public function getExamples() 116 | { 117 | return array( 118 | 'Delete an entry by the entry_id' => '123', 119 | 'Delete an entry by the url_title' => 'entry_be_gone', 120 | 'Delete an entry by the entry_id without confirmation' => '--force 123', 121 | ); 122 | } 123 | } 124 | -------------------------------------------------------------------------------- /src/Command/DeleteGlobalVariableCommand.php: -------------------------------------------------------------------------------- 1 | argument('name'); 57 | 58 | $siteId = ee()->config->item('site_id'); 59 | $siteName = ee()->config->item('site_short_name'); 60 | 61 | if (! $this->option('force') && ! $this->confirm('Are you sure you want to delete? [Yn]', true)) { 62 | $this->error('Did not delete global variable(s): '.implode(' ', $names)); 63 | 64 | return; 65 | } 66 | 67 | $query = ee()->db->select('variable_id, variable_name, variable_data') 68 | ->where('site_id', $siteId) 69 | ->where_in('variable_name', $names) 70 | ->get('global_variables'); 71 | 72 | $globalVariables = array(); 73 | 74 | foreach ($query->result() as $row) { 75 | $globalVariables[$row->variable_name] = $row; 76 | } 77 | 78 | $query->free_result(); 79 | 80 | $hasLowVariables = array_key_exists('Low_variables_ext', ee()->extensions->version_numbers); 81 | 82 | foreach ($names as $name) { 83 | if (! isset($globalVariables[$name])) { 84 | $this->error('Global variable '.$name.' not found.'); 85 | 86 | continue; 87 | } 88 | 89 | $globalVariable = $globalVariables[$name]; 90 | 91 | if ($hasLowVariables && ee()->db->where('variable_id', $globalVariable->variable_id)->count_all_results('low_variables') > 0) { 92 | $this->error('Could not delete Low Variable '.$name.'.'); 93 | 94 | continue; 95 | } 96 | 97 | ee()->db->delete('global_variables', array('variable_id' => $globalVariable->variable_id)); 98 | 99 | ee()->extensions->call('eecli_delete_global_variable', $globalVariable->variable_id, $globalVariable->variable_name, $globalVariable->variable_data, $siteId, $siteName); 100 | 101 | $this->info('Global variable '.$name.' deleted.'); 102 | } 103 | } 104 | 105 | public function getLongDescription() 106 | { 107 | return "Delete one or more global variables. You will be asked to confirm that you want to delete the specified global variable(s), unless you use the `--force` option.\n\nWhen you have [Sync Snippets](https://github.com/rsanchez/sync_snippets) installed and configured, this command will delete the global variable file as well."; 108 | } 109 | 110 | public function getExamples() 111 | { 112 | return array( 113 | 'Delete a global variable' => 'your_global_variable_name', 114 | 'Delete multiple global variables' => 'your_global_variable_name your_other_global_variable_name', 115 | 'Delete a global variable without confirmation' => '--force your_global_variable_name', 116 | ); 117 | } 118 | } 119 | -------------------------------------------------------------------------------- /src/Command/DeleteSnippetCommand.php: -------------------------------------------------------------------------------- 1 | argument('name'); 64 | 65 | $siteId = $this->option('global') ? 0 : ee()->config->item('site_id'); 66 | $siteName = $this->option('global') ? 'global_snippets' : ee()->config->item('site_short_name'); 67 | 68 | if (! $this->option('force') && ! $this->confirm('Are you sure you want to delete? [Yn]', true)) { 69 | $this->error('Did not delete snippet(s): '.implode(' ', $names)); 70 | 71 | return; 72 | } 73 | 74 | $query = ee()->db->select('snippet_id, snippet_name, snippet_contents') 75 | ->where('site_id', $siteId) 76 | ->where_in('snippet_name', $names) 77 | ->get('snippets'); 78 | 79 | $snippets = array(); 80 | 81 | foreach ($query->result() as $row) { 82 | $snippets[$row->snippet_name] = $row; 83 | } 84 | 85 | $query->free_result(); 86 | 87 | foreach ($names as $name) { 88 | if (! isset($snippets[$name])) { 89 | $this->error('Snippet '.$name.' not found.'); 90 | 91 | continue; 92 | } 93 | 94 | $snippet = $snippets[$name]; 95 | 96 | ee()->db->delete('snippets', array('snippet_id' => $snippet->snippet_id)); 97 | 98 | ee()->extensions->call('eecli_delete_snippet', $snippet->snippet_id, $snippet->snippet_name, $snippet->snippet_contents, $siteId, $siteName); 99 | 100 | $this->info('Snippet '.$name.' deleted.'); 101 | } 102 | } 103 | 104 | public function getLongDescription() 105 | { 106 | return "Delete one or more snippets. You will be asked to confirm that you want to delete the specified snippet(s), unless you use the `--force` option.\n\nWhen you have [Sync Snippets](https://github.com/rsanchez/sync_snippets) installed and configured, this command will delete the snippet file as well."; 107 | } 108 | 109 | public function getExamples() 110 | { 111 | return array( 112 | 'Delete a snippet' => 'your_snippet_name', 113 | 'Delete a snippet accessible to all sites' => '--global your_snippet_name', 114 | 'Delete multiple snippets' => 'your_snippet_name your_other_snippet_name', 115 | 'Delete a snippet without confirmation' => '--force your_snippet_name', 116 | ); 117 | } 118 | } 119 | -------------------------------------------------------------------------------- /src/Command/DeleteTemplateCommand.php: -------------------------------------------------------------------------------- 1 | argument('template'); 57 | 58 | $this->getApplication()->newControllerInstance('\\eecli\\CodeIgniter\\Controller\\DesignController'); 59 | 60 | ee()->load->model('template_model'); 61 | ee()->template = ee()->TMPL; 62 | 63 | if (! $this->option('force') && ! $this->confirm('Are you sure you want to delete? [Yn]', true)) { 64 | $this->error('Did not delete template(s): '.implode(' ', $templates)); 65 | 66 | return; 67 | } 68 | 69 | foreach ($templates as $template) { 70 | if (! preg_match('#^[a-zA-Z0-9_\-]+/[a-zA-Z0-9_\-]+$#', $template)) { 71 | $this->error('Template '.$template.' must be in / format.'); 72 | 73 | continue; 74 | } 75 | 76 | list($groupName, $templateName) = explode('/', $template); 77 | 78 | $query = ee()->db->select('template_id') 79 | ->join('template_groups', 'template_groups.group_id = templates.group_id') 80 | ->where('group_name', $groupName) 81 | ->where('template_name', $templateName) 82 | ->get('templates'); 83 | 84 | if ($query->num_rows() === 0) { 85 | $this->error('Template '.$template.' not found.'); 86 | } else { 87 | $_POST = array( 88 | 'template_id' => $query->row('template_id'), 89 | ); 90 | 91 | ee()->template_delete(); 92 | 93 | $this->info('Template '.$template.' deleted.'); 94 | } 95 | 96 | $query->free_result(); 97 | } 98 | } 99 | 100 | public function getLongDescription() 101 | { 102 | return 'Delete one or more templates. You will be asked to confirm that you want to delete the specified templates(s), unless you use the `--force` option.'; 103 | } 104 | 105 | public function getExamples() 106 | { 107 | return array( 108 | 'Delete a template' => 'site/index', 109 | 'Delete multiple templates' => 'site/index site/foo', 110 | 'Delete a template without confirmation' => '--force site/index', 111 | ); 112 | } 113 | } 114 | -------------------------------------------------------------------------------- /src/Command/DeleteTemplateGroupCommand.php: -------------------------------------------------------------------------------- 1 | argument('template_group'); 57 | 58 | $this->getApplication()->newControllerInstance('\\eecli\\CodeIgniter\\Controller\\DesignController'); 59 | 60 | if (! $this->option('force') && ! $this->confirm('Are you sure you want to delete? [Yn]', true)) { 61 | $this->error('Did not delete template group(s): '.implode(' ', $templateGroups)); 62 | 63 | return; 64 | } 65 | 66 | foreach ($templateGroups as $groupName) { 67 | $query = ee()->db->select('group_id') 68 | ->where('group_name', $groupName) 69 | ->get('template_groups'); 70 | 71 | if ($query->num_rows() === 0) { 72 | $this->error('Template group '.$groupName.' not found.'); 73 | } else { 74 | $_POST = array( 75 | 'group_id' => $query->row('group_id'), 76 | ); 77 | 78 | ee()->template_group_delete(); 79 | 80 | $this->info('Template group '.$groupName.' deleted.'); 81 | } 82 | 83 | $query->free_result(); 84 | } 85 | } 86 | 87 | public function getLongDescription() 88 | { 89 | return 'Delete one or more template groups. You will be asked to confirm that you want to delete the specified templates(s), unless you use the `--force` option.'; 90 | } 91 | 92 | public function getExamples() 93 | { 94 | return array( 95 | 'Delete a template group' => 'site', 96 | 'Delete multiple groups' => 'site news blog', 97 | 'Delete a template group without confirmation' => '--force site', 98 | ); 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /src/Command/GenerateCommandCommand.php: -------------------------------------------------------------------------------- 1 | argument('command_name'); 83 | $commandDescription = $this->option('description'); 84 | $hasArguments = $this->option('arguments'); 85 | $hasOptions = $this->option('options'); 86 | $namespace = $this->option('namespace'); 87 | 88 | // where to create the file, default to current directory 89 | $path = $this->argument('path') ?: '.'; 90 | 91 | // make sure it has a trailing slash 92 | $path = rtrim($path, DIRECTORY_SEPARATOR).DIRECTORY_SEPARATOR; 93 | 94 | // split command into individual words 95 | $words = preg_split('/[:-_]/', $commandName); 96 | 97 | // camel case 98 | $words = array_map(function ($word) { 99 | return mb_strtoupper(mb_substr($word, 0, 1)).mb_substr($word, 1); 100 | }, $words); 101 | 102 | $className = implode('', $words); 103 | 104 | $handlebars = new Handlebars(array( 105 | 'loader' => new FilesystemLoader(__DIR__.'/../templates/'), 106 | )); 107 | 108 | $destination = $path.$className.'Command.php'; 109 | 110 | $handle = fopen($destination, 'w'); 111 | 112 | $output = $handlebars->render('Command.php', array( 113 | 'className' => $className, 114 | 'commandName' => $commandName, 115 | 'commandDescription' => $commandDescription, 116 | 'hasArguments' => $hasArguments, 117 | 'hasOptions' => $hasOptions, 118 | 'namespace' => $namespace, 119 | )); 120 | 121 | fwrite($handle, $output); 122 | 123 | fclose($handle); 124 | 125 | $this->info($destination.' created.'); 126 | } 127 | 128 | public function getOptionExamples() 129 | { 130 | return array( 131 | 'namespace' => 'eecli\Command', 132 | 'description' => 'Your description here.', 133 | ); 134 | } 135 | 136 | public function getExamples() 137 | { 138 | return array( 139 | 'Generate a file called YourCustomCommand in the current directory' => 'your:custom_comand', 140 | 'Generate in the specified directory' => 'your:custom_comand ./commands/', 141 | 'Generate with a namespace' => '--namespace="YourSite\Command" your:custom_comand ./src/YourSite/Command/', 142 | 'Generate with arguments and options' => '--options --arguments your_command', 143 | 'Generate with a description' => '--description="Clear custom cache" cache:clear:custom', 144 | ); 145 | } 146 | } 147 | -------------------------------------------------------------------------------- /src/Command/GenerateHtaccessCommand.php: -------------------------------------------------------------------------------- 1 | argument('path') ?: '.'; 44 | 45 | // make sure it has a trailing slash 46 | $path = rtrim($path, DIRECTORY_SEPARATOR).DIRECTORY_SEPARATOR; 47 | 48 | $handlebars = new Handlebars(array( 49 | 'loader' => new FilesystemLoader(__DIR__.'/../templates/'), 50 | )); 51 | 52 | $destination = $path.'.htaccess'; 53 | 54 | if (file_exists($destination)) { 55 | $path = realpath($path).DIRECTORY_SEPARATOR; 56 | 57 | $confirmed = $this->confirm("An .htaccess file already exists in {$path}. Do you want to overwrite? [yN] ", false); 58 | 59 | if (! $confirmed) { 60 | $this->info('Did not create .htaccess file.'); 61 | 62 | return; 63 | } 64 | } 65 | 66 | $handle = fopen($destination, 'w'); 67 | 68 | $output = $handlebars->render('htaccess', array( 69 | 'systemFolder' => $this->getApplication()->getSystemFolder(), 70 | )); 71 | 72 | fwrite($handle, $output); 73 | 74 | fclose($handle); 75 | 76 | $this->info($destination.' created.'); 77 | } 78 | 79 | public function getLongDescription() 80 | { 81 | return 'Generate the official EE .htaccess file (as found in the [EE documentation](https://ellislab.com/expressionengine/user-guide/urls/remove_index.php.html)).'; 82 | } 83 | 84 | public function getExamples() 85 | { 86 | return array( 87 | 'Generate .htaccess in the current directory' => '', 88 | ); 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /src/Command/GithubAddonInstallerCommand.php: -------------------------------------------------------------------------------- 1 | getApi()->setOutput($this->output); 55 | 56 | if (class_exists('\Symfony\Component\Console\Helper\ProgressBar')) { 57 | $installerApp->getApi()->setProgressBar(new ProgressBar($this->output)); 58 | } else { 59 | $installerApp->getApi()->setProgressHelper($this->getHelperSet()->get('progress')); 60 | } 61 | 62 | $manifest = $installerApp->getManifest(); 63 | 64 | $addon = $this->argument('addon'); 65 | 66 | if (! $addon) { 67 | $dialog = $this->getHelper('dialog'); 68 | 69 | $validation = function ($addon) use ($manifest) { 70 | if (! isset($manifest[$addon])) { 71 | throw new \InvalidArgumentException(sprintf('Addon "%s" is invalid.', $addon)); 72 | } 73 | 74 | return $addon; 75 | }; 76 | 77 | $addon = $dialog->askAndValidate($this->output, 'Which addon do you want to install? ', $validation, false, null, array_keys($manifest)); 78 | } 79 | 80 | $branch = $this->argument('branch') ?: isset($manifest[$addon]['branch']) ? $manifest[$addon]['branch'] : 'master'; 81 | 82 | $installerApp->installAddon($addon, $branch); 83 | 84 | $this->info($addon.' installed.'); 85 | } 86 | 87 | public function getLongDescription() 88 | { 89 | return <<confirm('A configuration file already exists. Do you want to overwrite? y[n]', false); 31 | 32 | if (! $confirmed) { 33 | return; 34 | } 35 | } 36 | 37 | $source = file_get_contents(__DIR__.'/../../sample.eecli.php'); 38 | 39 | if ($source === false) { 40 | $this->error('Could not read the sample.eecli.php file.'); 41 | 42 | return; 43 | } 44 | 45 | $systemPath = $this->getApplication()->getSystemPath(); 46 | 47 | if ($systemPath) { 48 | $cwdLength = strlen($cwd); 49 | 50 | //check if the system path is in the cwd 51 | if (strncmp($cwd, $systemPath, $cwdLength) === 0) { 52 | $systemPath = substr($systemPath, $cwdLength); 53 | 54 | $replacement = "__DIR__.'{$systemPath}'"; 55 | } else { 56 | $replacement = "'{$systemPath}'"; 57 | } 58 | 59 | $source = str_replace("__DIR__.'/system'", $replacement, $source); 60 | } 61 | 62 | $handle = fopen($destination, 'w'); 63 | 64 | if ($handle === false) { 65 | $this->error('Could not open '.$destination.' for writing.'); 66 | 67 | return; 68 | } 69 | 70 | $write = fwrite($handle, $source); 71 | 72 | if ($write === false) { 73 | $this->error('Could not write to '.$destination); 74 | 75 | return; 76 | } 77 | 78 | fclose($handle); 79 | 80 | $this->info('Configuration file created.'); 81 | } 82 | 83 | /** 84 | * {@inheritdoc} 85 | */ 86 | public function getLongDescription() 87 | { 88 | return <<argument('action_id')) { 68 | ee()->db->where('action_id', $this->argument('action_id')); 69 | } 70 | 71 | $classes = $this->option('class') ?: []; 72 | 73 | if ($modules = $this->option('module')) { 74 | foreach ($modules as $module) { 75 | $classes[] = ucfirst($module); 76 | $classes[] = ucfirst($module).'_mcp'; 77 | } 78 | } 79 | 80 | if ($classes) { 81 | ee()->db->where_in('class', $classes); 82 | } 83 | 84 | if ($methods = $this->option('method')) { 85 | ee()->db->where_in('method', $methods); 86 | } 87 | 88 | $query = ee()->db->order_by('action_id') 89 | ->get('actions'); 90 | 91 | if ($query->num_rows() === 0) { 92 | if ($actionId) { 93 | $this->warning('There was no action found with the specified action_id.'); 94 | } else { 95 | $this->warning('There were no actions found.'); 96 | } 97 | } else { 98 | $results = $query->result_array(); 99 | 100 | $headers = array('ID', 'Class', 'Method'); 101 | 102 | if (array_key_exists('csrf_exempt', $results[0])) { 103 | $headers[] = 'CSRF Exempt'; 104 | } 105 | 106 | $this->table($headers, $results); 107 | } 108 | 109 | $query->free_result(); 110 | } 111 | } 112 | -------------------------------------------------------------------------------- /src/Command/ShowCategoryGroupsCommand.php: -------------------------------------------------------------------------------- 1 | db->from('category_groups'); 40 | 41 | ee()->db->where('category_groups.site_id', ee()->config->item('site_id')); 42 | 43 | $headers = array('Group ID'); 44 | 45 | ee()->db->select('category_groups.group_id'); 46 | 47 | $headers[] = 'Group Name'; 48 | 49 | ee()->db->select('category_groups.group_name'); 50 | 51 | $headers[] = 'Channels'; 52 | 53 | ee()->db->select('GROUP_CONCAT(channel_name SEPARATOR ";") AS channels'); 54 | 55 | // I know it looks bad but we have to drop the protect identifiers here to get the join working 56 | $existingProtectIdentifiers = ee()->db->_protect_identifiers; 57 | ee()->db->_protect_identifiers = false; 58 | ee()->db->join('channels', 'FIND_IN_SET(group_id, REPLACE(cat_group, "|", ",")) > 0', 'left'); 59 | ee()->db->_protect_identifiers = $existingProtectIdentifiers; 60 | 61 | ee()->db->group_by('category_groups.group_id'); 62 | 63 | if ($this->option('channel')) { 64 | 65 | ee()->db->where_in('channels.channel_name', $this->option('channel')); 66 | } 67 | 68 | $query = ee()->db->get(); 69 | 70 | $results = $query->result_array(); 71 | 72 | // alter the results and replace the semicolon with commas as CI driver doesn't like 73 | // commas in DB selects and its best not to deactivate escaping and sanitising functions 74 | $results = array_map(function($a) { 75 | return array_merge($a, array( 76 | 'channels' => str_replace(';', ',', $a['channels']), 77 | )); 78 | }, $results); 79 | 80 | $query->free_result(); 81 | 82 | $this->table($headers, $results); 83 | } 84 | } 85 | 86 | -------------------------------------------------------------------------------- /src/Command/ShowConfigCommand.php: -------------------------------------------------------------------------------- 1 | argument('key'); 55 | 56 | if ($key) { 57 | $value = $this->dump(ee()->config->item($key)); 58 | 59 | $this->line($value); 60 | 61 | return; 62 | } 63 | 64 | $headers = array('Key', 'Value'); 65 | 66 | $rows = array(); 67 | 68 | $config = ee()->config->config; 69 | 70 | ksort($config); 71 | 72 | foreach ($config as $key => $value) { 73 | if (! is_string($value) && ! is_int($value) && ! is_float($value)) { 74 | $value = $this->dump($value); 75 | } 76 | 77 | $rows[] = array($key, $value); 78 | } 79 | 80 | $this->table($headers, $rows); 81 | } 82 | 83 | /** 84 | * {@inheritdoc} 85 | */ 86 | public function getExamples() 87 | { 88 | return array( 89 | 'Show all config items' => '', 90 | 'Show the specified config item' => 'site_label', 91 | ); 92 | } 93 | 94 | /** 95 | * {@inheritdoc} 96 | */ 97 | public function getLongDescription() 98 | { 99 | return <<db->from('field_groups'); 40 | 41 | ee()->db->where('field_groups.site_id', ee()->config->item('site_id')); 42 | 43 | $headers = array('Group ID'); 44 | 45 | ee()->db->select('field_groups.group_id'); 46 | 47 | $headers[] = 'Group Name'; 48 | 49 | ee()->db->select('field_groups.group_name'); 50 | 51 | $headers[] = 'Channels'; 52 | 53 | ee()->db->select('GROUP_CONCAT(channel_name SEPARATOR ";") AS channels'); 54 | 55 | ee()->db->join('channels', 'channels.field_group = field_groups.group_id', 'left'); 56 | ee()->db->group_by('field_groups.group_id'); 57 | 58 | if ($this->option('channel')) { 59 | 60 | ee()->db->where_in('channels.channel_name', $this->option('channel')); 61 | } 62 | 63 | $query = ee()->db->get(); 64 | 65 | $results = $query->result_array(); 66 | 67 | // alter the results and replace the semicolon with commas as CI driver doesn't like 68 | // commas in DB selects and its best not to deactivate escaping and sanitising functions 69 | $results = array_map(function($a) { 70 | return array_merge($a, array( 71 | 'channels' => str_replace(';', ',', $a['channels']), 72 | )); 73 | }, $results); 74 | 75 | $query->free_result(); 76 | 77 | $this->table($headers, $results); 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /src/Command/ShowFieldsCommand.php: -------------------------------------------------------------------------------- 1 | db->from('channel_fields'); 52 | 53 | ee()->db->where('channel_fields.site_id', ee()->config->item('site_id')); 54 | 55 | $headers = array('ID'); 56 | 57 | ee()->db->select('channel_fields.field_id'); 58 | 59 | ee()->db->order_by('channel_fields.group_id', 'asc'); 60 | 61 | ee()->db->order_by('channel_fields.field_order', 'asc'); 62 | 63 | ee()->db->select('channel_fields.group_id'); 64 | 65 | $headers[] = 'Group ID'; 66 | 67 | ee()->db->join('field_groups', 'field_groups.group_id = channel_fields.group_id'); 68 | 69 | ee()->db->select('field_groups.group_name'); 70 | 71 | $headers[] = 'Group'; 72 | 73 | if ($this->option('group_id')) { 74 | ee()->db->where_in('channel_fields.group_id', $this->option('group_id')); 75 | } 76 | 77 | if ($this->option('channel')) { 78 | ee()->db->join('channels', 'channels.field_group = channel_fields.group_id'); 79 | 80 | ee()->db->where_in('channels.channel_name', $this->option('channel')); 81 | } 82 | 83 | if ($this->option('type')) { 84 | ee()->db->where_in('channel_fields.field_type', $this->option('type')); 85 | } 86 | 87 | ee()->db->select('channel_fields.field_name'); 88 | $headers[] = 'Name'; 89 | 90 | ee()->db->select('channel_fields.field_label'); 91 | $headers[] = 'Label'; 92 | 93 | ee()->db->select('channel_fields.field_type'); 94 | $headers[] = 'Type'; 95 | 96 | ee()->db->select('channel_fields.field_required'); 97 | $headers[] = 'R'; 98 | 99 | ee()->db->select('channel_fields.field_is_hidden'); 100 | $headers[] = 'H'; 101 | 102 | ee()->db->select('channel_fields.field_search'); 103 | $headers[] = 'S'; 104 | 105 | $query = ee()->db->get(); 106 | 107 | $results = $query->result_array(); 108 | 109 | $query->free_result(); 110 | 111 | $this->table($headers, $results); 112 | } 113 | } 114 | -------------------------------------------------------------------------------- /src/Command/ShowMembersCommand.php: -------------------------------------------------------------------------------- 1 | db->from('members'); 55 | 56 | $headers = array(); 57 | 58 | ee()->db->select('members.member_id'); 59 | $headers[] = 'ID'; 60 | 61 | ee()->db->join('member_groups', 'member_groups.group_id = members.group_id'); 62 | $table = ee()->db->dbprefix('member_groups'); 63 | ee()->db->select("CONCAT('(', {$table}.group_id, ') ', {$table}.group_title) AS group_name", FALSE); 64 | $headers[] = 'Group'; 65 | 66 | ee()->db->select('members.username'); 67 | $headers[] = 'Username'; 68 | 69 | ee()->db->select('members.screen_name'); 70 | $headers[] = 'Screen Name'; 71 | 72 | ee()->db->select('members.email'); 73 | $headers[] = 'Email'; 74 | 75 | if ($this->option('group_id')) { 76 | ee()->db->where_in('members.group_id', $this->option('group_id')); 77 | } 78 | 79 | $search = $this->argument('search'); 80 | 81 | if ($search) { 82 | if (is_numeric($search)) { 83 | ee()->db->where('members.member_id', $search); 84 | } else { 85 | ee()->db->like('members.username', $search) 86 | ->or_like('members.screen_name', $search) 87 | ->or_like('members.email', $search); 88 | } 89 | } 90 | 91 | $sql = ee()->db->_compile_select(); 92 | ee()->db->_reset_select(); 93 | $this->output->writeln($sql); 94 | $query = ee()->db->query($sql); 95 | //$query = ee()->db->get(); 96 | 97 | $results = $query->result_array(); 98 | 99 | $query->free_result(); 100 | 101 | $this->table($headers, $results); 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /src/Command/ShowTemplatesCommand.php: -------------------------------------------------------------------------------- 1 | db->from('templates') 25 | ->select('template_id') 26 | ->select("CONCAT(IF (is_site_default = 'y' AND template_name = 'index', '*', ''), group_name, '/', template_name) AS template", false) 27 | ->join('template_groups', 'template_groups.group_id = templates.group_id') 28 | ->order_by('group_order', 'asc') 29 | ->order_by('template_name', 'asc') 30 | ->get(); 31 | 32 | $templates = $query->result_array(); 33 | 34 | $query->free_result(); 35 | 36 | $this->table(array('ID', 'Template'), $templates); 37 | } 38 | 39 | /** 40 | * {@inheritdoc} 41 | */ 42 | public function getExamples() 43 | { 44 | return array( 45 | 'List all of the templates found in the database' => '', 46 | ); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/Command/ShowVersionCommand.php: -------------------------------------------------------------------------------- 1 | line(sprintf('ExpressionEngine version %s', APP_VER)); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/Command/SyncTemplatesCommand.php: -------------------------------------------------------------------------------- 1 | config->item('save_tmpl_files') !== 'y' || ! ee()->config->item('tmpl_file_basepath')) { 23 | $this->error('The "Save Templates as Files" system configuration must be turned on to use this command.'); 24 | 25 | return; 26 | } 27 | 28 | $this->getApplication()->newControllerInstance('\\eecli\\CodeIgniter\\Controller\\DesignController'); 29 | 30 | ee()->sync_templates(); 31 | 32 | $vars = ee()->cp->getVariables(); 33 | 34 | $toggle = array(); 35 | 36 | foreach ($vars['templates'] as $groupName => $templates) { 37 | foreach ($templates as $templateName => $templateData) { 38 | if (isset($templateData['toggle']) && preg_match('#name="toggle\[\]" value="(.*?)"#', $templateData['toggle'], $match)) { 39 | $toggle[] = $match[1]; 40 | } 41 | } 42 | } 43 | 44 | if (empty($toggle)) { 45 | $this->error('There are no templates to sync.'); 46 | 47 | return; 48 | } 49 | 50 | $_POST = array( 51 | 'confirm' => 'confirm', 52 | 'toggle' => $toggle, 53 | ); 54 | 55 | ee()->sync_run(); 56 | 57 | if (ee()->functions->getErrorMessage()) { 58 | $this->error(ee()->functions->getErrorMessage()); 59 | 60 | return; 61 | } 62 | 63 | if (ee()->functions->getSuccessMessage()) { 64 | $this->info(ee()->functions->getSuccessMessage()); 65 | } 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /src/Console/GlobalArgvInput.php: -------------------------------------------------------------------------------- 1 | commandName = current($tokens); 40 | 41 | $this->originalTokens = $tokens; 42 | 43 | parent::__construct($argv, $definition); 44 | } 45 | 46 | /** 47 | * Get the command name 48 | * @return string 49 | */ 50 | public function getCommandName() 51 | { 52 | return $this->commandName; 53 | } 54 | 55 | /** 56 | * Get the input definition 57 | * @return \Symfony\Component\Console\Input\InputDefinition 58 | */ 59 | public function getDefinition() 60 | { 61 | return $this->definition; 62 | } 63 | 64 | /** 65 | * {@inheritdoc} 66 | */ 67 | protected function parse() 68 | { 69 | $parsed = $tokens = $this->originalTokens; 70 | 71 | while (null !== $token = array_shift($parsed)) { 72 | $this->setTokens(array($token)); 73 | try { 74 | parent::parse(); 75 | } catch (RuntimeException $e) { 76 | // ignore these errors, otherwise re-throw it 77 | if (! preg_match('/^Too many arguments|^No arguments expected|does not exist\.$/', $e->getMessage())) { 78 | throw $e; 79 | } 80 | } 81 | } 82 | 83 | $this->setTokens($tokens); 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /src/Db/ConnectionTester.php: -------------------------------------------------------------------------------- 1 | hostname = $hostname; 35 | $this->username = $username; 36 | $this->password = $password; 37 | $this->database = $database; 38 | } 39 | 40 | /** 41 | * Test whether a valid DB connection can 42 | * be made with the specified credentials 43 | * @return bool 44 | */ 45 | abstract public function test(); 46 | 47 | /** 48 | * Set the error message 49 | * @param string $error 50 | */ 51 | public function setError($error) 52 | { 53 | $this->error = $error; 54 | } 55 | 56 | /** 57 | * Get the error message 58 | * @return string|null 59 | */ 60 | public function getError() 61 | { 62 | return $this->error; 63 | } 64 | 65 | /** 66 | * Create a new DB tester instance depending 67 | * on the driver specified. 68 | * 69 | * @param string $driver mysql or mysqli 70 | * @param string $hostname 71 | * @param string $username 72 | * @param string $password 73 | * @param string $database 74 | * @return \eecli\Db\ConnectionTester 75 | */ 76 | public static function create($driver, $hostname, $username, $password, $database) 77 | { 78 | switch ($driver) { 79 | case 'mysql': 80 | return new MysqlTester($hostname, $username, $password, $database); 81 | case 'mysqli': 82 | return new MysqliTester($hostname, $username, $password, $database); 83 | } 84 | 85 | throw new \Exception(sprintf('Unsupported DB driver %s', $driver)); 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /src/Db/MysqlTester.php: -------------------------------------------------------------------------------- 1 | hostname, $this->username, $this->password); 13 | 14 | if ($connection === false) { 15 | $error = @mysql_error(); 16 | 17 | if ($error === 'No such file or directory') { 18 | $error = sprintf('Could not connect to socket %s', @ini_get('mysql.default_socket')); 19 | } 20 | 21 | $this->setError($error); 22 | 23 | return false; 24 | } 25 | 26 | $db = @mysql_select_db($this->database, $connection); 27 | 28 | if ($db === false) { 29 | $this->setError(@mysql_error()); 30 | 31 | return false; 32 | } 33 | 34 | @mysql_close($connection); 35 | 36 | return true; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/Db/MysqliTester.php: -------------------------------------------------------------------------------- 1 | hostname, $this->username, $this->password, $this->database); 15 | 16 | if ($connection === false) { 17 | $error = mysqli_connect_error(); 18 | 19 | if ($error === 'No such file or directory') { 20 | $error = sprintf('Could not connect to socket %s', @ini_get('mysqli.default_socket')); 21 | } 22 | 23 | $this->setError($error); 24 | 25 | return false; 26 | } 27 | 28 | @mysqli_close($connection); 29 | 30 | return true; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/Handlebars/Loader/FilesystemLoader.php: -------------------------------------------------------------------------------- 1 | normalizePath($match[1]), '/'); 26 | } 27 | 28 | return parent::sanitizeDirectory($dir); 29 | } 30 | 31 | /** 32 | * Normalize path. 33 | * 34 | * From https://github.com/thephpleague/flysystem/blob/master/src/Util.php 35 | * 36 | * @param string $path 37 | * 38 | * @throws LogicException 39 | * 40 | * @return string 41 | */ 42 | protected function normalizePath($path) 43 | { 44 | // Remove any kind of funky unicode whitespace 45 | $normalized = preg_replace('#\p{C}+|^\./#u', '', $path); 46 | $normalized = $this->normalizeRelativePath($normalized); 47 | if (preg_match('#/\.{2}|^\.{2}/|^\.{2}$#', $normalized)) { 48 | throw new LogicException( 49 | 'Path is outside of the defined root, path: [' . $path . '], resolved: [' . $normalized . ']' 50 | ); 51 | } 52 | $normalized = preg_replace('#\\\{2,}#', '\\', trim($normalized, '\\')); 53 | $normalized = preg_replace('#/{2,}#', '/', trim($normalized, '/')); 54 | return $normalized; 55 | } 56 | 57 | /** 58 | * Normalize relative directories in a path. 59 | * 60 | * From https://github.com/thephpleague/flysystem/blob/master/src/Util.php 61 | * 62 | * @param string $path 63 | * 64 | * @return string 65 | */ 66 | protected function normalizeRelativePath($path) 67 | { 68 | // Path remove self referring paths ("/./"). 69 | $path = preg_replace('#/\.(?=/)|^\./|/\./?$#', '', $path); 70 | // Regex for resolving relative paths 71 | $regex = '#/*[^/\.]+/\.\.#Uu'; 72 | while (preg_match($regex, $path)) { 73 | $path = preg_replace($regex, '', $path); 74 | } 75 | return $path; 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /src/bootstrap.php: -------------------------------------------------------------------------------- 1 | setVendorPath($vendor_path); 22 | 23 | $app->fire('bootstrap.before'); 24 | 25 | if ($app->canBeBootstrapped()) { 26 | require $vendor_path.'eecli/bootstrap/bootstrap-ee2.php'; 27 | } 28 | 29 | $app->fire('bootstrap.after'); 30 | 31 | $app->addComposerCommands(); 32 | $app->addConditionalCommands(); 33 | $app->addThirdPartyCommands(); 34 | $app->addUserDefinedCommands(); 35 | $app->addGlobalCommands(); 36 | 37 | $app->run(); 38 | -------------------------------------------------------------------------------- /src/stub.php: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env php 2 | 2 | RewriteEngine On 3 | RewriteBase / 4 | 5 | # Removes index.php from ExpressionEngine URLs 6 | RewriteCond %{THE_REQUEST} ^GET.*index\.php [NC] 7 | RewriteCond %{REQUEST_URI} !/{{systemFolder}}/.* [NC] 8 | RewriteRule (.*?)index\.php/*(.*) /$1$2 [R=301,NE,L] 9 | 10 | # Directs all EE web requests through the site index file 11 | RewriteCond %{REQUEST_FILENAME} !-f 12 | RewriteCond %{REQUEST_FILENAME} !-d 13 | RewriteRule ^(.*)$ /index.php/$1 [L] 14 | --------------------------------------------------------------------------------