Passed
Push — main ( 94f2ad...21b941 )
by Sammy
01:32
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
82
            $class_name = $this->cascadeNamespace($m[1], $m[2]);
83
84
            if ($m[2] === 'Class') {
85
                return $class_name;
86
            }
87
88
            if($m[2] === 'Interface'){
89
                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

89
                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...
90
            }
91
92
            return $this->getInstance($class_name);
93
        }
94
95
        throw new ConfigurationException($configuration);
96
    }
97
98
    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...
99
    {
100
      $wire = $this->getSettings('settings.interface_implementations');
101
102
      if (!isset($wire[$interface])) {
103
        throw new ConfigurationException($interface);
104
      }
105
106
      return $this->getInstance($wire[$interface]);
107
    }
108
109
    private function cascadeNamespace($class_name, $mvc_type = null)
110
    {
111
        // does the name already exists ?
112
        if (class_exists($class_name)) {
113
            return $class_name;
114
        }
115
116
        if ($mvc_type === 'Class') {
117
            $mvc_type = 'Model';
118
        }
119
120
        if ($mvc_type === 'Controller') {
121
            $class_name = $class_name . 'Controller';
122
        }
123
124
        // not fully namespaced, lets cascade
125
        foreach ($this->getSettings('settings.namespaces') as $ns) {
126
            if (class_exists($full_name = $ns . $mvc_type . 's\\' . $class_name)) {
127
                return $full_name;
128
            }
129
        }
130
131
        throw new ConfigurationException($class_name);
132
    }
133
134
    private function getInstance($class)
135
    {
136
        try {
137
            $rc = new \ReflectionClass($class);
138
            $instance = null;
139
            $construction_args = [];
140
            if (!is_null($rc->getConstructor())) {
141
                foreach ($rc->getConstructor()->getParameters() as $param) {
142
                    $construction_args [] = $this->get($param->getType() . '');
143
                }
144
                $instance = $rc->newInstanceArgs($construction_args);
145
            } else {
146
                $instance = $rc->newInstanceArgs();
147
            }
148
149
            if ($rc->hasMethod('set_container')) {
150
                $instance->set_container($this);
151
            }
152
153
            return $instance;
154
        } catch (\ReflectionException $e) {
155
            return null;
156
        }
157
    }
158
159
160
    private function getSettings($setting)
161
    {
162
        $ret = $this->configurations;
163
164
      //dot based hierarchy, parse and climb
165
        foreach (explode('.', $setting) as $k) {
166
            if (!isset($ret[$k])) {
167
                throw new ConfigurationException($setting);
168
            }
169
            $ret = $ret[$k];
170
        }
171
172
        return $ret;
173
    }
174
}
175