Test Failed
Pull Request — master (#37)
by Divine Niiquaye
03:19
created

Definition::should()   B

Complexity

Conditions 8
Paths 8

Size

Total Lines 45
Code Lines 28

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 28
CRAP Score 8

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 28
c 1
b 0
f 0
dl 0
loc 45
ccs 28
cts 28
cp 1
rs 8.4444
cc 8
nc 8
nop 2
crap 8
1
<?php
2
3
declare(strict_types=1);
4
5
/*
6
 * This file is part of DivineNii opensource projects.
7
 *
8
 * PHP version 7.4 and above required
9
 *
10
 * @author    Divine Niiquaye Ibok <[email protected]>
11
 * @copyright 2021 DivineNii (https://divinenii.com/)
12
 * @license   https://opensource.org/licenses/BSD-3-Clause License
13
 *
14
 * For the full copyright and license information, please view the LICENSE
15
 * file that was distributed with this source code.
16
 */
17
18
namespace Rade\DI;
19
20
use PhpParser\Node\Expr\{Assign, Variable};
21
use PhpParser\Node\Stmt\Return_;
22
use Rade\DI\Exceptions\ServiceCreationException;
23
use Rade\DI\Definitions\{DefinitionAwareInterface, DefinitionInterface, DepreciableDefinitionInterface, ShareableDefinitionInterface, TypedDefinitionInterface};
24
use Rade\DI\Definitions\Traits as Defined;
25
26
/**
27
 * Represents definition of standard service.
28
 *
29
 * @author Divine Niiquaye Ibok <[email protected]>
30
 */
31
class Definition implements DefinitionInterface, TypedDefinitionInterface, ShareableDefinitionInterface, DefinitionAwareInterface, DepreciableDefinitionInterface
32
{
33
    use Defined\DeprecationTrait;
34
    use Defined\ParameterTrait;
35
    use Defined\BindingTrait;
0 ignored issues
show
Bug introduced by
The trait Rade\DI\Definitions\Traits\BindingTrait requires the property $var which is not provided by Rade\DI\Definition.
Loading history...
36
    use Defined\VisibilityTrait;
37
    use Defined\AutowireTrait;
38
    use Defined\DefinitionAwareTrait;
39
40
    /** @var mixed The service entity */
41
    private $entity;
42
43
    /**
44
     * Definition constructor.
45
     *
46
     * @param mixed                   $entity
47
     * @param array<int|string,mixed> $arguments
48
     */
49
    public function __construct($entity, array $arguments = [])
50
    {
51
        $this->replace($entity, true);
52
        $this->arguments = $arguments;
53
    }
54
55
    /**
56
     * {@inheritdoc}
57
     */
58
    public function getEntity()
59
    {
60
        return $this->entity;
61
    }
62
63
    /**
64
     * Replace existing entity to a new entity.
65
     *
66
     * @param mixed $entity
67
     *
68
     * @return $this
69
     */
70
    public function replace($entity, bool $if)
71
    {
72
        if ($entity instanceof DefinitionInterface) {
73
            throw new ServiceCreationException(\sprintf('A definition entity must not be an instance of "%s".', DefinitionInterface::class));
74
        }
75
76
        if ($if /* Replace if matches a rule */) {
77
            $this->entity = $entity;
78
79
            if ($this->autowired) {
80
                $this->typed(Resolver::autowireService($entity, false, isset($this->innerId) ? $this->container : null));
81
            }
82
        }
83
84
        return $this;
85
    }
86
87
    /**
88
     * {@inheritdoc}
89
     */
90
    public function build(string $id, Resolver $resolver)
91
    {
92
        if (null === $builder = $resolver->getBuilder()) {
93
            return $this->resolve($id, $resolver);
94
        }
95
96
        $this->triggerReturnType($defNode = $builder->method($resolver->createMethod($id))->makeProtected());
97
98
        if ($this->isDeprecated()) {
99
            $defNode->addStmt($this->triggerDeprecation($id, $builder));
100
        }
101
102 117
        if ($this->lazy) {
103
            $createdDef = $builder->methodCall($builder->propertyFetch($builder->var('this'), 'resolver'), 'resolver', [$this->entity, $resolver->resolveArguments($this->arguments)]);
104 117
        } else {
105 117
            $createdDef = $resolver->resolve($this->entity, $this->arguments);
106 117
107
            if ($createdDef instanceof Injector\Injectable) {
108
                $createdDef = $createdDef->build($defNode, $builder->var('service'), $builder);
109
            }
110
        }
111
112
        if ($this->hasBinding()) {
113
            if (!$createdDef instanceof Assign) {
114
                $defNode->addStmt($createdDef = new Assign(new Variable('service'), $createdDef));
115
            }
116 49
117
            $this->resolveBinding($defNode, $createdDef, $resolver, $builder);
118 49
        }
119 38
120
        if ($this->shared) {
121
            $createdDef = $this->triggerSharedBuild($id, $createdDef instanceof Assign ? $createdDef->var : $createdDef, $builder);
122 22
        }
123
124
        return $defNode->addStmt(new Return_($createdDef));
125
    }
126
127
    /**
128 21
     * @return mixed
129
     */
130 21
    protected function resolve(string $id, Resolver $resolver)
131
    {
132
        if ($this->isDeprecated()) {
133
            $this->triggerDeprecation($id);
134
        }
135
136
        if (\is_object($resolved = $this->entity)) {
137
            $resolved = !\is_callable($resolved) ? $resolved : $resolver->resolveCallable($resolved);
0 ignored issues
show
Bug introduced by
$resolved of type object is incompatible with the type array<integer,mixed>|callable expected by parameter $callback of Rade\DI\Resolver::resolveCallable(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

137
            $resolved = !\is_callable($resolved) ? $resolved : $resolver->resolveCallable(/** @scrutinizer ignore-type */ $resolved);
Loading history...
138
        } else {
139 91
            $resolved = $resolver->resolve($this->entity, $this->arguments);
140
        }
141 91
142 91
        if ($this->hasBinding()) {
143
            if (\is_object($resolved)) {
144 91
                foreach ($this->parameters as $property => $propertyValue) {
145 49
                    $resolved->{$property} = $resolver->resolve($propertyValue);
146
                }
147 91
148
                foreach ($this->calls as [$method, $methodValue]) {
149
                    $resolver->resolve([$resolved, $method], (array) $methodValue);
150
                }
151
            }
152
153
            foreach ($this->extras as [$extend, $code]) {
154
                $resolver->resolve($code, $extend ? [$resolved] : []);
155
            }
156 57
        }
157
158 57
        return $resolved;
159 5
    }
160
}
161