Completed
Push — master ( ea25cb...280c7e )
by Tristan
02:05
created

Binder::cleanAlias()   A

Complexity

Conditions 3
Paths 2

Size

Total Lines 9
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 1
Metric Value
c 1
b 0
f 1
dl 0
loc 9
rs 9.6666
cc 3
eloc 4
nc 2
nop 1
1
<?php
2
3
namespace Enzyme\LaravelBinder;
4
5
use Illuminate\Contracts\Container\Container;
6
7
/**
8
 * Manages a set of context bindings using Laravel's service container.
9
 */
10
class Binder
11
{
12
    /**
13
     * A reference to the service container.
14
     *
15
     * @var \Illuminate\Contracts\Container\Container
16
     */
17
    protected $container;
18
19
    /**
20
     * A collection of bindings.
21
     *
22
     * @var array
23
     */
24
    protected $bindings = [];
25
26
    /**
27
     * A collection of aliases.
28
     *
29
     * @var array
30
     */
31
    protected $aliases = [];
32
33
    /**
34
     * A collection of classes and their dependencies.
35
     *
36
     * @var array
37
     */
38
    protected $needs = [];
39
40
    /**
41
     * Holds a record of the last binding that occured.
42
     *
43
     * @var array
44
     */
45
    protected $lastBinding = [];
46
47
    /**
48
     * Create a new Binder from the given service container instance.
49
     * 
50
     * @param \Illuminate\Contracts\Container\Container $container
51
     */
52
    public function __construct(Container $container)
53
    {
54
        $this->container = $container;
55
    }
56
57
    /**
58
     * Create an alias for the given class or interface.
59
     *
60
     * @param string $alias The alias.
61
     * @param string $fqn   The full namespaced path to the class or interface.
62
     */
63
    public function setAlias($alias, $fqn)
64
    {
65
        $this->aliases[$this->cleanAlias($alias)] = $fqn;
66
    }
67
68
    /**
69
     * Create a binding from an interface to a concrete class.
70
     *
71
     * @param string $alias     The alias for this binding.
72
     * @param string $interface The interface.
73
     * @param string $concrete  The concrete implementation.
74
     */
75
    public function setBinding($alias, $interface, $concrete)
76
    {
77
        $this->bindings[$this->cleanAlias($alias)] = [
78
            'interface' => $interface,
79
            'concrete'  => $concrete,
80
        ];
81
82
        $this->lastBinding = compact('alias', 'interface', 'concrete');
83
84
        return $this;
85
    }
86
87
    /**
88
     * Binds the previous virtual binding into the Laravel service container.
89
     * This will map the interface to the concrete class, then create an alias
90
     * for the interface so it can later be referenced by its short name.
91
     */
92
    public function solidify()
93
    {
94
        if (count($this->lastBinding) < 3) {
95
            throw new BindingException(
96
                "Container injection can't be completed ".
97
                "as a previous binding hasn't occured."
98
            );
99
        }
100
101
        $alias = $this->lastBinding['alias'];
102
        $interface = $this->lastBinding['interface'];
103
        $concrete = $this->lastBinding['concrete'];
104
105
        $this
106
            ->container
107
            ->bind($this->getFqn($interface), $concrete);
108
        $this
109
            ->container
110
            ->bind($alias, function($app) use($interface) {
111
                return $app->make($this->getFqn($interface));
112
            });
113
    }
114
115
    /**
116
     * Set the dependencies of a class.
117
     *
118
     * @param string $alias The alias of the class.
119
     * @param array  $needs An array of dependencies.
120
     */
121
    public function setNeeds($alias, array $needs)
122
    {
123
        $this->needs[$this->cleanAlias($alias)] = $needs;
124
    }
125
126
    /**
127
     * Register all the dependencies with the underlying service container.
128
     */
129
    public function register()
130
    {
131
        foreach ($this->needs as $parent => $dependencies) {
132
            $this->registerDependencies($this->getFqn($parent), $dependencies);
133
        }
134
    }
135
136
    /**
137
     * Registers the given dependencies with the parent class.
138
     *
139
     * @param string $parent_fqn   The full namespaced class path.
140
     * @param array  $dependencies The collection of dependencies.
141
     */
142
    protected function registerDependencies($parent_fqn, array $dependencies)
143
    {
144
        foreach ($dependencies as $dependency) {
145
            $dependency_tree = $this->bindings[$dependency];
146
147
            $this
148
                ->container
149
                ->when($parent_fqn)
150
                ->needs($this->getFqn($dependency_tree['interface']))
151
                ->give($this->getFqn($dependency_tree['concrete']));
152
        }
153
    }
154
155
    /**
156
     * Get the fully qualified name for the given string if it's an alias
157
     * otherwise ensure the class/interface exists and return it. Will throw a
158
     * BindingException if the class/interface does not exist.
159
     *
160
     * @param string $string
161
     *
162
     * @return string
163
     */
164
    protected function getFqn($string)
165
    {
166
        if (class_exists($string) || interface_exists($string)) {
167
            return $string;
168
        }
169
170
        if ($this->arrayHas($this->aliases, $string)) {
171
            return $this->getFqn($this->aliases[$string]);
172
        }
173
174
        throw new BindingException(
175
            "The class or alias [{$string}] does not exist."
176
        );
177
    }
178
179
    /**
180
     * Check if the given array has the key specified.
181
     *
182
     * @param array $array The array to check.
183
     * @param mixed $key   The key.
184
     *
185
     * @return boolean
186
     */
187
    protected function arrayHas(array $array, $key)
188
    {
189
        return isset($array[$key])
190
            && array_key_exists($key, $array);
191
    }
192
193
    /**
194
     * Return a clean alias and ensure it is a string and not of length zero.
195
     * Will throw a BindingException if the value given is not a string or a
196
     * string of length zero.
197
     *
198
     * @param string $alias
199
     *
200
     * @return string
201
     */
202
    protected function cleanAlias($alias)
203
    {
204
        if (is_string($alias) && strlen($alias) > 0)
205
        {
206
            return $alias;
207
        }
208
209
        throw new BindingException("The alias [{$alias}] is invalid.");
210
    }
211
}
212