1: <?php
2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21:
22:
23: 24: 25: 26: 27: 28:
29: class ApiShell extends Shell {
30:
31: 32: 33: 34: 35: 36:
37: var $paths = array();
38:
39: 40: 41: 42: 43:
44: function initialize() {
45: $this->paths = array_merge($this->paths, array(
46: 'behavior' => LIBS . 'model' . DS . 'behaviors' . DS,
47: 'cache' => LIBS . 'cache' . DS,
48: 'controller' => LIBS . 'controller' . DS,
49: 'component' => LIBS . 'controller' . DS . 'components' . DS,
50: 'helper' => LIBS . 'view' . DS . 'helpers' . DS,
51: 'model' => LIBS . 'model' . DS,
52: 'view' => LIBS . 'view' . DS,
53: 'core' => LIBS
54: ));
55: }
56:
57: 58: 59: 60: 61:
62: function main() {
63: if (empty($this->args)) {
64: return $this->help();
65: }
66:
67: $type = strtolower($this->args[0]);
68:
69: if (isset($this->paths[$type])) {
70: $path = $this->paths[$type];
71: } else {
72: $path = $this->paths['core'];
73: }
74:
75: if (count($this->args) == 1) {
76: $file = $type;
77: $class = Inflector::camelize($type);
78: } elseif (count($this->args) > 1) {
79: $file = Inflector::underscore($this->args[1]);
80: $class = Inflector::camelize($file);
81: }
82:
83: $objects = App::objects('class', $path);
84: if (in_array($class, $objects)) {
85: if (in_array($type, array('behavior', 'component', 'helper')) && $type !== $file) {
86: if (!preg_match('/' . Inflector::camelize($type) . '$/', $class)) {
87: $class .= Inflector::camelize($type);
88: }
89: }
90:
91: } else {
92: $this->err(sprintf(__("%s not found", true), $class));
93: $this->_stop();
94: }
95:
96: $parsed = $this->__parseClass($path . $file .'.php');
97:
98: if (!empty($parsed)) {
99: if (isset($this->params['m'])) {
100: if (!isset($parsed[$this->params['m']])) {
101: $this->err(sprintf(__("%s::%s() could not be found", true), $class, $this->params['m']));
102: $this->_stop();
103: }
104: $method = $parsed[$this->params['m']];
105: $this->out($class .'::'.$method['method'] . $method['parameters']);
106: $this->hr();
107: $this->out($method['comment'], true);
108: } else {
109: $this->out(ucwords($class));
110: $this->hr();
111: $i = 0;
112: foreach ($parsed as $method) {
113: $list[] = ++$i . ". " . $method['method'] . $method['parameters'];
114: }
115: $this->out($list);
116:
117: $methods = array_keys($parsed);
118: while ($number = strtolower($this->in(__('Select a number to see the more information about a specific method. q to quit. l to list.', true), null, 'q'))) {
119: if ($number === 'q') {
120: $this->out(__('Done', true));
121: $this->_stop();
122: }
123:
124: if ($number === 'l') {
125: $this->out($list);
126: }
127:
128: if (isset($methods[--$number])) {
129: $method = $parsed[$methods[$number]];
130: $this->hr();
131: $this->out($class .'::'.$method['method'] . $method['parameters']);
132: $this->hr();
133: $this->out($method['comment'], true);
134: }
135: }
136: }
137: }
138: }
139:
140: 141: 142: 143: 144:
145: function help() {
146: $head = "Usage: cake api [<type>] <className> [-m <method>]\n";
147: $head .= "-----------------------------------------------\n";
148: $head .= "Parameters:\n\n";
149:
150: $commands = array(
151: 'path' => "\t<type>\n" .
152: "\t\tEither a full path or type of class (model, behavior, controller, component, view, helper).\n".
153: "\t\tAvailable values:\n\n".
154: "\t\tbehavior\tLook for class in CakePHP behavior path\n".
155: "\t\tcache\tLook for class in CakePHP cache path\n".
156: "\t\tcontroller\tLook for class in CakePHP controller path\n".
157: "\t\tcomponent\tLook for class in CakePHP component path\n".
158: "\t\thelper\tLook for class in CakePHP helper path\n".
159: "\t\tmodel\tLook for class in CakePHP model path\n".
160: "\t\tview\tLook for class in CakePHP view path\n",
161: 'className' => "\t<className>\n" .
162: "\t\tA CakePHP core class name (e.g: Component, HtmlHelper).\n"
163: );
164:
165: $this->out($head);
166: if (!isset($this->args[1])) {
167: foreach ($commands as $cmd) {
168: $this->out("{$cmd}\n\n");
169: }
170: } elseif (isset($commands[strtolower($this->args[1])])) {
171: $this->out($commands[strtolower($this->args[1])] . "\n\n");
172: } else {
173: $this->out("Command '" . $this->args[1] . "' not found");
174: }
175: }
176:
177: 178: 179: 180: 181: 182: 183: 184: 185:
186: function __parseClass($path) {
187: $parsed = array();
188:
189: $File = new File($path);
190: if (!$File->exists()) {
191: $this->err(sprintf(__("%s could not be found", true), $File->name));
192: $this->_stop();
193: }
194:
195: $contents = $File->read();
196:
197: if (preg_match_all('%(/\\*\\*[\\s\\S]*?\\*/)(\\s+function\\s+\\w+)(\\(.*\\))%', $contents, $result, PREG_PATTERN_ORDER)) {
198: foreach ($result[2] as $key => $method) {
199: $method = str_replace('function ', '', trim($method));
200:
201: if (strpos($method, '__') === false && $method[0] != '_') {
202: $parsed[$method] = array(
203: 'comment' => str_replace(array('/*', '*/', '*'), '', trim($result[1][$key])),
204: 'method' => $method,
205: 'parameters' => trim($result[3][$key])
206: );
207: }
208: }
209: }
210: ksort($parsed);
211: return $parsed;
212: }
213: }
214: