Passed
Branch master (ae28f9)
by Alexey
03:06
created

UnresolvableDependencyException::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 1.0156

Importance

Changes 0
Metric Value
dl 0
loc 4
ccs 3
cts 4
cp 0.75
rs 10
c 0
b 0
f 0
cc 1
eloc 2
nc 1
nop 3
crap 1.0156
1
<?php declare(strict_types = 1);
2
3
namespace Venta\Container\Exception;
4
5
use Exception;
6
use ReflectionFunctionAbstract;
7
use ReflectionMethod;
8
use ReflectionParameter;
9
10
/**
11
 * Class ResolveException
12
 *
13
 * @package Venta\Container\Exception
14
 */
15
class UnresolvableDependencyException extends ContainerException
16
{
17
18
    /**
19
     * @inheritDoc
20
     * @param ArgumentResolverException $previous
21
     */
22 1
    public function __construct($entryId, array $referenceChain, ArgumentResolverException $previous)
23
    {
24 1
        parent::__construct($entryId, $referenceChain, $previous);
25 1
    }
26
27
    /**
28
     * @inheritDoc
29
     * @param ArgumentResolverException $argumentResolveException
1 ignored issue
show
Documentation introduced by
Should the type for parameter $argumentResolveException not be null|Exception?

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
30
     */
31 1
    protected function createMessage(Exception $argumentResolveException = null): string
32
    {
33 1
        return sprintf(
34 1
            'Unable to resolve parameter "%s" value for "%s" %s, path: "%s".',
35 1
            $this->formatParameter($argumentResolveException->getParameter()),
1 ignored issue
show
Bug introduced by
It seems like you code against a specific sub-type and not the parent class Exception as the method getParameter() does only exist in the following sub-classes of Exception: Venta\Container\Exceptio...gumentResolverException. Maybe you want to instanceof check for one of these explicitly?

Let’s take a look at an example:

abstract class User
{
    /** @return string */
    abstract public function getPassword();
}

class MyUser extends User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different sub-classes of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the parent class:

    abstract class User
    {
        /** @return string */
        abstract public function getPassword();
    
        /** @return string */
        abstract public function getDisplayName();
    }
    
Loading history...
36 1
            $this->formatFunction($argumentResolveException->getFunction()),
1 ignored issue
show
Bug introduced by
It seems like you code against a specific sub-type and not the parent class Exception as the method getFunction() does only exist in the following sub-classes of Exception: Venta\Container\Exceptio...gumentResolverException. Maybe you want to instanceof check for one of these explicitly?

Let’s take a look at an example:

abstract class User
{
    /** @return string */
    abstract public function getPassword();
}

class MyUser extends User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different sub-classes of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the parent class:

    abstract class User
    {
        /** @return string */
        abstract public function getPassword();
    
        /** @return string */
        abstract public function getDisplayName();
    }
    
Loading history...
37 1
            $argumentResolveException->getFunction() instanceof ReflectionMethod ? 'method' : 'function',
1 ignored issue
show
Bug introduced by
It seems like you code against a specific sub-type and not the parent class Exception as the method getFunction() does only exist in the following sub-classes of Exception: Venta\Container\Exceptio...gumentResolverException. Maybe you want to instanceof check for one of these explicitly?

Let’s take a look at an example:

abstract class User
{
    /** @return string */
    abstract public function getPassword();
}

class MyUser extends User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different sub-classes of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the parent class:

    abstract class User
    {
        /** @return string */
        abstract public function getPassword();
    
        /** @return string */
        abstract public function getDisplayName();
    }
    
Loading history...
38 1
            implode(' -> ', $this->referenceChain)
39
        );
40
    }
41
42
    /**
43
     * Formats function declaration depending on method/function type.
44
     *
45
     * @param ReflectionFunctionAbstract $function
46
     * @return string
47
     */
48 1
    private function formatFunction(ReflectionFunctionAbstract $function)
49
    {
50 1
        return $function instanceof ReflectionMethod ?
51
            $function->getDeclaringClass()->getName() . '::' . $function->getName() :
52 1
            $function->getName();
53
    }
54
55
    /**
56
     * Formats parameter depending on type
57
     *
58
     * @param ReflectionParameter $parameter
59
     * @return string
60
     */
61 1
    private function formatParameter(ReflectionParameter $parameter): string
62
    {
63 1
        return $parameter->hasType() ?
64
            sprintf('%s $%s', $parameter->getType(), $parameter->getName()) :
65 1
            sprintf('$%s', $parameter->getName());
66
    }
67
}