1<?php 2/** 3 * Template Task can generate templated output Used in other Tasks 4 * 5 * CakePHP(tm) : Rapid Development Framework (https://cakephp.org) 6 * Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) 7 * 8 * Licensed under The MIT License 9 * For full copyright and license information, please see the LICENSE.txt 10 * Redistributions of files must retain the above copyright notice. 11 * 12 * @copyright Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) 13 * @link https://cakephp.org CakePHP(tm) Project 14 * @since CakePHP(tm) v 1.3 15 * @license https://opensource.org/licenses/mit-license.php MIT License 16 */ 17 18App::uses('AppShell', 'Console/Command'); 19App::uses('Folder', 'Utility'); 20 21/** 22 * Template Task can generate templated output Used in other Tasks. 23 * Acts like a simplified View class. 24 * 25 * @package Cake.Console.Command.Task 26 */ 27class TemplateTask extends AppShell { 28 29/** 30 * variables to add to template scope 31 * 32 * @var array 33 */ 34 public $templateVars = array(); 35 36/** 37 * Paths to look for templates on. 38 * Contains a list of $theme => $path 39 * 40 * @var array 41 */ 42 public $templatePaths = array(); 43 44/** 45 * Initialize callback. Setup paths for the template task. 46 * 47 * @return void 48 */ 49 public function initialize() { 50 $this->templatePaths = $this->_findThemes(); 51 } 52 53/** 54 * Find the paths to all the installed shell themes in the app. 55 * 56 * Bake themes are directories not named `skel` inside a `Console/Templates` path. 57 * They are listed in this order: app -> plugin -> default 58 * 59 * @return array Array of bake themes that are installed. 60 */ 61 protected function _findThemes() { 62 $paths = App::path('Console'); 63 64 $plugins = App::objects('plugin'); 65 foreach ($plugins as $plugin) { 66 $paths[] = $this->_pluginPath($plugin) . 'Console' . DS; 67 } 68 69 $core = current(App::core('Console')); 70 $separator = DS === '/' ? '/' : '\\\\'; 71 $core = preg_replace('#shells' . $separator . '$#', '', $core); 72 73 $Folder = new Folder($core . 'Templates' . DS . 'default'); 74 75 $contents = $Folder->read(); 76 $themeFolders = $contents[0]; 77 78 $paths[] = $core; 79 80 foreach ($paths as $i => $path) { 81 $paths[$i] = rtrim($path, DS) . DS; 82 } 83 84 $themes = array(); 85 foreach ($paths as $path) { 86 $Folder = new Folder($path . 'Templates', false); 87 $contents = $Folder->read(); 88 $subDirs = $contents[0]; 89 foreach ($subDirs as $dir) { 90 if (empty($dir) || preg_match('@^skel$|_skel$@', $dir)) { 91 continue; 92 } 93 $Folder = new Folder($path . 'Templates' . DS . $dir); 94 $contents = $Folder->read(); 95 $subDirs = $contents[0]; 96 if (array_intersect($contents[0], $themeFolders)) { 97 $templateDir = $path . 'Templates' . DS . $dir . DS; 98 $themes[$dir] = $templateDir; 99 } 100 } 101 } 102 return $themes; 103 } 104 105/** 106 * Set variable values to the template scope 107 * 108 * @param string|array $one A string or an array of data. 109 * @param string|array $two Value in case $one is a string (which then works as the key). 110 * Unused if $one is an associative array, otherwise serves as the values to $one's keys. 111 * @return void 112 */ 113 public function set($one, $two = null) { 114 if (is_array($one)) { 115 if (is_array($two)) { 116 $data = array_combine($one, $two); 117 } else { 118 $data = $one; 119 } 120 } else { 121 $data = array($one => $two); 122 } 123 124 if (!$data) { 125 return false; 126 } 127 $this->templateVars = $data + $this->templateVars; 128 } 129 130/** 131 * Runs the template 132 * 133 * @param string $directory directory / type of thing you want 134 * @param string $filename template name 135 * @param array $vars Additional vars to set to template scope. 136 * @return string contents of generated code template 137 */ 138 public function generate($directory, $filename, $vars = null) { 139 if ($vars !== null) { 140 $this->set($vars); 141 } 142 if (empty($this->templatePaths)) { 143 $this->initialize(); 144 } 145 $themePath = $this->getThemePath(); 146 $templateFile = $this->_findTemplate($themePath, $directory, $filename); 147 if ($templateFile) { 148 extract($this->templateVars); 149 ob_start(); 150 ob_implicit_flush(0); 151 include $templateFile; 152 $content = ob_get_clean(); 153 return $content; 154 } 155 return ''; 156 } 157 158/** 159 * Find the theme name for the current operation. 160 * If there is only one theme in $templatePaths it will be used. 161 * If there is a -theme param in the cli args, it will be used. 162 * If there is more than one installed theme user interaction will happen 163 * 164 * @return string returns the path to the selected theme. 165 */ 166 public function getThemePath() { 167 if (count($this->templatePaths) === 1) { 168 $paths = array_values($this->templatePaths); 169 return $paths[0]; 170 } 171 if (!empty($this->params['theme']) && isset($this->templatePaths[$this->params['theme']])) { 172 return $this->templatePaths[$this->params['theme']]; 173 } 174 175 $this->hr(); 176 $this->out(__d('cake_console', 'You have more than one set of templates installed.')); 177 $this->out(__d('cake_console', 'Please choose the template set you wish to use:')); 178 $this->hr(); 179 180 $i = 1; 181 $indexedPaths = array(); 182 foreach ($this->templatePaths as $key => $path) { 183 $this->out($i . '. ' . $key); 184 $indexedPaths[$i] = $path; 185 $i++; 186 } 187 $index = $this->in(__d('cake_console', 'Which bake theme would you like to use?'), range(1, $i - 1), 1); 188 $themeNames = array_keys($this->templatePaths); 189 $this->params['theme'] = $themeNames[$index - 1]; 190 return $indexedPaths[$index]; 191 } 192 193/** 194 * Find a template inside a directory inside a path. 195 * Will scan all other theme dirs if the template is not found in the first directory. 196 * 197 * @param string $path The initial path to look for the file on. If it is not found fallbacks will be used. 198 * @param string $directory Subdirectory to look for ie. 'views', 'objects' 199 * @param string $filename lower_case_underscored filename you want. 200 * @return string filename will exit program if template is not found. 201 */ 202 protected function _findTemplate($path, $directory, $filename) { 203 $themeFile = $path . $directory . DS . $filename . '.ctp'; 204 if (file_exists($themeFile)) { 205 return $themeFile; 206 } 207 foreach ($this->templatePaths as $path) { 208 $templatePath = $path . $directory . DS . $filename . '.ctp'; 209 if (file_exists($templatePath)) { 210 return $templatePath; 211 } 212 } 213 $this->err(__d('cake_console', 'Could not find template for %s', $filename)); 214 return false; 215 } 216 217} 218