AgaviException::buildParamList()   C
last analyzed

Complexity

Conditions 16
Paths 71

Size

Total Lines 55
Code Lines 43

Duplication

Lines 6
Ratio 10.91 %

Importance

Changes 0
Metric Value
cc 16
eloc 43
nc 71
nop 3
dl 6
loc 55
rs 6.6992
c 0
b 0
f 0

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
// +---------------------------------------------------------------------------+
4
// | This file is part of the Agavi package.                                   |
5
// | Copyright (c) 2005-2011 the Agavi Project.                                |
6
// | Based on the Mojavi3 MVC Framework, Copyright (c) 2003-2005 Sean Kerr.    |
7
// |                                                                           |
8
// | For the full copyright and license information, please view the LICENSE   |
9
// | file that was distributed with this source code. You can also view the    |
10
// | LICENSE file online at http://www.agavi.org/LICENSE.txt                   |
11
// |   vi: set noexpandtab:                                                    |
12
// |   Local Variables:                                                        |
13
// |   indent-tabs-mode: t                                                     |
14
// |   End:                                                                    |
15
// +---------------------------------------------------------------------------+
16
17
18
namespace Agavi\Exception;
19
20
use Agavi\Config\Config;
21
use Agavi\Core\Context;
22
use Agavi\Dispatcher\ExecutionContainer;
23
24
/**
25
 * AgaviException is the base class for all Agavi related exceptions and
26
 * provides an additional method for printing up a detailed view of an
27
 * exception.
28
 *
29
 * @package    agavi
30
 * @subpackage exception
31
 *
32
 * @author     David Zülke <[email protected]>
33
 * @author     Sean Kerr <[email protected]>
34
 * @author     Bob Zoller <[email protected]>
35
 * @copyright  Authors
36
 * @copyright  The Agavi Project
37
 *
38
 * @since      0.9.0
39
 *
40
 * @version    $Id$
41
 */
42
class AgaviException extends \Exception
43
{
44
    /**
45
     * Print the stack trace for this exception.
46
     *
47
     * @param      \Exception         $e         The original exception.
48
     * @param      Context            $context   The context instance.
49
     * @param      ExecutionContainer $container The execution container instance
50
     *
51
     * @author     David Zülke <[email protected]>
52
     * @since      0.9.0
53
     *
54
     * @deprecated Superseded by AgaviException::render()
55
     */
56
    public static function printStackTrace(\Exception $e, Context $context = null, ExecutionContainer $container = null)
57
    {
58
        return self::render($e, $context, $container);
59
    }
60
    
61
    /**
62
     * Returns a fixed stack trace in case the original one from the exception
63
     * does not contain the origin as the first entry in the trace array, which
64
     * appears to happen from time to time or with certain PHP/XDebug versions.
65
     *
66
     * @param      \Exception $e    The exception to pull the trace from.
67
     * @param      \Exception $next Optionally, the next exception to display (pulled
68
     *                             from Exception::getPrevious() and displayed in
69
     *                             reverse order), which will then result in identical
70
     *                             parts of the stack trace not being returned.
71
     *
72
     * @return     array The trace containing the exception origin as first item.
73
     *
74
     * @author     David Zülke <[email protected]>
75
     * @since      1.0.3
76
     */
77
    public static function getFixedTrace(\Exception $e, \Exception $next = null)
78
    {
79
        // fix stack trace in case it doesn't contain the exception origin as the first entry
80
        $fixedTrace = $e->getTrace();
81
        
82
        if (!isset($fixedTrace[0]['file']) || !($fixedTrace[0]['file'] == $e->getFile() && $fixedTrace[0]['line'] == $e->getLine())) {
83
            $fixedTrace = array_merge(array(array('file' => $e->getFile(), 'line' => $e->getLine())), $fixedTrace);
84
        }
85
        
86
        if ($next) {
87
            $nextTrace = self::getFixedTrace($next);
88
            foreach ($fixedTrace as $i => $fixedTraceItem) {
89
                if ($fixedTraceItem == $nextTrace[1]) {
90
                    $fixedTrace = array_slice($fixedTrace, 0, $i);
91
                    break;
92
                }
93
            }
94
        }
95
        
96
        return $fixedTrace;
97
    }
98
    
99
    /**
100
     * Build a list of parameters passed to a method. Example:
101
     * array([object AgaviFilter], 'baz' => array(1, 2), 'log' => [resource stream])
102
     *
103
     * @param      array $params An (associative) array of variables.
104
     * @param      bool  $html   Whether or not to style and encode for HTML output.
105
     * @param      int   $level
106
     *
107
     * @return     string A string, possibly formatted using HTML "em" tags.
108
     *
109
     * @author     David Zülke <[email protected]>
110
     * @since      0.11.0
111
     */
112
    public static function buildParamList($params, $html = true, $level = 1)
113
    {
114
        $retval = array();
115
        foreach ($params as $key => $param) {
116
            if (is_string($key)) {
117 View Code Duplication
                if (preg_match('/^(.{5}).{2,}(.{5})$/us', $key, $matches)) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
118
                    $key = $matches[1] . '…' . $matches[2];
119
                }
120
                $key = var_export($key, true) . ' => ';
121
                if ($html) {
122
                    $key = htmlspecialchars($key);
123
                }
124
            } else {
125
                $key = '';
126
            }
127
            switch (gettype($param)) {
128
                case 'array':
129
                    $retval[] = $key . 'array(' . ($level < 2 ? self::buildParamList($param, $html, ++$level) : (count($param) ? '…' : '')) . ')';
130
                    break;
131
                case 'object':
132
                    if ($html) {
133
                        $retval[] = $key . '[object <em>' . get_class($param) . '</em>]';
134
                    } else {
135
                        $retval[] = $key . '[object ' . get_class($param) . ']';
136
                    }
137
                    break;
138
                case 'resource':
139
                    if ($html) {
140
                        $retval[] = $key . '[resource <em>' . htmlspecialchars(get_resource_type($param)) . '</em>]';
141
                    } else {
142
                        $retval[] = $key . '[resource ' . get_resource_type($param) . ']';
143
                    }
144
                    break;
145
                case 'string':
146
                    $val = $param;
147 View Code Duplication
                    if (preg_match('/^(.{20}).{3,}(.{20})$/us', $val, $matches)) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
148
                        $val = $matches[1] . ' … ' . $matches[2];
149
                    }
150
                    $val = var_export($val, true);
151
                    if ($html) {
152
                        $retval[] = $key . htmlspecialchars($val);
153
                    } else {
154
                        $retval[] = $key . $val;
155
                    }
156
                    break;
157
                default:
158
                    if ($html) {
159
                        $retval[] = $key . htmlspecialchars(var_export($param, true));
160
                    } else {
161
                        $retval[] = $key . var_export($param, true);
162
                    }
163
            }
164
        }
