Completed
Push — master ( a3ba2f...57d762 )
by Erin
02:00
created

AssertionException::traceLeoCall()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 10
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 3
eloc 5
c 0
b 0
f 0
nc 3
nop 1
dl 0
loc 10
rs 9.4285
1
<?php
2
3
namespace Peridot\Leo\Responder\Exception;
4
5
use Exception;
6
use ReflectionClass;
7
8
/**
9
 * Thrown by ExceptionResponder when an assertion fails.
10
 *
11
 * @package Peridot\Leo\Responder\Exception
12
 */
13
final class AssertionException extends Exception
14
{
15
    /**
16
     * Trim the supplied exception's stack trace to only include relevant
17
     * information.
18
     *
19
     * Also replaces the file path and line number.
20
     *
21
     * @param Exception $exception The exception.
22
     */
23
    public static function trim(Exception $exception)
24
    {
25
        $reflector = new ReflectionClass('Exception');
26
        $traceProperty = $reflector->getProperty('trace');
27
        $traceProperty->setAccessible(true);
28
        $call = static::traceLeoCall($traceProperty->getValue($exception));
29
30
        if ($call) {
31
            $trace = array($call);
32
            list($file, $line) = self::traceCallPosition($call);
33
        } else {
34
            $trace = array();
35
            $file = null;
36
            $line = null;
37
        }
38
39
        $traceProperty->setValue($exception, $trace);
40
        self::updateExceptionPosition($reflector, $exception, $file, $line);
41
    }
42
43
    /**
44
     * Find the Leo entry point call in a stack trace.
45
     *
46
     * @param array $trace The stack trace.
47
     *
48
     * @return array|null The call, or null if unable to determine the entry point.
49
     */
50
    public static function traceLeoCall(array $trace)
51
    {
52
        for ($i = count($trace) - 1; $i >= 0; --$i) {
53
            if (self::isLeoTraceEntry($trace[$i])) {
54
                return $trace[$i];
55
            }
56
        }
57
58
        return null;
59
    }
60
61
    /**
62
     * Construct a new assertion exception.
63
     *
64
     * @param string $message The message.
65
     */
66
    public function __construct($message)
67
    {
68
        parent::__construct($message);
69
70
        static::trim($this);
71
    }
72
73
    private static function isLeoTraceEntry($entry)
74
    {
75
        $prefix = 'Peridot\\Leo\\';
76
77
        if (isset($entry['class'])) {
78
            return 0 === strpos($entry['class'], $prefix);
79
        }
80
81
        return 0 === strpos($entry['function'], $prefix);
82
    }
83
84
    private static function traceCallPosition($call)
85
    {
86
        return array(
87
            isset($call['file']) ? $call['file'] : null,
88
            isset($call['line']) ? $call['line'] : null,
89
        );
90
    }
91
92
    private static function updateExceptionPosition($reflector, $exception, $file, $line)
93
    {
94
        $fileProperty = $reflector->getProperty('file');
95
        $fileProperty->setAccessible(true);
96
        $fileProperty->setValue($exception, $file);
97
98
        $lineProperty = $reflector->getProperty('line');
99
        $lineProperty->setAccessible(true);
100
        $lineProperty->setValue($exception, $line);
101
    }
102
}
103