Passed
Push — main ( e6a09b...cb46db )
by Sammy
01:35
created

LeMarchand.php (1 issue)

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)$/';
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
        throw new LamentException('MVC_TYPE ('.$mvc_type.') UNKOWN');
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $mvc_type seems to be never defined.
Loading history...
25
      }
26
27
      return self::$instance;
28
    }
29
30
31
    private function __construct($settings)
32
    {
33
        $this->configurations['settings'] = $settings;
34
    }
35
36
    public function __debugInfo(): array
37
    {
38
        $dbg = get_object_vars($this);
39
        if (isset($dbg['configurations']['template_engine'])) {
40
          // way too long of an object
41
            $dbg['configurations']['template_engine'] = get_class($dbg['configurations']['template_engine']);
42
        }
43
        return $dbg;
44
    }
45
46
    public function register($configuration, $instance)
47
    {
48
        $this->configurations[$configuration] = $instance;
49
    }
50
51
    public function has($configuration)
52
    {
53
      try{
54
        $this->get($configuration);
55
        return true;
56
      }
57
      catch(NotFoundExceptionInterface $e){
58
        return false;
59
      }
60
      catch(ContainerExceptionInterface $e){
61
        return false;
62
      }
63
    }
64
65
66
    public function get($configuration)
67
    {
68
        if (!is_string($configuration)) {
69
            throw new LamentException($configuration);
70
        }
71
        // 1. is it a first level key ?
72
        if (isset($this->configurations[$configuration])) {
73
            return $this->configurations[$configuration];
74
        }
75
76
        // 2. is it configuration data ?
77
        if (preg_match(self::RX_SETTINGS, $configuration, $m) === 1) {
78
            return $this->getSettings($configuration);
79
        }
80
        // 3. is it a class
81
        if (preg_match(self::RX_CLASS_NAME, $configuration, $m) === 1) {
82
            $class_name = $this->cascadeNamespace($m[1], $m[2]);
83
            if($m[2] === 'Class')
84
              return $class_name;
85
86
            return $this->getInstance($class_name);
87
        }
88
89
        if (preg_match(self::RX_INTERFACE_NAME, $configuration, $m) === 1) {
90
            $wire = $this->get('settings.interface_implementations');
91
            if(isset($wire[$configuration]))
92
              return $this->getInstance($wire[$configuration]);
93
        }
94
95
        throw new ConfigurationException($configuration);
96
    }
97
98
    // private function cascadeControllers($controller_name)
99
    // {
100
    //     // is the controller name already instantiable ?
101
    //     if (!is_null($instance = $this->getInstance($controller_name))) {
102
    //         return $instance;
103
    //     }
104
    //     // not fully namespaced, lets cascade
105
    //     foreach ($this->getSettings('settings.controller_namespaces') as $cns) {
106
    //         if (!is_null($instance = $this->getInstance($cns . $controller_name))) {
107
    //             return $instance;
108
    //         }
109
    //     }
110
    //     throw new ConfigurationException($controller_name);
111
    // }
112
113
    private function cascadeNamespace($class_name, $mvc_type=null)
114
    {
115
        // is the controller name already instantiable ?
116
        if(is_null($mvc_type) && class_exists($class_name))
117
          return $class_name;
118
119
        if($mvc_type === 'Class')
120
          $mvc_type = 'Model';
121
122
        if($mvc_type !== 'Model' && $mvc_type !== 'Controller'){
123
            throw new LamentException('MVC_TYPE ('.$mvc_type.') UNKOWN');
124
        }
125
        if($mvc_type === 'Controller')
126
          $class_name = $class_name.'Controller';
127
128
        // not fully namespaced, lets cascade
129
        foreach ($this->getSettings('settings.namespaces') as $ns) {
130
            if(class_exists($full_name = $ns . $mvc_type . 's\\' . $class_name))
131
              return $full_name;
132
        }
133
134
        throw new ConfigurationException($class_name);
135
    }
136
137
    private function getInstance($class)
138
    {
139
        try {
140
            $rc = new \ReflectionClass($class);
141
            $instance = null;
142
            $construction_args = [];
143
            if (!is_null($rc->getConstructor())) {
144
                foreach ($rc->getConstructor()->getParameters() as $param) {
145
                    $construction_args [] = $this->get($param->getType() . '');
146
                }
147
                $instance = $rc->newInstanceArgs($construction_args);
148
            } else {
149
                $instance = $rc->newInstanceArgs();
150
            }
151
152
            if ($rc->hasMethod('set_container')) {
153
                $instance->set_container($this);
154
            }
155
156
            return $instance;
157
        } catch (\ReflectionException $e) {
158
            return null;
159
        }
160
    }
161
162
163
    private function getSettings($setting)
164
    {
165
        $ret = $this->configurations;
166
167
      //dot based hierarchy, parse and climb
168
        foreach (explode('.', $setting) as $k) {
169
            if (!isset($ret[$k])) {
170
                throw new ConfigurationException($setting);
171
            }
172
            $ret = $ret[$k];
173
        }
174
175
        return $ret;
176
    }
177
}
178