Passed
Push — main ( 47fd5b...0acc1f )
by Sammy
01:43
created

LeMarchand.php (2 issues)

1
<?php
2
3
namespace HexMakina\LeMarchand;
4
5
use Psr\Container\{ContainerInterface, ContainerExceptionInterface, NotFoundExceptionInterface};
6
7
class LeMarchand implements ContainerInterface
8
{
9
    private static $instance = null;
10
    private $configurations = [];
11
12
    // public const RX_CONTROLLER_NAME = '/([a-zA-Z]+)Controller$/';
13
    // public const RX_MODEL_CLASS = '/([a-zA-Z]+)(Class|Model)$/';
14
    public const RX_SETTINGS = '/^settings\./';
15
    // public const RX_INTERFACE_NAME = '/([a-zA-Z]+)Interface$/';
16
    public const RX_CLASS_NAME = '/([a-zA-Z]+)(Class|Model|Controller|Interface)$/';
17
18
19
    public static function box($settings = null): ContainerInterface
20
    {
21
        if (is_null(self::$instance)) {
22
            if (is_array($settings)) {
23
                return (self::$instance = new LeMarchand($settings));
24
            }
25
            throw new LamentException('UNABLE_TO_OPEN_BOX');
26
        }
27
28
        return self::$instance;
29
    }
30
31
32
    private function __construct($settings)
33
    {
34
        $this->configurations['settings'] = $settings;
35
    }
36
37
    public function __debugInfo(): array
38
    {
39
        $dbg = get_object_vars($this);
40
        if (isset($dbg['configurations']['template_engine'])) {
41
          // way too long of an object
42
            $dbg['configurations']['template_engine'] = get_class($dbg['configurations']['template_engine']);
43
        }
44
        return $dbg;
45
    }
46
47
    public function register($configuration, $instance)
48
    {
49
        $this->configurations[$configuration] = $instance;
50
    }
51
52
    public function has($configuration)
53
    {
54
        try {
55
            $this->get($configuration);
56
            return true;
57
        } catch (NotFoundExceptionInterface $e) {
58
            return false;
59
        } catch (ContainerExceptionInterface $e) {
60
            return false;
61
        }
62
    }
63
64
65
    public function get($configuration)
66
    {
67
        if (!is_string($configuration)) {
68
            throw new LamentException($configuration);
69
        }
70
        // 1. is it a first level key ?
71
        if (isset($this->configurations[$configuration])) {
72
            return $this->configurations[$configuration];
73
        }
74
75
        // 2. is it configuration data ?
76
        if (preg_match(self::RX_SETTINGS, $configuration, $m) === 1) {
77
            return $this->getSettings($configuration);
78
        }
79
        // 3. is it a class
80
        if (preg_match(self::RX_CLASS_NAME, $configuration, $m) === 1) {
81
            return $this->classification($m[1], $m[2]);
82
        }
83
84
        throw new ConfigurationException($configuration);
85
    }
86
87
88
    private function getSettings($setting)
89
    {
90
        $ret = $this->configurations;
91
92
      //dot based hierarchy, parse and climb
93
        foreach (explode('.', $setting) as $k) {
94
            if (!isset($ret[$k])) {
95
                throw new ConfigurationException($setting);
96
            }
97
            $ret = $ret[$k];
98
        }
99
100
        return $ret;
101
    }
102
103
    private function classification($name, $type)
104
    {
105
      $class_name = $this->cascadeNamespace($name, $type);
106
107
      if ($type === 'Class') {
108
          return $class_name;
109
      }
110
111
      if($type === 'Interface'){
112
          return $this->wireInstance();
0 ignored issues
show
The method wireInstance() does not exist on HexMakina\LeMarchand\LeMarchand. Did you maybe mean wireIntance()? ( Ignorable by Annotation )

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

112
          return $this->/** @scrutinizer ignore-call */ wireInstance();

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
113
      }
114
115
      return $this->getInstance($class_name);
116
    }
117
118
    private function cascadeNamespace($class_name, $mvc_type = null)
119
    {
120
        // does the name already exists ?
121
        if (class_exists($class_name)) {
122
            return $class_name;
123
        }
124
125
        if ($mvc_type === 'Class') {
126
            $mvc_type = 'Model';
127
        }
128
129
        if ($mvc_type === 'Controller') {
130
            $class_name = $class_name . 'Controller';
131
        }
132
133
        // not fully namespaced, lets cascade
134
        foreach ($this->getSettings('settings.namespaces') as $ns) {
135
            if (class_exists($full_name = $ns . $mvc_type . 's\\' . $class_name)) {
136
                return $full_name;
137
            }
138
        }
139
140
        throw new ConfigurationException($class_name);
141
    }
142
143
    private function wireIntance($interface)
0 ignored issues
show
The method wireIntance() is not used, and could be removed.

This check looks for private methods that have been defined, but are not used inside the class.

Loading history...
144
    {
145
      $wire = $this->getSettings('settings.interface_implementations');
146
147
      if (!isset($wire[$interface])) {
148
        throw new ConfigurationException($interface);
149
      }
150
151
      return $this->getInstance($wire[$interface]);
152
    }
153
154
    private function getInstance($class)
155
    {
156
        try {
157
            $rc = new \ReflectionClass($class);
158
            $instance = null;
159
            $construction_args = [];
160
            if (!is_null($rc->getConstructor())) {
161
                foreach ($rc->getConstructor()->getParameters() as $param) {
162
                    $construction_args [] = $this->get($param->getType() . '');
163
                }
164
                $instance = $rc->newInstanceArgs($construction_args);
165
            } else {
166
                $instance = $rc->newInstanceArgs();
167
            }
168
169
            if ($rc->hasMethod('set_container')) {
170
                $instance->set_container($this);
171
            }
172
173
            return $instance;
174
        } catch (\ReflectionException $e) {
175
            return null;
176
        }
177
    }
178
179
180
}
181