From 734d52b608a21529a09abcf01f32673888ea5adb Mon Sep 17 00:00:00 2001 From: "mariano.iglesias" Date: Wed, 23 May 2007 21:03:01 +0000 Subject: [PATCH] Adding API Shell to get method signatures from core CakePHP classes git-svn-id: https://svn.cakephp.org/repo/branches/1.2.x.x@5161 3807eeeb-6ff5-0310-8944-8be069107fe0 --- cake/console/libs/api.php | 231 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 231 insertions(+) create mode 100644 cake/console/libs/api.php diff --git a/cake/console/libs/api.php b/cake/console/libs/api.php new file mode 100644 index 000000000..0b548decc --- /dev/null +++ b/cake/console/libs/api.php @@ -0,0 +1,231 @@ + + * Copyright 2005-2007, Cake Software Foundation, Inc. + * 1785 E. Sahara Avenue, Suite 490-204 + * Las Vegas, Nevada 89104 + * + * Licensed under The MIT License + * Redistributions of files must retain the above copyright notice. + * + * @filesource + * @copyright Copyright 2005-2007, Cake Software Foundation, Inc. + * @link http://www.cakefoundation.org/projects/info/cakephp CakePHP(tm) Project + * @package cake + * @subpackage cake.cake.console.libs + * @since CakePHP(tm) v 1.2.0.5012 + * @version $Revision$ + * @modifiedby $LastChangedBy$ + * @lastmodified $Date$ + * @license http://www.opensource.org/licenses/mit-license.php The MIT License + */ + +/** + * API shell to show method signatures of CakePHP core classes. + * + * @package cake + * @subpackage cake.cake.console.libs + */ +class ApiShell extends Shell { +/** + * Map between short name for paths and real paths. + * + * @var array + */ + var $paths = array(); +/** + * Override intialize of the Shell + * + * @access public + */ + function initialize () { + $this->paths = am($this->paths, array( + 'behavior' => LIBS . 'model' . DS . 'behaviors' . DS, + 'cache' => LIBS . 'cache' . DS, + 'controller' => LIBS . 'controller' . DS, + 'component' => LIBS . 'controller' . DS . 'components' . DS, + 'helper' => LIBS . 'view' . DS . 'helpers' . DS, + 'model' => LIBS . 'model' . DS, + 'view' => LIBS . 'view' . DS + )); + } +/** + * Override main() to handle action + * + * @access public + */ + function main() { + if (empty($this->args)) { + return $this->help(); + } + + if (count($this->args) > 1) { + $path = $this->args[0]; + $class = $this->args[1]; + + $this->__loadDependencies($path); + + if (in_array(low($path), array('behavior', 'component', 'helper'))) { + if (!preg_match('/' . Inflector::camelize($path) . '$/', $class)) { + $class .= Inflector::camelize($path); + } + } + + if (isset($this->paths[low($path)])) { + $path = $this->paths[low($path)]; + } + } else { + $class = $this->args[0]; + $path = LIBS; + } + + if (!is_readable($path) || !is_dir($path)) { + $this->err(sprintf(__('Path %s could not be accessed', true), $path)); + return; + } + + $File = null; + + $candidates = array( + Inflector::underscore($class), + substr(Inflector::underscore($class), 0, strpos(Inflector::underscore($class), '_')) + ); + + foreach($candidates as $candidate) { + $File = new File($path . $candidate . '.php'); + + if ($File->exists()) { + if (!class_exists($class)) { + include($File->getFullPath()); + } + + if (class_exists($class)) { + break; + } + } + + $File = null; + } + + if (empty($File)) { + $this->err(sprintf(__('No file for class %s could be found', true), $class)); + return; + } + + $parsed = $this->__parseClass($File, $class); + + if (!empty($parsed)) { + $this->out($class); + $this->hr(); + + foreach($parsed as $method) { + $this->out("\t" . $method['method'] . "(" . $method['parameters'] . ")", true); + } + } + } + +/** + * Show help for this shell. + * + * @access public + */ + function help() { + $head = "Usage: cake api [] \n"; + $head .= "-----------------------------------------------\n"; + $head .= "Parameters:\n\n"; + + $commands = array( + 'path' => "\t\n" . + "\t\tEither a full path or an indicator on where the class is stored.\n". + "\t\tAvailable values:\n\n". + "\t\tbehavior\tLook for class in CakePHP behavior path\n". + "\t\tcache\tLook for class in CakePHP cache path\n". + "\t\tcontroller\tLook for class in CakePHP controller path\n". + "\t\tcomponent\tLook for class in CakePHP component path\n". + "\t\thelper\tLook for class in CakePHP helper path\n". + "\t\tmodel\tLook for class in CakePHP model path\n". + "\t\tview\tLook for class in CakePHP view path\n", + 'className' => "\t\n" . + "\t\tA CakePHP core class name (e.g: Component, HtmlHelper).\n" + ); + + $this->out($head); + if (!isset($this->args[1])) { + foreach ($commands as $cmd) { + $this->out("{$cmd}\n\n"); + } + } elseif (isset($commands[low($this->args[1])])) { + $this->out($commands[low($this->args[1])] . "\n\n"); + } else { + $this->out("Command '" . $this->args[1] . "' not found"); + } + } + +/** + * Parse a given class (located on given file) and get public methods and their + * signatures. + * + * @param object $File File object + * @param string $class Class name + * @return array Methods and signatures indexed by method name + * @access private + */ + function __parseClass(&$File, $class) { + $parsed = array(); + + $methods = am(array(), array_diff(get_class_methods($class), get_class_methods(get_parent_class($class)))); + + $contents = $File->read(); + + foreach($methods as $method) { + if (strpos($method, '__') !== 0 && strpos($method, '_') !== 0) { + $regex = '/\s+function\s+(' . preg_quote($method, '/') . ')\s*\(([^{]*)\)\s*{/is'; + + if (preg_match($regex, $contents, $matches)) { + $parsed[$method] = array( + 'method' => trim($matches[1]), + 'parameters' => trim($matches[2]) + ); + } + } + } + + return $parsed; + } + +/** + * Load dependencies for given element (controller/component/helper) + * + * @param string $element Element to load dependency for + * @access private + */ + function __loadDependencies($element) { + switch(low($element)) { + case 'behavior': + loadModel(null); + loadBehavior(null); + break; + case 'controller': + loadController(null); + break; + case 'component': + loadComponent(null); + break; + case 'helper': + loadHelper(null); + break; + case 'model': + loadModel(null); + break; + } + } +} + +?> \ No newline at end of file