Passed
Push — master ( ff34bb...ae72d7 )
by Mihail
09:20
created

DIException::forUnprocessableFunctionParameter()   A

Complexity

Conditions 2
Paths 1

Size

Total Lines 18
Code Lines 13

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 6

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 13
c 1
b 0
f 0
dl 0
loc 18
ccs 0
cts 0
cp 0
rs 9.8333
cc 2
nc 1
nop 2
crap 6
1
<?php
2
3
/*
4
 * This file is part of the Koded package.
5
 *
6
 * (c) Mihail Binev <[email protected]>
7
 *
8
 * Please view the LICENSE distributed with this source code
9
 * for the full copyright and license information.
10
 *
11
 */
12
13
namespace Koded;
14
15
use Psr\Container\{ContainerExceptionInterface, NotFoundExceptionInterface};
16
17
class DIException extends \LogicException implements ContainerExceptionInterface
18
{
19
    public const
20
        E_CIRCULAR_DEPENDENCY = 7001,
21
        E_NON_PUBLIC_METHOD = 7002,
22
        E_CANNOT_INSTANTIATE = 7003,
23
        E_INVALID_PARAMETER_NAME = 7004,
24
        E_INSTANCE_NOT_FOUND = 7005,
25
        E_MISSING_ARGUMENT = 7006,
26
        E_REFLECTION_ERROR = 7007,
27
        E_UNPROCESSABLE_FUNCTION = 7008;
28
29
    protected array $messages = [
30
        DIException::E_CIRCULAR_DEPENDENCY => 'Circular dependency detected while creating an instance for :class',
31
        DIException::E_NON_PUBLIC_METHOD => 'Failed to create an instance, because the method ":class::s:method" is not public',
32
        DIException::E_CANNOT_INSTANTIATE => 'Cannot instantiate :type :name',
33
        DIException::E_INVALID_PARAMETER_NAME => 'Provide a valid name for the global parameter: ":name"',
34
        DIException::E_INSTANCE_NOT_FOUND => 'The requested instance :id is not found in the container',
35
        DIException::E_MISSING_ARGUMENT => 'Required parameter "$:name" is missing at position :position in :function()',
36
        DIException::E_REFLECTION_ERROR => ':message',
37
        DIException::E_UNPROCESSABLE_FUNCTION => 'Cannot process function :function() for argument #:position ($:name), called in :file on line :line',
38 15
    ];
39
40 15
    public function __construct(int $code, array $arguments = [], \Throwable $previous = null)
41 15
    {
42 15
        parent::__construct(
43 15
            strtr($this->messages[$code] ?? ':message', $arguments + [':message' => $this->message]),
44 15
            $code,
45
            $previous
46 1
        );
47
    }
48 1
49
    public static function forCircularDependency(string $class): static
50
    {
51 1
        return new static(static::E_CIRCULAR_DEPENDENCY, [':class' => $class]);
52
    }
53 1
54
    public static function forNonPublicMethod(string $class, string $method): static
55
    {
56 4
        return new static(static::E_NON_PUBLIC_METHOD, [':class' => $class, ':method' => $method]);
57
    }
58 4
59
    public static function cannotInstantiate(\ReflectionClass $dependency): static
60
    {
61 7
        $type = 'class';
62
        if ($dependency->isInterface()) {
63 7
            $type = 'interface';
64
        } elseif ($dependency->isAbstract()) {
65
            $type = 'abstract class';
66 1
        } elseif ($dependency->isTrait()) {
67
            $type = 'trait';
68 1
        }
69 1
        return new static(static::E_CANNOT_INSTANTIATE, [':name' => $dependency->name, ':type' => $type]);
70 1
    }
71 1
72
    public static function forInvalidParameterName(string $name): static
73
    {
74
        return new static(static::E_INVALID_PARAMETER_NAME, [':name' => $name]);
75
    }
76
77
    public static function forMissingArgument(string $name, \ReflectionParameter $parameter): static
78
    {
79 1
        return new static(static::E_MISSING_ARGUMENT, [
80
            ':name' => $name,
81 1
            ':position' => $parameter->getPosition(),
82
            ':function' => $parameter->getDeclaringClass()->name . '::' . $parameter->getDeclaringFunction()->name,
83
        ]);
84
    }
85
86
    public static function forReflectionError(\ReflectionException $e): static
87
    {
88
        return new static(static::E_REFLECTION_ERROR, [':message' => $e->getMessage()], $e);
89
    }
90
91
    // [EXPERIMENTAL]
92
    public static function forUnprocessableFunctionParameter(\ReflectionParameter $parameter, array $backtrace): static
93
    {
94
        $function = $parameter->getDeclaringFunction()->name;
95
        $trace = \array_filter($backtrace, function(array $trace) use ($function) {
96
            try {
97
                return \ltrim($trace['args'][0], '\\') === $function;
98
            } catch (\Throwable) {
99
                return false;
100
            }
101
        });
102
        $trace = \array_pop($trace);
103
104
        return new self(self::E_UNPROCESSABLE_FUNCTION, [
105
            ':name' => $parameter->name,
106
            ':function' => $function,
107
            ':position' => $parameter->getPosition() + 1,
108
            ':file' => $trace['file'],
109
            ':line' => $trace['line']
110
        ]);
111
    }
112
}
113
114
115
class DIInstanceNotFound extends DIException implements NotFoundExceptionInterface
116
{
117
    public static function for(string $id): NotFoundExceptionInterface
118
    {
119
        return new static(static::E_INSTANCE_NOT_FOUND, [':id' => $id]);
120
    }
121
}
122