Passed
Push — main ( d29fb3...fde677 )
by Michael
12:35
created

BindingBuilder::scoped()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 1
nc 1
nop 1
dl 0
loc 3
rs 10
c 1
b 0
f 0
ccs 2
cts 2
cp 1
crap 1
1
<?php
2
3
declare(strict_types=1);
4
5
namespace MichaelRubel\EnhancedContainer\Core;
6
7
use MichaelRubel\EnhancedContainer\Binding;
8
use MichaelRubel\EnhancedContainer\Extending;
9
use MichaelRubel\EnhancedContainer\Traits\HelpsProxies;
10
11
class BindingBuilder implements Binding, Extending
12
{
13
    use HelpsProxies;
0 ignored issues
show
introduced by
The trait MichaelRubel\EnhancedContainer\Traits\HelpsProxies requires some properties which are not provided by MichaelRubel\EnhancedContainer\Core\BindingBuilder: $contextual, $map
Loading history...
14
15
    /**
16
     * @var string
17
     */
18
    private string $abstract;
19
20
    /**
21
     * @var \Closure|string|array
22
     */
23
    private \Closure|string|array $contextualImplementation;
24
25
    /**
26
     * BindingBuilder constructor.
27
     *
28
     * @param object|string $abstract
29
     */
30 36
    public function __construct(object | string $abstract)
31
    {
32 36
        $this->abstract = $this->convertToNamespace($abstract);
33
    }
34
35
    /**
36
     * Method binding.
37
     *
38
     * @param string|null  $method
39
     * @param \Closure|null $override
40
     *
41
     * @return $this|null
42
     */
43 13
    public function method(string $method = null, \Closure $override = null): self|null
44
    {
45
        // Try to auto-resolve an implementation
46
        // for this particular abstract type.
47 13
        $this->resolve();
48
49 13
        if (is_null($method) || is_null($override)) {
50 8
            return $this;
51
        }
52
53 5
        return $this->{$method}($override);
54
    }
55
56
    /**
57
     * Basic "bind".
58
     *
59
     * @param object|string|null $concrete
60
     * @param bool               $shared
61
     *
62
     * @return $this
63
     */
64 17
    public function to(object|string $concrete = null, bool $shared = false): self
65
    {
66 17
        app()->bind($this->abstract, $this->wrapToClosure($concrete), $shared);
67
68 17
        return $this;
69
    }
70
71
    /**
72
     * Basic "bind", binds itself.
73
     *
74
     * @return void
75
     */
76 1
    public function itself(): void
77
    {
78 1
        app()->bind($this->abstract);
79
    }
80
81
    /**
82
     * Singleton.
83
     *
84
     * @param object|string|null $concrete
85
     *
86
     * @return void
87
     */
88 3
    public function singleton(object|string $concrete = null): void
89
    {
90 3
        app()->singleton($this->abstract, $this->wrapToClosure($concrete));
91
    }
92
93
    /**
94
     * Scoped instance.
95
     *
96
     * @param object|string|null $concrete
97
     *
98
     * @return void
99
     */
100 2
    public function scoped(object|string $concrete = null): void
101
    {
102 2
        app()->scoped($this->abstract, $this->wrapToClosure($concrete));
103
    }
104
105
    /**
106
     * Enables contextual binding.
107
     *
108
     * @return $this
109
     */
110 6
    public function contextual(\Closure|string|array $implementation): self
111
    {
112 6
        $this->contextualImplementation = $implementation;
113
114 6
        return $this;
115
    }
116
117
    /**
118
     * Contextual binding.
119
     *
120
     * @param array|string $concrete
121
     *
122
     * @return void
123
     */
124 6
    public function for(array|string $concrete): void
125
    {
126 6
        app()->when($concrete)
127 6
             ->needs($this->abstract)
128 6
             ->give($this->contextualImplementation);
129
    }
130
131
    /**
132
     * Extend the abstract type.
133
     *
134
     * @param \Closure $closure
135
     *
136
     * @return BindingBuilder
137
     */
138 1
    public function extend(\Closure $closure): self
139
    {
140 1
        app()->extend($this->abstract, $closure);
141
142 1
        return $this;
143
    }
144
145
    /**
146
     * Register an existing instance as shared in the container.
147
     *
148
     * @param mixed $instance
149
     *
150
     * @return BindingBuilder
151
     */
152 1
    public function instance(mixed $instance): self
153
    {
154 1
        app()->instance($this->abstract, $instance);
155
156 1
        return $this;
157
    }
158
159
    /**
160
     * Try to resolve an implementation for this particular abstract type.
161
     *
162
     * @return mixed
163
     */
164 13
    public function resolve(): mixed
165
    {
166 13
        $concrete = rescue(
167 13
            fn () => app($this->abstract),
168
            report: false
169
        );
170
171 13
        if (! is_null($concrete)) {
172 12
            $this->abstract = $this->convertToNamespace($concrete);
173
        }
174
175 13
        return $this->abstract;
176
    }
177
178
    /**
179
     * Wrap an object to the closure if the type of the object differs.
180
     *
181
     * @param object|string|null $concrete
182
     *
183
     * @return \Closure|string
184
     */
185 20
    protected function wrapToClosure(object|string|null $concrete): \Closure|string
186
    {
187 20
        if (! is_string($concrete) && ! $concrete instanceof \Closure) {
188 1
            return fn () => $concrete;
189
        }
190
191 20
        return $concrete;
192
    }
193
194
    /**
195
     * Bind the method to the container.
196
     *
197
     * @param string $method
198
     * @param array  $parameters
199
     *
200
     * @return void
201
     */
202 11
    public function __call(string $method, array $parameters): void
203
    {
204 11
        app()->bindMethod([$this->abstract, $method], current($parameters));
205
    }
206
}
207