Completed
Pull Request — master (#6)
by Akpé Aurelle Emmanuel Moïse
01:42
created

Shortcut::prepare()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 3
nc 1
nop 3
dl 0
loc 5
rs 10
c 0
b 0
f 0
1
<?php
2
namespace EZAMA
3
4
/**
5
*
6
* @Name : Shortcut
7
* @Version : 1.0.0
8
* @Programmer : Akpé Aurelle Emmanuel Moïse Zinsou
9
* @Date : 2019-04-01
10
* @Released under : https://github.com/manuwhat/Shortcut/blob/master/LICENSE
11
* @Repository : https://github.com/manuwhat/Shortcut
12
*
13
**/
14
{
15
16
    class Shortcut
17
    {
18
        const VALID_PHP_FUNCTION_NAME_PATTERN = '#^[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*$#';
19
        const CAN_NEVER_EVER_CHOOSE_THIS_AS_FUNCTION_NAME= "new";
20
        const PLACEHOLDER_FOR_INTERNALS_CLASSES_OPTIONALS_PARAMETERS ="This is internal and thus sucks we must do something ClassShortcutDesigner";
21
        private static $DIR=null;
22
        
23
        public static function create($classname, $name=self::CAN_NEVER_EVER_CHOOSE_THIS_AS_FUNCTION_NAME)
24
        {
25
            if (is_string($classname)&&class_exists($classname, true)) {
26
                self::prepare($classname, $reflectionClass, $fullQualifiedClassname);
27
                self::getTheRightDir($file, $Dir, $fullQualifiedClassname);
28
                $fileExists=file_exists($file);
29
                if (!function_exists($classname)&&!function_exists($name)) {
30
                    if (!$fileExists) {
31
                        $name=trim($name);
32
                        self::createDir($Dir);
33
                        $reflectionMethod=$reflectionClass->getConstructor();
34
                        $notInstantiable=false;
35
                        if (self::IsNotInstantiableOrHasNoConstructor($reflectionMethod, $reflectionClass, $notInstantiable)) {
36
                            return self::HandleNotInstantiableAndHasNoConstructor($Shortcut, $fullQualifiedClassname, $name, $notInstantiable, $file, $classname);
37
                        }
38
                        self::getSignature($reflectionMethod, $signature, $parameters, $paramsNum, $count);
39
                        
40
                        $hasInternal='';
41
                        if ($count) {
42
                            self::BuildTheSwitch($hasInternal, $count, $paramsNum, $parameters, $classname);
43
                        }
44
                        self::useTheRightName($Shortcut, $name, $fullQualifiedClassname, $signature);
45
                        
46
                        self::handleInternals($Shortcut, $hasInternal, $parameters, $signature, $classname);
47
                            
48
                        return self::pushAndShow($file, $Shortcut);
49
                    } else {
50
                        return include_once($file);
51
                    }
52
                } else {
53
                    self::GetTheRightExceptionMessage($fileExists, $name, $fullQualifiedClassname);
54
                }
55
            }
56
        }
57
        
58
        private static function IsNotInstantiableOrHasNoConstructor($reflectionMethod, $reflectionClass, &$notInstantiable)
59
        {
60
            return is_null($reflectionMethod)||$notInstantiable=!$reflectionClass->isInstantiable();
61
        }
62
        
63
        private static function prepare(&$classname, &$reflectionClass, &$fullQualifiedClassname)
64
        {
65
            $reflectionClass=new \reflectionClass($classname);
66
            $classname=$reflectionClass->getName();
67
            $fullQualifiedClassname=str_replace('\\', '_', $classname);
68
        }
69
70
        private static function getSignature(\ReflectionMethod $method, &$signature, &$parameters, &$paramsNum, &$count)
71
        {
72
            $params=$method->getParameters();
73
            $paramsNum=count($params);
74
            $signature='';
75
            $parameters=array();
76
            $count=0;
77
            foreach ($params as $k=>$param) {
78
                if ($param->isPassedByReference()) {
79
                    $tmp='&$'.$param->getName();
80
                } else {
81
                    $tmp='$'.$param->getName();
82
                }
83
84
                if ($param->isOptional()) {
85
                    $count++;
86
                    if ($method->isInternal()) {
87
                        $tmp.='="This is internal and thus sucks we must do something ClassShortcutDesigner"';
88
                    } elseif ($param->isDefaultValueConstant()) {
89
                        $tmp.='='.$param->getDefaultValueConstantName();
90
                    } elseif ($param->isDefaultValueAvailable()) {
91
                        $tmp.='='.var_export($param->getDefaultValue(), true);
92
                    } elseif ($param->allowsNull()) {
93
                        $tmp.='=null';
94
                    }
95
                }
96
                
97
                $signature.=$tmp;
98
                $parameters[]='$'.$param->getName();
99
                $tmp='';
100
                if ($k<$paramsNum-1) {
101
                    $signature.=',';
102
                }
103
            }
104
        }
105
        private static function BuildTheSwitch(&$hasInternal, $count, $paramsNum, $parameters, $classname)
106
        {
107
            $hasInternal.='switch($count){';
108
            while ($count>0) {
109
                $hasInternal.="case $count:return new $classname(".join(',', array_slice($parameters, 0, $paramsNum-$count))."); break;";
110
                $count--;
111
            }
112
            $hasInternal.='default:return new '. $classname.'('.join(',', $parameters).');break;}';
113
        }
114
        
115
        private static function useTheRightName(&$Shortcut, $name, $fullQualifiedClassname, $signature)
116
        {
117
            if (strtolower($name)!=='new'&&preg_match(self::VALID_PHP_FUNCTION_NAME_PATTERN, $name)) {
118
                $Shortcut="<?php
119
							function $name($signature){";
120
            } else {
121
                $Shortcut="<?php
122
							function $fullQualifiedClassname($signature){";
123
            }
124
        }
125
        
126
        private static function handleInternals(&$Shortcut, $hasInternal, $parameters, $signature, $classname)
127
        {
128
            if (!strpos($signature, "This is internal and thus sucks we must do something ClassShortcutDesigner")) {
129
                $Shortcut.="return new $classname(".join(',', $parameters).");
130
							}";
131
            } else {
132
                $Shortcut.='
133
							$count=count(array_keys(get_defined_vars(),"'.self::PLACEHOLDER_FOR_INTERNALS_CLASSES_OPTIONALS_PARAMETERS.'"));
134
							'.$hasInternal.'
135
							}';
136
            }
137
        }
138
        
139
        private static function pushAndShow($file, $Shortcut)
140
        {
141
            file_put_contents($file, str_replace("\t", '    ', $Shortcut));
142
            file_put_contents($file, php_strip_whitespace($file));//just for cleanliness of the generated code
143
            return include_once($file);
144
        }
145
        
146
        private static function GetTheRightExceptionMessage($fileExists, $name, $fullQualifiedClassname)
147
        {
148
            if (!$fileExists) {
149
                if (strtolower($name)!=='new'&&preg_match(self::VALID_PHP_FUNCTION_NAME_PATTERN, $name)) {
150
                    throw new \InvalidArgumentException('function '.$name.' passed as second Argument already exists.
151
					Can\'t create a shortcut with the same name');
152
                } else {
153
                    throw new \InvalidArgumentException('function '.$fullQualifiedClassname.' already exists and An alias has not been provided as Argument 2.
154
					Can\'t create a shortcut function with this name');
155
                }
156
            }
157
        }
158
        
159
        private static function HandleNotInstantiableAndHasNoConstructor(&$Shortcut, $fullQualifiedClassname, $name, $notInstantiable, $file, $classname)
160
        {
161
            if ($notInstantiable) {
162
                throw new \InvalidArgumentException('Not Instantiable class '.$fullQualifiedClassname.' passed as Argument');
163
            } else {
164
                self::useTheRightName($Shortcut, $name, $fullQualifiedClassname, '');
165
                
166
                $Shortcut.="return new $classname();
167
						}";
168
                return self::pushAndShow($file, $Shortcut);
169
            }
170
        }
171
        
172
        private static function getTheRightDir(&$file, &$Dir, $fullQualifiedClassname)
173
        {
174
            if ($Dir=self::$DIR) {
175
                $file=self::$DIR.DIRECTORY_SEPARATOR.$fullQualifiedClassname.".Shortcut.php";
176
            } else {
177
                $Dir=dirname(__DIR__).DIRECTORY_SEPARATOR.'ClassShortcuts';
178
                $file=$Dir.DIRECTORY_SEPARATOR.$fullQualifiedClassname.".Shortcut.php";
179
            }
180
        }
181
        
182
        private static function createDir($Dir)
183
        {
184
            if (!file_exists($Dir)) {
185
                mkdir($Dir);
186
            }
187
        }
188
        
189
        
190
        
191
        public static function setDir($dirname)
192
        {
193
            if (is_dir($dirname)&&is_writable($dirname)&&!self::$DIR) {
194
                self::$DIR=$dirname;
195
            }
196
        }
197
        
198
        
199
        private function __construct()
200
        {
201
        }
202
    }
203
}
204
205
namespace{
206
    function create_Shortcut($classname, $name='new')
207
    {
208
        return EZAMA\Shortcut::create($classname, $name);
209
    }
210
}
211