Passed
Push — main ( 8fb716...17db83 )
by Sammy
01:41
created

LeMarchand::cascadeControllers()   A

Complexity

Conditions 4
Paths 4

Size

Total Lines 13
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

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