165
        return implode(', ', $retval);
166
    }
167
    
168
    /**
169
     * Perform PHP syntax highlighting on the given file.
170
     *
171
     * @param      string $filepath The path of the file to highlight.
172
     *
173
     * @return     array An 0-indexed array of HTML-highlighted code lines.
174
     *
175
     * @author     David Zülke <[email protected]>
176
     * @since      1.0.3
177
     */
178
    public static function highlightFile($filepath)
179
    {
180
        return self::highlightString(file_get_contents($filepath));
181
    }
182
    
183
    /**
184
     * Perform PHP syntax highlighting on the given code string.
185
     *
186
     * @param      string $code The PHP code to highlight.
187
     *
188
     * @return     array An 0-indexed array of HTML-highlighted code lines.
189
     *
190
     * @author     David Zülke <[email protected]>
191
     * @since      1.0.3
192
     */
193
    public static function highlightString($code)
194
    {
195
        $code = highlight_string(str_replace('	', '  ', $code), true);
196
        // time to cleanup this highlighted string
197
        // first, drop all newlines (we'll explode by "<br />")
198
        $code = str_replace(array("\r\n", "\n", "\r"), array('', '', ''), $code);
199
        // second, remove start and end wrappers and replace &nbsp; with numeric entity
200
        $code = str_replace(array(sprintf('<code><span style="color: %s">', ini_get('highlight.html')), '</span></code>', '&nbsp;'), array('', '', '&#160;'), $code);
201
        // make an array of lines
202
        $code = explode('<br />', $code);
203
        // iterate and cleanup each line
204
        $remember = null;
205
        foreach ($code as &$line) {
206
            // we need at least an nbsp for empty lines
207
            if ($line == '') {
208
                $line = '&#160;';
209
            }
210
            
211
            // drop leading </span>
212
            if (strpos($line, '</span>') === 0) {
213
                $line = substr($line, 7);
214
                // no style to carry over from previous line(s)
215
                $remember = null;
216
            }
217
            
218
            // prepend style from previous line if we have one
219
            if ($remember) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $remember of type string|null is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
220
                $line = sprintf('<span style="color: %s">%s', $remember, $line);
221
            }
222
            
223
            $openingSpanPos = strpos($line, '<span');
224
            $openingSpanRPos = strrpos($line, '<span');
225
            $closingSpanPos = strpos($line, '</span>');
226
            $closingSpanRPos = strrpos($line, '</span>');
0 ignored issues
show
Unused Code introduced by
$closingSpanRPos is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
227
            
228
            $balanced = (($openingSpanCount = preg_match_all('#<span#', $line, $matches)) == ($closingSpanCount = preg_match_all('#</span>#', $line, $matches)));
229
            if ($balanced && $openingSpanPos !== false && $openingSpanPos < $closingSpanPos) {
230
                // already balanced, no further cleanup necessary
231
                $remember = null;
232
                continue;
233
            }
234
            
235
            if (substr($line, -7) == '</span>') {
236
                // discard previous style if style terminates in this line
237
                $remember = null;
238
            } else {
239
                // otherwise, remember last style from this line if there is one
240
                if ($openingSpanRPos !== false) {
241
                    // must remember previous color; 20 is the length of '<span style="color: '
242
                    // we're using strpos since someone could set the colors to "#333" or "red" through php.ini, so we don't know the length
243
                    $remember = substr($line, $openingSpanRPos + 20, strpos($line, '"', $openingSpanRPos + 20) - ($openingSpanRPos + 20));
244
                }
245
                // append closing tag
246
                $line .= '</span>';
247
                $closingSpanCount++;
248
            }
249
            
250
            // in case things still are not right...
251
            // can happen for instance when the first line of the file is HTML and we drop the first span, since that is a wrapper for everything
252
            if ($openingSpanCount < $closingSpanCount) {
253
                $line = sprintf('%1$s%2$s', str_repeat('<span color="%3s">', $closingSpanCount - $openingSpanCount), $line, ini_get('highlight.html'));
254
            }
255
            if ($closingSpanCount < $openingSpanCount) {
256
                $line = sprintf('%s%s', $line, str_repeat('</span>', $openingSpanCount - $closingSpanCount), $line);
257
            }
258
        }
