Passed
Push — master ( b9d836...e906dc )
by Kirill
02:56
created

DirectiveBuilder::loadDirective()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 9

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
dl 0
loc 9
ccs 0
cts 7
cp 0
rs 9.9666
c 0
b 0
f 0
cc 1
nc 1
nop 1
crap 2
1
<?php
2
/**
3
 * This file is part of Railt package.
4
 *
5
 * For the full copyright and license information, please view the LICENSE
6
 * file that was distributed with this source code.
7
 */
8
declare(strict_types=1);
9
10
namespace Railt\SDL\Builder\Invocation;
11
12
use Railt\Parser\Ast\RuleInterface;
13
use Railt\Reflection\Contracts\Definition;
14
use Railt\Reflection\Contracts\Invocation\Behaviour\ProvidesDirectives;
15
use Railt\Reflection\Definition\DirectiveDefinition;
16
use Railt\Reflection\Invocation\Behaviour\HasDirectives;
17
use Railt\Reflection\Invocation\DirectiveInvocation;
18
use Railt\Reflection\Type;
19
use Railt\SDL\Exception\SyntaxException;
20
use Railt\SDL\Exception\TypeException;
21
use Railt\SDL\Exception\TypeNotFoundException;
22
23
/**
24
 * Class DirectiveBuilder
25
 * @property ProvidesDirectives|HasDirectives $definition
26
 */
27
class DirectiveBuilder extends TypeInvocationBuilder
28
{
29
    /**
30
     * @return Definition
31
     * @throws SyntaxException
32
     * @throws TypeException
33
     */
34
    public function build(): Definition
35
    {
36
        /** @var DirectiveInvocation $directive */
37
        $directive = $this->bind(new DirectiveInvocation($this->document, $this->getName()));
38
39
        foreach ($this->ast->getChildren() as $argument) {
40
            if ($argument->is('Argument')) {
41
                $this->buildArgument($directive, $argument);
42
            }
43
        }
44
45
        $this->async(function () use ($directive): void {
46
            $this->loadDirective($directive);
47
48
            $this->definition->withDirective($directive);
0 ignored issues
show
Bug introduced by
The method withDirective does only exist in Railt\Reflection\Invocat...Behaviour\HasDirectives, but not in Railt\Reflection\Contrac...iour\ProvidesDirectives.

It seems like the method you are trying to call exists only in some of the possible types.

Let’s take a look at an example:

class A
{
    public function foo() { }
}

class B extends A
{
    public function bar() { }
}

/**
 * @param A|B $x
 */
function someFunction($x)
{
    $x->foo(); // This call is fine as the method exists in A and B.
    $x->bar(); // This method only exists in B and might cause an error.
}

Available Fixes

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
49
        });
50
51
        return $directive;
52
    }
53
54
    private function buildArgument(DirectiveInvocation $directive, RuleInterface $rule): void
0 ignored issues
show
Unused Code introduced by
The parameter $directive is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
55
    {
56
        echo $rule;
57
        die;
58
    }
59
60
    /**
61
     * @param DirectiveInvocation $directive
62
     * @throws TypeException
63
     * @throws TypeNotFoundException
64
     */
65
    private function loadDirective(DirectiveInvocation $directive): void
66
    {
67
        /** @var DirectiveDefinition $definition */
68
        $definition = $this->load($directive->getName(), $directive);
0 ignored issues
show
Bug introduced by
Consider using $directive->name. There is an issue with getName() and APC-enabled PHP versions.
Loading history...
69
70
        $this->checkType($directive, $definition);
71
        $this->loadDefaultArguments($directive, $definition);
72
        $this->checkMissingArguments($directive, $definition);
0 ignored issues
show
Unused Code introduced by
The call to the method Railt\SDL\Builder\Invoca...checkMissingArguments() seems un-needed as the method has no side-effects.

PHP Analyzer performs a side-effects analysis of your code. A side-effect is basically anything that might be visible after the scope of the method is left.

Let’s take a look at an example:

class User
{
    private $email;

    public function getEmail()
    {
        return $this->email;
    }

    public function setEmail($email)
    {
        $this->email = $email;
    }
}

If we look at the getEmail() method, we can see that it has no side-effect. Whether you call this method or not, no future calls to other methods are affected by this. As such code as the following is useless:

$user = new User();
$user->getEmail(); // This line could safely be removed as it has no effect.

On the hand, if we look at the setEmail(), this method _has_ side-effects. In the following case, we could not remove the method call:

$user = new User();
$user->setEmail('email@domain'); // This line has a side-effect (it changes an
                                 // instance variable).
Loading history...
73
    }
74
75
    /**
76
     * @param DirectiveInvocation $directive
77
     * @param Definition $definition
78
     * @throws TypeException
79
     */
80
    private function checkType(DirectiveInvocation $directive, Definition $definition): void
81
    {
82
        if (! $definition::getType()->is(Type::DIRECTIVE)) {
83
            $error = \sprintf('Can not use %s as directive', $definition);
84
85
            $exception = new TypeException($error);
86
            $exception->throwsIn($directive->getFile(), $directive->getLine(), $directive->getColumn());
87
88
            throw $exception;
89
        }
90
    }
91
92
    /**
93
     * @param DirectiveInvocation $directive
94
     * @param DirectiveDefinition $definition
95
     */
96
    private function loadDefaultArguments(DirectiveInvocation $directive, DirectiveDefinition $definition): void
97
    {
98
        foreach ($definition->getArguments() as $argument) {
99
            if ($argument->hasDefaultValue()) {
100
                $directive->withArgument($argument->getName(), $argument->getDefaultValue());
101
            }
102
        }
103
    }
104
105
    private function checkMissingArguments(DirectiveInvocation $directive, DirectiveDefinition $definition): void
0 ignored issues
show
Unused Code introduced by
The parameter $directive is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $definition is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
106
    {
107
    }
108
}
109