PageRenderTime 36ms CodeModel.GetById 8ms RepoModel.GetById 0ms app.codeStats 0ms

/lib/Cake/Console/Command/Task/ProjectTask.php

https://gitlab.com/manuperazafa/elsartenbackend
PHP | 448 lines | 332 code | 33 blank | 83 comment | 56 complexity | 904dd1afeab668de8c9982ee18af542b MD5 | raw file
  1. <?php
  2. /**
  3. * The Project Task handles creating the base application
  4. *
  5. * CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
  6. * Copyright (c) Cake Software Foundation, Inc. (http://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. (http://cakefoundation.org)
  13. * @link http://cakephp.org CakePHP(tm) Project
  14. * @since CakePHP(tm) v 1.2
  15. * @license http://www.opensource.org/licenses/mit-license.php MIT License
  16. */
  17. App::uses('AppShell', 'Console/Command');
  18. App::uses('File', 'Utility');
  19. App::uses('Folder', 'Utility');
  20. App::uses('String', 'Utility');
  21. App::uses('Security', 'Utility');
  22. /**
  23. * Task class for creating new project apps and plugins
  24. *
  25. * @package Cake.Console.Command.Task
  26. */
  27. class ProjectTask extends AppShell {
  28. /**
  29. * configs path (used in testing).
  30. *
  31. * @var string
  32. */
  33. public $configPath = null;
  34. /**
  35. * Checks that given project path does not already exist, and
  36. * finds the app directory in it. Then it calls bake() with that information.
  37. *
  38. * @return mixed
  39. */
  40. public function execute() {
  41. $project = null;
  42. if (isset($this->args[0])) {
  43. $project = $this->args[0];
  44. } else {
  45. $appContents = array_diff(scandir(APP), array('.', '..'));
  46. if (empty($appContents)) {
  47. $suggestedPath = rtrim(APP, DS);
  48. } else {
  49. $suggestedPath = APP . 'myapp';
  50. }
  51. }
  52. while (!$project) {
  53. $prompt = __d('cake_console', "What is the path to the project you want to bake?");
  54. $project = $this->in($prompt, null, $suggestedPath);
  55. }
  56. if ($project && !Folder::isAbsolute($project) && isset($_SERVER['PWD'])) {
  57. $project = $_SERVER['PWD'] . DS . $project;
  58. }
  59. $response = false;
  60. while (!$response && is_dir($project) === true && file_exists($project . 'Config' . 'core.php')) {
  61. $prompt = __d('cake_console', '<warning>A project already exists in this location:</warning> %s Overwrite?', $project);
  62. $response = $this->in($prompt, array('y', 'n'), 'n');
  63. if (strtolower($response) === 'n') {
  64. $response = $project = false;
  65. }
  66. }
  67. $success = true;
  68. if ($this->bake($project)) {
  69. $path = Folder::slashTerm($project);
  70. if ($this->securitySalt($path) === true) {
  71. $this->out(__d('cake_console', ' * Random hash key created for \'Security.salt\''));
  72. } else {
  73. $this->err(__d('cake_console', 'Unable to generate random hash for \'Security.salt\', you should change it in %s', APP . 'Config' . DS . 'core.php'));
  74. $success = false;
  75. }
  76. if ($this->securityCipherSeed($path) === true) {
  77. $this->out(__d('cake_console', ' * Random seed created for \'Security.cipherSeed\''));
  78. } else {
  79. $this->err(__d('cake_console', 'Unable to generate random seed for \'Security.cipherSeed\', you should change it in %s', APP . 'Config' . DS . 'core.php'));
  80. $success = false;
  81. }
  82. if ($this->cachePrefix($path)) {
  83. $this->out(__d('cake_console', ' * Cache prefix set'));
  84. } else {
  85. $this->err(__d('cake_console', 'The cache prefix was <error>NOT</error> set'));
  86. $success = false;
  87. }
  88. if ($this->consolePath($path) === true) {
  89. $this->out(__d('cake_console', ' * app/Console/cake.php path set.'));
  90. } else {
  91. $this->err(__d('cake_console', 'Unable to set console path for app/Console.'));
  92. $success = false;
  93. }
  94. $hardCode = false;
  95. if ($this->cakeOnIncludePath()) {
  96. $this->out(__d('cake_console', '<info>CakePHP is on your `include_path`. CAKE_CORE_INCLUDE_PATH will be set, but commented out.</info>'));
  97. } else {
  98. $this->out(__d('cake_console', '<warning>CakePHP is not on your `include_path`, CAKE_CORE_INCLUDE_PATH will be hard coded.</warning>'));
  99. $this->out(__d('cake_console', 'You can fix this by adding CakePHP to your `include_path`.'));
  100. $hardCode = true;
  101. }
  102. $success = $this->corePath($path, $hardCode) === true;
  103. if ($success) {
  104. $this->out(__d('cake_console', ' * CAKE_CORE_INCLUDE_PATH set to %s in %s', CAKE_CORE_INCLUDE_PATH, 'webroot/index.php'));
  105. $this->out(__d('cake_console', ' * CAKE_CORE_INCLUDE_PATH set to %s in %s', CAKE_CORE_INCLUDE_PATH, 'webroot/test.php'));
  106. } else {
  107. $this->err(__d('cake_console', 'Unable to set CAKE_CORE_INCLUDE_PATH, you should change it in %s', $path . 'webroot' . DS . 'index.php'));
  108. $success = false;
  109. }
  110. if ($success && $hardCode) {
  111. $this->out(__d('cake_console', ' * <warning>Remember to check these values after moving to production server</warning>'));
  112. }
  113. $Folder = new Folder($path);
  114. if (!$Folder->chmod($path . 'tmp', 0777)) {
  115. $this->err(__d('cake_console', 'Could not set permissions on %s', $path . DS . 'tmp'));
  116. $this->out('chmod -R 0777 ' . $path . DS . 'tmp');
  117. $success = false;
  118. }
  119. if ($success) {
  120. $this->out(__d('cake_console', '<success>Project baked successfully!</success>'));
  121. } else {
  122. $this->out(__d('cake_console', 'Project baked but with <warning>some issues.</warning>.'));
  123. }
  124. return $path;
  125. }
  126. }
  127. /**
  128. * Checks PHP's include_path for CakePHP.
  129. *
  130. * @return bool Indicates whether or not CakePHP exists on include_path
  131. */
  132. public function cakeOnIncludePath() {
  133. $paths = explode(PATH_SEPARATOR, ini_get('include_path'));
  134. foreach ($paths as $path) {
  135. if (file_exists($path . DS . 'Cake' . DS . 'bootstrap.php')) {
  136. return true;
  137. }
  138. }
  139. return false;
  140. }
  141. /**
  142. * Looks for a skeleton template of a Cake application,
  143. * and if not found asks the user for a path. When there is a path
  144. * this method will make a deep copy of the skeleton to the project directory.
  145. *
  146. * @param string $path Project path
  147. * @param string $skel Path to copy from
  148. * @param string $skip array of directories to skip when copying
  149. * @return mixed
  150. */
  151. public function bake($path, $skel = null, $skip = array('empty')) {
  152. if (!$skel && !empty($this->params['skel'])) {
  153. $skel = $this->params['skel'];
  154. }
  155. while (!$skel) {
  156. $skel = $this->in(
  157. __d('cake_console', "What is the path to the directory layout you wish to copy?"),
  158. null,
  159. CAKE . 'Console' . DS . 'Templates' . DS . 'skel'
  160. );
  161. if (!$skel) {
  162. $this->err(__d('cake_console', 'The directory path you supplied was empty. Please try again.'));
  163. } else {
  164. while (is_dir($skel) === false) {
  165. $skel = $this->in(
  166. __d('cake_console', 'Directory path does not exist please choose another:'),
  167. null,
  168. CAKE . 'Console' . DS . 'Templates' . DS . 'skel'
  169. );
  170. }
  171. }
  172. }
  173. $app = basename($path);
  174. $this->out(__d('cake_console', '<info>Skel Directory</info>: ') . $skel);
  175. $this->out(__d('cake_console', '<info>Will be copied to</info>: ') . $path);
  176. $this->hr();
  177. $looksGood = $this->in(__d('cake_console', 'Look okay?'), array('y', 'n', 'q'), 'y');
  178. switch (strtolower($looksGood)) {
  179. case 'y':
  180. $Folder = new Folder($skel);
  181. if (!empty($this->params['empty'])) {
  182. $skip = array();
  183. }
  184. if ($Folder->copy(array('to' => $path, 'skip' => $skip))) {
  185. $this->hr();
  186. $this->out(__d('cake_console', '<success>Created:</success> %s in %s', $app, $path));
  187. $this->hr();
  188. } else {
  189. $this->err(__d('cake_console', "<error>Could not create</error> '%s' properly.", $app));
  190. return false;
  191. }
  192. foreach ($Folder->messages() as $message) {
  193. $this->out(String::wrap(' * ' . $message), 1, Shell::VERBOSE);
  194. }
  195. return true;
  196. case 'n':
  197. unset($this->args[0]);
  198. $this->execute();
  199. return false;
  200. case 'q':
  201. $this->out(__d('cake_console', '<error>Bake Aborted.</error>'));
  202. return false;
  203. }
  204. }
  205. /**
  206. * Generates the correct path to the CakePHP libs that are generating the project
  207. * and points app/console/cake.php to the right place
  208. *
  209. * @param string $path Project path.
  210. * @return bool success
  211. */
  212. public function consolePath($path) {
  213. $File = new File($path . 'Console' . DS . 'cake.php');
  214. $contents = $File->read();
  215. if (preg_match('/(__CAKE_PATH__)/', $contents, $match)) {
  216. $root = strpos(CAKE_CORE_INCLUDE_PATH, '/') === 0 ? " DS . '" : "'";
  217. $replacement = $root . str_replace(DS, "' . DS . '", trim(CAKE_CORE_INCLUDE_PATH, DS)) . "'";
  218. $result = str_replace($match[0], $replacement, $contents);
  219. if ($File->write($result)) {
  220. return true;
  221. }
  222. return false;
  223. }
  224. return false;
  225. }
  226. /**
  227. * Generates and writes 'Security.salt'
  228. *
  229. * @param string $path Project path
  230. * @return bool Success
  231. */
  232. public function securitySalt($path) {
  233. $File = new File($path . 'Config' . DS . 'core.php');
  234. $contents = $File->read();
  235. if (preg_match('/([\s]*Configure::write\(\'Security.salt\',[\s\'A-z0-9]*\);)/', $contents, $match)) {
  236. $string = Security::generateAuthKey();
  237. $result = str_replace($match[0], "\t" . 'Configure::write(\'Security.salt\', \'' . $string . '\');', $contents);
  238. if ($File->write($result)) {
  239. return true;
  240. }
  241. return false;
  242. }
  243. return false;
  244. }
  245. /**
  246. * Generates and writes 'Security.cipherSeed'
  247. *
  248. * @param string $path Project path
  249. * @return bool Success
  250. */
  251. public function securityCipherSeed($path) {
  252. $File = new File($path . 'Config' . DS . 'core.php');
  253. $contents = $File->read();
  254. if (preg_match('/([\s]*Configure::write\(\'Security.cipherSeed\',[\s\'A-z0-9]*\);)/', $contents, $match)) {
  255. App::uses('Security', 'Utility');
  256. $string = substr(bin2hex(Security::generateAuthKey()), 0, 30);
  257. $result = str_replace($match[0], "\t" . 'Configure::write(\'Security.cipherSeed\', \'' . $string . '\');', $contents);
  258. if ($File->write($result)) {
  259. return true;
  260. }
  261. return false;
  262. }
  263. return false;
  264. }
  265. /**
  266. * Writes cache prefix using app's name
  267. *
  268. * @param string $dir Path to project
  269. * @return bool Success
  270. */
  271. public function cachePrefix($dir) {
  272. $app = basename($dir);
  273. $File = new File($dir . 'Config' . DS . 'core.php');
  274. $contents = $File->read();
  275. if (preg_match('/(\$prefix = \'myapp_\';)/', $contents, $match)) {
  276. $result = str_replace($match[0], '$prefix = \'' . $app . '_\';', $contents);
  277. return $File->write($result);
  278. }
  279. return false;
  280. }
  281. /**
  282. * Generates and writes CAKE_CORE_INCLUDE_PATH
  283. *
  284. * @param string $path Project path
  285. * @param bool $hardCode Whether or not define calls should be hardcoded.
  286. * @return bool Success
  287. */
  288. public function corePath($path, $hardCode = true) {
  289. if (dirname($path) !== CAKE_CORE_INCLUDE_PATH) {
  290. $filename = $path . 'webroot' . DS . 'index.php';
  291. if (!$this->_replaceCorePath($filename, $hardCode)) {
  292. return false;
  293. }
  294. $filename = $path . 'webroot' . DS . 'test.php';
  295. if (!$this->_replaceCorePath($filename, $hardCode)) {
  296. return false;
  297. }
  298. return true;
  299. }
  300. }
  301. /**
  302. * Replaces the __CAKE_PATH__ placeholder in the template files.
  303. *
  304. * @param string $filename The filename to operate on.
  305. * @param bool $hardCode Whether or not the define should be uncommented.
  306. * @return bool Success
  307. */
  308. protected function _replaceCorePath($filename, $hardCode) {
  309. $contents = file_get_contents($filename);
  310. $root = strpos(CAKE_CORE_INCLUDE_PATH, '/') === 0 ? " DS . '" : "'";
  311. $corePath = $root . str_replace(DS, "' . DS . '", trim(CAKE_CORE_INCLUDE_PATH, DS)) . "'";
  312. $result = str_replace('__CAKE_PATH__', $corePath, $contents, $count);
  313. if ($hardCode) {
  314. $result = str_replace('//define(\'CAKE_CORE', 'define(\'CAKE_CORE', $result);
  315. }
  316. if (!file_put_contents($filename, $result)) {
  317. return false;
  318. }
  319. return (bool)$count;
  320. }
  321. /**
  322. * Enables Configure::read('Routing.prefixes') in /app/Config/core.php
  323. *
  324. * @param string $name Name to use as admin routing
  325. * @return bool Success
  326. */
  327. public function cakeAdmin($name) {
  328. $path = (empty($this->configPath)) ? APP . 'Config' . DS : $this->configPath;
  329. $File = new File($path . 'core.php');
  330. $contents = $File->read();
  331. if (preg_match('%(\s*[/]*Configure::write\(\'Routing.prefixes\',[\s\'a-z,\)\(]*\);)%', $contents, $match)) {
  332. $result = str_replace($match[0], "\n" . 'Configure::write(\'Routing.prefixes\', array(\'' . $name . '\'));', $contents);
  333. if ($File->write($result)) {
  334. Configure::write('Routing.prefixes', array($name));
  335. return true;
  336. }
  337. }
  338. return false;
  339. }
  340. /**
  341. * Checks for Configure::read('Routing.prefixes') and forces user to input it if not enabled
  342. *
  343. * @return string Admin route to use
  344. */
  345. public function getPrefix() {
  346. $admin = '';
  347. $prefixes = Configure::read('Routing.prefixes');
  348. if (!empty($prefixes)) {
  349. if (count($prefixes) === 1) {
  350. return $prefixes[0] . '_';
  351. }
  352. if ($this->interactive) {
  353. $this->out();
  354. $this->out(__d('cake_console', 'You have more than one routing prefix configured'));
  355. }
  356. $options = array();
  357. foreach ($prefixes as $i => $prefix) {
  358. $options[] = $i + 1;
  359. if ($this->interactive) {
  360. $this->out($i + 1 . '. ' . $prefix);
  361. }
  362. }
  363. $selection = $this->in(__d('cake_console', 'Please choose a prefix to bake with.'), $options, 1);
  364. return $prefixes[$selection - 1] . '_';
  365. }
  366. if ($this->interactive) {
  367. $this->hr();
  368. $this->out(__d('cake_console', 'You need to enable %s in %s to use prefix routing.',
  369. 'Configure::write(\'Routing.prefixes\', array(\'admin\'))',
  370. '/app/Config/core.php'));
  371. $this->out(__d('cake_console', 'What would you like the prefix route to be?'));
  372. $this->out(__d('cake_console', 'Example: %s', 'www.example.com/admin/controller'));
  373. while (!$admin) {
  374. $admin = $this->in(__d('cake_console', 'Enter a routing prefix:'), null, 'admin');
  375. }
  376. if ($this->cakeAdmin($admin) !== true) {
  377. $this->out(__d('cake_console', '<error>Unable to write to</error> %s.', '/app/Config/core.php'));
  378. $this->out(__d('cake_console', 'You need to enable %s in %s to use prefix routing.',
  379. 'Configure::write(\'Routing.prefixes\', array(\'admin\'))',
  380. '/app/Config/core.php'));
  381. return $this->_stop();
  382. }
  383. return $admin . '_';
  384. }
  385. return '';
  386. }
  387. /**
  388. * Gets the option parser instance and configures it.
  389. *
  390. * @return ConsoleOptionParser
  391. */
  392. public function getOptionParser() {
  393. $parser = parent::getOptionParser();
  394. $parser->description(
  395. __d('cake_console', 'Generate a new CakePHP project skeleton.')
  396. )->addArgument('name', array(
  397. 'help' => __d('cake_console', 'Application directory to make, if it starts with "/" the path is absolute.')
  398. ))->addOption('empty', array(
  399. 'boolean' => true,
  400. 'help' => __d('cake_console', 'Create empty files in each of the directories. Good if you are using git')
  401. ))->addOption('theme', array(
  402. 'short' => 't',
  403. 'help' => __d('cake_console', 'Theme to use when baking code.')
  404. ))->addOption('skel', array(
  405. 'default' => current(App::core('Console')) . 'Templates' . DS . 'skel',
  406. 'help' => __d('cake_console', 'The directory layout to use for the new application skeleton.' .
  407. ' Defaults to cake/Console/Templates/skel of CakePHP used to create the project.')
  408. ));
  409. return $parser;
  410. }
  411. }