259
        
260
        return $code;
261
    }
262
    
263
    /**
264
     * Pretty-print this exception using a template.
265
     *
266
     * @param      \Exception         $exception The original exception.
0 ignored issues
show
Bug introduced by
There is no parameter named $exception. Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
267
     * @param      Context            $context   The context instance.
268
     * @param      ExecutionContainer $container The response instance.
269
     *
270
     * @author     David Zülke <[email protected]>
271
     * @since      1.0.0
272
     */
273
    public static function render(\Exception $e, Context $context = null, ExecutionContainer $container = null)
274
    {
275
        // exit code is 70, EX_SOFTWARE, according to /usr/include/sysexits.h: http://cvs.opensolaris.org/source/xref/on/usr/src/head/sysexits.h
276
        // nice touch: an exception template can change this value :)
277
        $exitCode = 70;
278
        
279
        $exceptions = array();
280
        // reverse order of exceptions for linking
281
        $ce = $e;
282
        while ($ce) {
283
            array_unshift($exceptions, $ce);
284
            $ce = $ce->getPrevious();
285
        }
286
        
287
        // discard any previous output waiting in the buffer
288
        while (@ob_end_clean()) {
0 ignored issues
show
Unused Code introduced by
This while loop is empty and can be removed.

This check looks for while loops that have no statements or where all statements have been commented out. This may be the result of changes for debugging or the code may simply be obsolete.

Consider removing the loop.

Loading history...
289
        }
290
        
291
        if ($container !== null && $container->getOutputType() !== null && $container->getOutputType()->getExceptionTemplate() !== null) {
292
            // an exception template was defined for the container's output type
293
            include($container->getOutputType()->getExceptionTemplate());
294
            exit($exitCode);
0 ignored issues
show
Coding Style Compatibility introduced by
The method render() contains an exit expression.

An exit expression should only be used in rare cases. For example, if you write a short command line script.

In most cases however, using an exit expression makes the code untestable and often causes incompatibilities with other libraries. Thus, unless you are absolutely sure it is required here, we recommend to refactor your code to avoid its usage.

Loading history...
295
        }
296
        
297
        if ($context !== null && $context->getDispatcher() !== null) {
298
            try {
299
                // check if an exception template was defined for the default output type
300
                if ($context->getDispatcher()->getOutputType()->getExceptionTemplate() !== null) {
301
                    include($context->getDispatcher()->getOutputType()->getExceptionTemplate());
302
                    exit($exitCode);
0 ignored issues
show
Coding Style Compatibility introduced by
The method render() contains an exit expression.

An exit expression should only be used in rare cases. For example, if you write a short command line script.

In most cases however, using an exit expression makes the code untestable and often causes incompatibilities with other libraries. Thus, unless you are absolutely sure it is required here, we recommend to refactor your code to avoid its usage.

Loading history...
303
                }
304
            } catch (\Exception $e2) {
305
                unset($e2);
306
            }
307
        }
308
        
309
        if ($context !== null && Config::get('exception.templates.' . $context->getName()) !== null) {
310
            // a template was set for this context
311
            include(Config::get('exception.templates.' . $context->getName()));
312
            exit($exitCode);
0 ignored issues
show
Coding Style Compatibility introduced by
The method render() contains an exit expression.

An exit expression should only be used in rare cases. For example, if you write a short command line script.

In most cases however, using an exit expression makes the code untestable and often causes incompatibilities with other libraries. Thus, unless you are absolutely sure it is required here, we recommend to refactor your code to avoid its usage.

Loading history...
313
        }
314
        
315
        // include default exception template
316
        include(Config::get('exception.default_template'));
317
        
318
        // bail out
319
        exit($exitCode);
0 ignored issues
show
Coding Style Compatibility introduced by
The method render() contains an exit expression.

An exit expression should only be used in rare cases. For example, if you write a short command line script.

In most cases however, using an exit expression makes the code untestable and often causes incompatibilities with other libraries. Thus, unless you are absolutely sure it is required here, we recommend to refactor your code to avoid its usage.

Loading history...
320
    }
321
}
322