ApiShell::main()   F
last analyzed

Complexity

Conditions 17
Paths 361

Size

Total Lines 76
Code Lines 52

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 17
eloc 52
c 0
b 0
f 0
nc 361
nop 0
dl 0
loc 76
rs 3.9636

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
/**
3
 * API shell to get CakePHP core method signatures.
4
 *
5
 * Implementation of a Cake Shell to show CakePHP core method signatures.
6
 *
7
 * CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
8
 * Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
9
 *
10
 * Licensed under The MIT License
11
 * For full copyright and license information, please see the LICENSE.txt
12
 * Redistributions of files must retain the above copyright notice.
13
 *
14
 * @copyright     Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
15
 * @link          http://cakephp.org CakePHP(tm) Project
16
 * @since         CakePHP(tm) v 1.2.0.5012
17
 * @license       http://www.opensource.org/licenses/mit-license.php MIT License
18
 */
19
20
App::uses('AppShell', 'Console/Command');
21
App::uses('File', 'Utility');
22
23
/**
24
 * API shell to show method signatures of CakePHP core classes.
25
 *
26
 * Implementation of a Cake Shell to show CakePHP core method signatures.
27
 *
28
 * @package       Cake.Console.Command
29
 */
30
class ApiShell extends AppShell {
31
32
/**
33
 * Map between short name for paths and real paths.
34
 *
35
 * @var array
36
 */
37
	public $paths = array();
38
39
/**
40
 * Override initialize of the Shell
41
 *
42
 * @return void
43
 */
44
	public function initialize() {
45
		$this->paths = array_merge($this->paths, array(
46
			'behavior' => CAKE . 'Model' . DS . 'Behavior' . DS,
47
			'cache' => CAKE . 'Cache' . DS,
48
			'controller' => CAKE . 'Controller' . DS,
49
			'component' => CAKE . 'Controller' . DS . 'Component' . DS,
50
			'helper' => CAKE . 'View' . DS . 'Helper' . DS,
51
			'model' => CAKE . 'Model' . DS,
52
			'view' => CAKE . 'View' . DS,
53
			'core' => CAKE
54
		));
55
	}
56
57
/**
58
 * Override main() to handle action
59
 *
60
 * @return void
61
 */
62
	public function main() {
63
		if (empty($this->args)) {
64
			return $this->out($this->OptionParser->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
		$count = count($this->args);
76
		if ($count > 1) {
77
			$file = Inflector::underscore($this->args[1]);
78
			$class = Inflector::camelize($this->args[1]);
79
		} elseif ($count) {
80
			$file = $type;
81
			$class = Inflector::camelize($type);
82
		}
83
		$objects = App::objects('class', $path);
84
		if (in_array($class, $objects)) {
85
			if (in_array($type, array('behavior', 'component', 'helper')) && $type !== $file) {
0 ignored issues
show
Bug introduced by
The variable $file does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
86
				if (!preg_match('/' . Inflector::camelize($type) . '$/', $class)) {
87
					$class .= Inflector::camelize($type);
0 ignored issues
show
Bug introduced by
The variable $class does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
88
				}
89
			}
90
91
		} else {
92
			$this->error(__d('cake_console', '%s not found', $class));
93
		}
94
95
		$parsed = $this->_parseClass($path . $class . '.php', $class);
96
97
		if (!empty($parsed)) {
98
			if (isset($this->params['method'])) {
99
				if (!isset($parsed[$this->params['method']])) {
100
					$this->err(__d('cake_console', '%s::%s() could not be found', $class, $this->params['method']));
101
					return $this->_stop();
102
				}
103
				$method = $parsed[$this->params['method']];
104
				$this->out($class . '::' . $method['method'] . $method['parameters']);
105
				$this->hr();
106
				$this->out($method['comment'], true);
107
			} else {
108
				$this->out(ucwords($class));
109
				$this->hr();
110
				$i = 0;
111
				foreach ($parsed as $method) {
112
					$list[] = ++$i . ". " . $method['method'] . $method['parameters'];
0 ignored issues
show
Coding Style Comprehensibility introduced by
$list was never initialized. Although not strictly required by PHP, it is generally a good practice to add $list = array(); before regardless.

Adding an explicit array definition is generally preferable to implicit array definition as it guarantees a stable state of the code.

Let’s take a look at an example:

foreach ($collection as $item) {
    $myArray['foo'] = $item->getFoo();

    if ($item->hasBar()) {
        $myArray['bar'] = $item->getBar();
    }

    // do something with $myArray
}

As you can see in this example, the array $myArray is initialized the first time when the foreach loop is entered. You can also see that the value of the bar key is only written conditionally; thus, its value might result from a previous iteration.

This might or might not be intended. To make your intention clear, your code more readible and to avoid accidental bugs, we recommend to add an explicit initialization $myArray = array() either outside or inside the foreach loop.

Loading history...
113
				}
114
				$this->out($list);
0 ignored issues
show
Bug introduced by
The variable $list does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
115
116
				$methods = array_keys($parsed);
117
				while ($number = strtolower($this->in(__d('cake_console', 'Select a number to see the more information about a specific method. q to quit. l to list.'), null, 'q'))) {
118
					if ($number === 'q') {
119
						$this->out(__d('cake_console', 'Done'));
120
						return $this->_stop();
121
					}
122
123
					if ($number === 'l') {
124
						$this->out($list);
125
					}
126
127
					if (isset($methods[--$number])) {
128
						$method = $parsed[$methods[$number]];
129
						$this->hr();
130
						$this->out($class . '::' . $method['method'] . $method['parameters']);
131
						$this->hr();
132
						$this->out($method['comment'], true);
133
					}
134
				}
135
			}
136
		}
137
	}
138
139
/**
140
 * Get and configure the optionparser.
141
 *
142
 * @return ConsoleOptionParser
143
 */
144
	public function getOptionParser() {
145
		$parser = parent::getOptionParser();
146
		$parser->addArgument('type', array(
147
			'help' => __d('cake_console', 'Either a full path or type of class (model, behavior, controller, component, view, helper)')
148
		))->addArgument('className', array(
149
			'help' => __d('cake_console', 'A CakePHP core class name (e.g: Component, HtmlHelper).')
150
		))->addOption('method', array(
151
			'short' => 'm',
152
			'help' => __d('cake_console', 'The specific method you want help on.')
153
		))->description(__d('cake_console', 'Lookup doc block comments for classes in CakePHP.'));
154
		return $parser;
155
	}
156
157
/**
158
 * Show help for this shell.
159
 *
160
 * @return void
161
 */
162
	public function help() {
163
		$head = "Usage: cake api [<type>] <className> [-m <method>]\n";
164
		$head .= "-----------------------------------------------\n";
165
		$head .= "Parameters:\n\n";
166
167
		$commands = array(
168
			'path' => "\t<type>\n" .
169
				"\t\tEither a full path or type of class (model, behavior, controller, component, view, helper).\n" .
170
				"\t\tAvailable values:\n\n" .
171
				"\t\tbehavior\tLook for class in CakePHP behavior path\n" .
172
				"\t\tcache\tLook for class in CakePHP cache path\n" .
173
				"\t\tcontroller\tLook for class in CakePHP controller path\n" .
174
				"\t\tcomponent\tLook for class in CakePHP component path\n" .
175
				"\t\thelper\tLook for class in CakePHP helper path\n" .
176
				"\t\tmodel\tLook for class in CakePHP model path\n" .
177
				"\t\tview\tLook for class in CakePHP view path\n",
178
			'className' => "\t<className>\n" .
179
				"\t\tA CakePHP core class name (e.g: Component, HtmlHelper).\n"
180
		);
181
182
		$this->out($head);
183
		if (!isset($this->args[1])) {
184
			foreach ($commands as $cmd) {
185
				$this->out("{$cmd}\n\n");
186
			}
187
		} elseif (isset($commands[strtolower($this->args[1])])) {
188
			$this->out($commands[strtolower($this->args[1])] . "\n\n");
189
		} else {
190
			$this->out(__d('cake_console', 'Command %s not found', $this->args[1]));
191
		}
192
	}
193
194
/**
195
 * Parse a given class (located on given file) and get public methods and their
196
 * signatures.
197
 *
198
 * @param string $path File path
199
 * @param string $class Class name
200
 * @return array Methods and signatures indexed by method name
201
 */
202
	protected function _parseClass($path, $class) {
203
		$parsed = array();
204
205
		if (!class_exists($class)) {
206
			if (!include_once $path) {
207
				$this->err(__d('cake_console', '%s could not be found', $path));
208
			}
209
		}
210
211
		$reflection = new ReflectionClass($class);
212
213
		foreach ($reflection->getMethods() as $method) {
214
			if (!$method->isPublic() || strpos($method->getName(), '_') === 0) {
215
				continue;
216
			}
217
			if ($method->getDeclaringClass()->getName() != $class) {
218
				continue;
219
			}
220
			$args = array();
221
			foreach ($method->getParameters() as $param) {
222
				$paramString = '$' . $param->getName();
223
				if ($param->isDefaultValueAvailable()) {
224
					$paramString .= ' = ' . str_replace("\n", '', var_export($param->getDefaultValue(), true));
225
				}
226
				$args[] = $paramString;
227
			}
228
			$parsed[$method->getName()] = array(
229
				'comment' => str_replace(array('/*', '*/', '*'), '', $method->getDocComment()),
230
				'method' => $method->getName(),
231
				'parameters' => '(' . implode(', ', $args) . ')'
232
			);
233
		}
234
		ksort($parsed);
235
		return $parsed;
236
	}
237
238
}
239