Completed
Push — master ( 7dba56...6875ae )
by Oscar
10:21
created

CallableTrait   A

Complexity

Total Complexity 13

Size/Duplication

Total Lines 86
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 3

Importance

Changes 4
Bugs 2 Features 0
Metric Value
wmc 13
c 4
b 2
f 0
lcom 1
cbo 3
dl 0
loc 86
rs 10

2 Methods

Rating   Name   Duplication   Size   Complexity  
C getCallable() 0 31 7
B executeCallable() 0 30 6
1
<?php
2
3
namespace Psr7Middlewares\Utils;
4
5
use RuntimeException;
6
use Psr\Http\Message\RequestInterface;
7
use Psr\Http\Message\ResponseInterface;
8
9
/**
10
 * Utilities used by middlewares with callables.
11
 */
12
trait CallableTrait
13
{
14
    use ArgumentsTrait;
15
16
    /**
17
     * Execute the callable.
18
     *
19
     * @param mixed             $target
20
     * @param RequestInterface  $request
21
     * @param ResponseInterface $response
22
     *
23
     * @return ResponseInterface
24
     */
25
    private function executeCallable($target, RequestInterface $request, ResponseInterface $response)
26
    {
27
        try {
28
            ob_start();
29
30
            $arguments = array_merge([$request, $response], $this->arguments);
31
            $target = self::getCallable($target, $arguments);
32
            $return = call_user_func_array($target, $arguments);
33
34
            if ($return instanceof ResponseInterface) {
35
                $response = $return;
36
                $return = '';
37
            }
38
39
            $return = ob_get_contents().$return;
40
            $body = $response->getBody();
41
42
            if ($return !== '' && $body->isWritable()) {
43
                $body->write($return);
44
            }
45
46
            return $response;
47
        } catch (\Exception $exception) {
48
            throw $exception;
49
        } finally {
50
            if (ob_get_level() > 0) {
51
                ob_end_clean();
52
            }
53
        }
54
    }
55
56
    /**
57
     * Resolves the target of the route and returns a callable.
58
     *
59
     * @param mixed $target
60
     * @param array $construct_args
61
     *
62
     * @throws RuntimeException If the target is not callable
63
     *
64
     * @return callable
65
     */
66
    private static function getCallable($target, array $construct_args)
67
    {
68
        if (is_string($target)) {
69
            //is a class "classname::method"
70
            if (strpos($target, '::') === false) {
71
                $class = $target;
72
                $method = '__invoke';
73
            } else {
74
                list($class, $method) = explode('::', $target, 2);
75
            }
76
77
            if (!class_exists($class)) {
78
                throw new RuntimeException("The class {$class} does not exists");
79
            }
80
81
            $fn = new \ReflectionMethod($class, $method);
82
83
            if (!$fn->isStatic()) {
84
                $class = new \ReflectionClass($class);
85
                $instance = $class->hasMethod('__construct') ? $class->newInstanceArgs($construct_args) : $class->newInstance();
86
                $target = [$instance, $method];
87
            }
88
        }
89
90
        //if it's callable as is
91
        if (is_callable($target)) {
92
            return $target;
93
        }
94
95
        throw new RuntimeException('The route target is not callable');
96
    }
97
}
98