PageRenderTime 42ms CodeModel.GetById 13ms RepoModel.GetById 0ms app.codeStats 0ms

/plugins/Console.php

http://atomikframework.googlecode.com/
PHP | 341 lines | 154 code | 47 blank | 140 comment | 12 complexity | 813d830df11611998394036ac1b05f38 MD5 | raw file
Possible License(s): LGPL-2.1, MIT, CC-BY-3.0
  1. <?php
  2. /**
  3. * Atomik Framework
  4. * Copyright (c) 2008-2009 Maxime Bouroumeau-Fuseau
  5. *
  6. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  7. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  8. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  9. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  10. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  11. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  12. * THE SOFTWARE.
  13. *
  14. * @package Atomik
  15. * @subpackage Plugins
  16. * @author Maxime Bouroumeau-Fuseau
  17. * @copyright 2008-2009 (c) Maxime Bouroumeau-Fuseau
  18. * @license http://www.opensource.org/licenses/mit-license.php
  19. * @link http://www.atomikframework.com
  20. */
  21. /**
  22. * Console plugin
  23. *
  24. * CLI commands to simplify administration
  25. *
  26. * index.php command [arg1 [arg2 [...]]]
  27. *
  28. * Two builtin commands: init and generate
  29. *
  30. * @package Atomik
  31. * @subpackage Plugins
  32. */
  33. class ConsolePlugin
  34. {
  35. /** @var array */
  36. public static $config = array();
  37. /** @var array */
  38. protected static $_commands = array();
  39. /**
  40. * Checks we're in console mode
  41. *
  42. * @param array $config
  43. * @return bool
  44. */
  45. public static function start(&$config)
  46. {
  47. $config = array_merge(array(
  48. // directory where scripts are stored
  49. 'scripts_dir' => './app/scripts'
  50. ), $config);
  51. self::$config = &$config;
  52. // checks if we are in the CLI
  53. if (isset($_SERVER['HTTP_HOST'])) {
  54. return false;
  55. }
  56. // registers builtin commands
  57. self::register('init', array('ConsolePlugin', 'init'));
  58. self::register('generate', array('ConsolePlugin', 'generate'));
  59. }
  60. /**
  61. * Returns script directories
  62. *
  63. * @return array
  64. */
  65. public static function getScriptDirs()
  66. {
  67. $paths = (array) self::$config['scripts_dir'];
  68. foreach (Atomik::getLoadedPlugins(true) as $plugin => $path) {
  69. $paths[] = $path;
  70. }
  71. return $paths;
  72. }
  73. /**
  74. * Display the console and execute callbacks associated
  75. * to the command
  76. */
  77. public static function onAtomikStart()
  78. {
  79. restore_error_handler();
  80. $success = true;
  81. try {
  82. echo "Atomik " . ATOMIK_VERSION . " Console\n\n";
  83. if ($_SERVER['argc'] <= 1) {
  84. Atomik::fireEvent('Console::End');
  85. Atomik::end(true);
  86. }
  87. /* get parameters from the command line arguments */
  88. $command = $_SERVER['argv'][1];
  89. $arguments = array_slice($_SERVER['argv'], 2);
  90. /* console starts */
  91. Atomik::fireEvent('Console::Start', array(&$command, &$arguments));
  92. /* checks if a script file exists */
  93. if (($scriptFilename = Atomik::path($command . '.php', self::getScriptDirs())) !== false) {
  94. /* run the script */
  95. require $scriptFilename;
  96. } else {
  97. /* checks if the command is registered */
  98. if (!array_key_exists($command, self::$_commands)) {
  99. echo "The command $command does not exists\n";
  100. Atomik::end(true);
  101. }
  102. /* executes the callback */
  103. call_user_func(self::$_commands[$command], $arguments);
  104. }
  105. /* console ends */
  106. Atomik::fireEvent('Console::End', array($command, $arguments));
  107. } catch (Exception $e) {
  108. self::_displayError($e);
  109. $success = false;
  110. }
  111. echo "\n\nDone\n";
  112. Atomik::end($success);
  113. }
  114. /**
  115. * Display an error message
  116. *
  117. * @param Exception $e
  118. */
  119. public static function onAtomikError($e)
  120. {
  121. self::_displayError($e);
  122. Atomik::end(false);
  123. }
  124. /**
  125. * Display an exception
  126. *
  127. * @param Exception $e
  128. */
  129. private static function _displayError(Exception $e)
  130. {
  131. self::println('AN ERROR OCCURED at line ' . $e->getLine() . ' in ' . $e->getFile() . "\n");
  132. self::println($e->getMessage() . "\n", 1);
  133. self::println($e->getTraceAsString());
  134. }
  135. /**
  136. * Registers a callback to call when a command is
  137. * executed
  138. *
  139. * @param string $command
  140. * @param callback $callback
  141. */
  142. public static function register($command, $callback)
  143. {
  144. self::$_commands[$command] = $callback;
  145. }
  146. /**
  147. * Prints a message
  148. *
  149. * @param string $message
  150. * @param int $indent OPTIONAL Indentation
  151. */
  152. public static function println($message, $indent = 0)
  153. {
  154. echo "\n" . str_repeat("\t", $indent) . $message;
  155. }
  156. /**
  157. * Prints a success message
  158. *
  159. * @param string $message OPTIONAL
  160. * @return bool TRUE
  161. */
  162. public static function success($message = '')
  163. {
  164. echo ' [SUCCESS' . (!empty($message) ? ': ' . $message : '') . ']';
  165. return true;
  166. }
  167. /**
  168. * Prints a fail message
  169. *
  170. * @param string $message OPTIONAL
  171. * @return bool FALSE
  172. */
  173. public static function fail($message = '')
  174. {
  175. echo ' [FAIL' . (!empty($message) ? ': ' . $message : '') . ']';
  176. return false;
  177. }
  178. /**
  179. * Creates a directory
  180. *
  181. * @param string $dir
  182. * @param int $indent OPTIONAL Indentation of the console text
  183. * @param string $message OPTIONAL Message to announce the action
  184. * @return bool
  185. */
  186. public static function mkdir($dir, $indent = 0, $message = 'Creating directory: ')
  187. {
  188. self::println($message . $dir, $indent);
  189. /* checks if the file exists */
  190. if (file_exists($dir)) {
  191. if (!is_dir($dir)) {
  192. /* it exists but it's not a directory */
  193. return self::fail('Already exists and is not a directory');
  194. } else {
  195. /* it exists and it's a directory, no need to continue */
  196. return self::success('Already exists');
  197. }
  198. }
  199. /* creates the directory */
  200. if (!@mkdir($dir)) {
  201. return self::fail();
  202. }
  203. return self::success();
  204. }
  205. /**
  206. * Creates a file
  207. *
  208. * @param string $filename
  209. * @param string $content OPTIONAL File content
  210. * @param int $indent OPTIONAL Indentation of the console text
  211. * @param string $message OPTIONAL Message to announce the action
  212. * @return bool
  213. */
  214. public static function touch($filename, $content = '', $indent = 0, $message = 'Creating file: ')
  215. {
  216. self::println($message . $filename, $indent);
  217. /* writes the file */
  218. if (file_put_contents($filename, $content) === false) {
  219. return self::fail();
  220. }
  221. return self::success();
  222. }
  223. /**
  224. * Init command
  225. * index.php init [--htaccess]
  226. *
  227. * @param array $arguments
  228. */
  229. public static function init($arguments)
  230. {
  231. self::println('Creating directory structure');
  232. /* checks if current directory is writeable */
  233. if (!is_writeable(dirname(__FILE__))) {
  234. return self::fail('Current directory is not writeable');
  235. }
  236. /* creates the actions directory */
  237. foreach (Atomik::path(Atomik::get('atomik/dirs/actions'), true) as $path) {
  238. self::mkdir($path, 1);
  239. }
  240. /* creates the templates directory */
  241. foreach (Atomik::path(Atomik::get('atomik/dirs/views'), true) as $path) {
  242. self::mkdir($path, 1);
  243. }
  244. /* creates the plugins directory */
  245. foreach (Atomik::path(Atomik::get('atomik/dirs/plugins'), true) as $path) {
  246. self::mkdir($path, 1);
  247. }
  248. /* creates the includes directory */
  249. foreach (Atomik::path(Atomik::get('atomik/dirs/includes'), true) as $path) {
  250. self::mkdir($path, 1);
  251. }
  252. /* creates the styles directory */
  253. self::mkdir(dirname(__FILE__) . '/styles', 1);
  254. /* creates the images directory */
  255. self::mkdir(dirname(__FILE__) . '/images', 1);
  256. /* fires an event so other package can do stuff too */
  257. Atomik::fireEvent('Console::Init', array($arguments));
  258. /* creates the .htaccess file */
  259. if (in_array('--htaccess', $arguments)) {
  260. $trigger = Atomik::get('atomik/trigger');
  261. $htaccess = "<IfModule mod_rewrite.c>\n\t"
  262. . "RewriteEngine on\n\t"
  263. . "RewriteRule ^app/plugins/(.+)/assets - [L]\n\t"
  264. . "RewriteRule ^app/ - [L,F]\n\t"
  265. . "RewriteCond %{REQUEST_FILENAME} !-f\n\t"
  266. . "RewriteCond %{REQUEST_FILENAME} !-d\n\t"
  267. . "RewriteRule ^(.*)$ index.php?$trigger=\$1 [L,QSA]\n"
  268. . "</IfModule>";
  269. self::touch(dirname(__FILE__) . '/.htaccess', $htaccess);
  270. }
  271. /* generate the default action scripts */
  272. self::generate(array(Atomik::get('atomik/default_action')));
  273. }
  274. /**
  275. * Generate command.
  276. * index.php generate action_name [action_name [action_name [...]]]
  277. *
  278. * @param array $arguments
  279. */
  280. public static function generate($arguments)
  281. {
  282. foreach ($arguments as $action) {
  283. self::println('Generating ' . $action);
  284. $filename = ltrim($action, '/') . '.php';
  285. /* creates the action file */
  286. self::touch(Atomik::path(Atomik::get('atomik/dirs/actions')) . $filename,
  287. "<?php\n\n\t/* Logic goes here */\n", 1);
  288. /* creates the template file */
  289. self::touch(Atomik::path(Atomik::get('atomik/dirs/views')) . $filename, '', 1);
  290. /* fires an event to allow packages to extend the generate command */
  291. Atomik::fireEvent('Console::Generate', array($action));
  292. }
  293. }
  294. }