Completed
Push — master ( b4d6a5...352f6d )
by Basil
02:42
created

ObjectHelper   A

Complexity

Total Complexity 32

Size/Duplication

Total Lines 235
Duplicated Lines 0 %

Coupling/Cohesion

Components 0
Dependencies 5

Importance

Changes 0
Metric Value
wmc 32
lcom 0
cbo 5
dl 0
loc 235
rs 9.84
c 0
b 0
f 0

8 Methods

Rating   Name   Duplication   Size   Complexity  
A isInstanceOf() 0 21 5
A isTraitInstanceOf() 0 17 4
A traitsList() 0 23 4
A toArray() 0 4 1
A getActions() 0 13 6
B getControllers() 0 22 6
A fileToName() 0 4 1
A callMethodSanitizeArguments() 0 20 5
1
<?php
2
3
namespace luya\helpers;
4
5
use ReflectionClass;
6
use ReflectionMethod;
7
use luya\Exception;
8
use yii\base\Controller;
9
use luya\base\Module;
10
use yii\base\InvalidParamException;
11
12
/**
13
 * Helper methods when dealing with Objects.
14
 *
15
 * @author Basil Suter <[email protected]>
16
 * @since 1.0.0
17
 */
18
class ObjectHelper
19
{
20
    /**
21
     * Checks a given variable if its an instance of an element in the $instances list.
22
     *
23
     * ```php
24
     * $object = new \Exception();
25
     *
26
     * ObjectHelper::isInstanceOf($object, '\Exception');
27
     * ```
28
     *
29
     * In order to check if an object is at least an instance of one given resourcese use:
30
     *
31
     * ```php
32
     * ObjectHelper::isInstanceOf($object, ['not\this\Object', 'maybe\this\Object', '\Exception']);
33
     * ```
34
     *
35
     * If at least one of the given exception names in the array is an instance of the given object, true
36
     * is returned.
37
     *
38
     * @param object $object The object to type check against haystack.
39
     * @param string|array|object $haystack A list of classes, a string for a given class, or an object.
40
     * @param boolean $throwException Whether an exception should be thrown or not.
41
     * @throws \luya\Exception
42
     * @return boolean
43
     * @since 1.0.3
44
     */
45
    public static function isInstanceOf($object, $haystack, $throwException = true)
46
    {
47
        // if instances is an object (compare object directly) we have to get the class name to compare with instanceof later
48
        if (is_object($haystack)) {
49
            $haystack = get_class($haystack);
50
        }
51
        
52
        $haystack = (array) $haystack;
53
        
54
        foreach ($haystack as $class) {
55
            if ($object instanceof $class) {
56
                return true;
57
            }
58
        }
59
        
60
        if ($throwException) {
61
            throw new Exception("The given object must be an instance of: " . implode(",", $haystack));
62
        }
63
        
64
        return false;
65
    }
66
67
    /**
68
     * Check whether a given object contains a trait.
69
     *
70
     * ```php
71
     * trait XYZ {
72
     *
73
     * }
74
     *
75
     * class ABC {
76
     *    use XYZ;
77
     * }
78
     *
79
     * $object = new ABC();
80
     *
81
     * ObjectHelper::isTraitInstanceOf($object, XYZ::class);
82
     * ```
83
     *
84
     * @param object $object
85
     * @param string|array|object $haystack
86
     * @return boolean
87
     * @since 1.0.17
88
     */
89
    public static function isTraitInstanceOf($object, $haystack)
90
    {
91
        $traits = static::traitsList($object);
92
93
        // if its an object, the all traits for the given object.
94
        if (is_object($haystack)) {
95
            $haystack = static::traitsList($haystack);
96
        }
97
98
        foreach ((array) $haystack as $stack) {
99
            if (in_array($stack, $traits)) {
100
                return true;
101
            }
102
        }
103
104
        return false;
105
    }
106
107
    /**
108
     * Get an array with all traits for a given object
109
     *
110
     * @param object $object
111
     * @param boolean $autoload
112
     * @return array
113
     * @since 1.0.17
114
     * @see https://www.php.net/manual/en/function.class-uses.php#122427
115
     */
116
    public static function traitsList($object, $autoload = true)
117
    {
118
        $traits = [];
119
120
        // Get traits of all parent classes
121
        do {
122
            $traits = array_merge(class_uses($object, $autoload), $traits);
123
        } while ($object = get_parent_class($object));
124
125
        // Get traits of all parent traits
126
        $traitsToSearch = $traits;
127
        while (!empty($traitsToSearch)) {
128
            $newTraits = class_uses(array_pop($traitsToSearch), $autoload);
129
            $traits = array_merge($newTraits, $traits);
130
            $traitsToSearch = array_merge($newTraits, $traitsToSearch);
131
        };
132
133
        foreach ($traits as $trait => $same) {
134
            $traits = array_merge(class_uses($trait, $autoload), $traits);
135
        }
136
137
        return $traits;
138
    }
139
    
140
    /**
141
     * Convert Object to Array
142
     *
143
     * @param object $object
144
     * @return array
145
     */
146
    public static function toArray($object)
147
    {
148
        return (array) $object;
149
    }
150
    
151
    /**
152
     * Call a method and ensure arguments.
153
     *
154
     * Call a class method with arguments and verify the arguments if they are in the list of method arguments or not.
155
     *
156
     * ```php
157
     * ObjectHelper::callMethodSanitizeArguments(new MyClass(), 'methodToCall', ['paramName' => 'paramValue']);
158
     * ```
159
     *
160
     * The response is the return value from the called method of the object.
161
     *
162
     * @param object $object The class object where the method must be found.
163
     * @param string $method The class method to call inside the object.
164
     * @param array $argumentsList A massiv assigned list of array items, where the key is bind to the method argument and the value to be passed in the method on call.
165
     * @throws \luya\Exception Throws an exception if a argument coult not be found.
166
     * @return mixed
167
     */
168
    public static function callMethodSanitizeArguments($object, $method, array $argumentsList = [])
169
    {
170
        // get class reflection object
171
        $reflection = new ReflectionMethod($object, $method);
172
        // array where the sanitized arguemnts will be stored
173
        $methodArgs = [];
174
175
        foreach ($reflection->getParameters() as $param) {
176
            // add the argument into the method list when existing
177
            if (array_key_exists($param->name, $argumentsList)) {
178
                $methodArgs[] = $argumentsList[$param->name];
179
            }
180
            // check if the provided arguemnt is optional or not
181
            if (!$param->isOptional() && !array_key_exists($param->name, $argumentsList)) {
182
                throw new Exception(sprintf("The argument '%s' is required for method '%s' in class '%s'.", $param->name, $method, get_class($object)));
183
            }
184
        }
185
186
        return call_user_func_array([$object, $method], $methodArgs);
187
    }
188
189
    /**
190
     * Get all actions from a given controller.
191
     *
192
     * @param Controller $controller
193
     * @return array
194
     * @since 1.0.19
195
     */
196
    public static function getActions(Controller $controller)
197
    {
198
        $actions = array_keys($controller->actions());
199
        $class = new ReflectionClass($controller);
200
        foreach ($class->getMethods() as $method) {
201
            $name = $method->getName();
0 ignored issues
show
Bug introduced by
Consider using $method->name. There is an issue with getName() and APC-enabled PHP versions.
Loading history...
202
            if ($name !== 'actions' && $method->isPublic() && !$method->isStatic() && strncmp($name, 'action', 6) === 0) {
203
                $actions[] = Inflector::camel2id(substr($name, 6), '-', true);
204
            }
205
        }
206
        sort($actions);
207
        return array_unique($actions);
208
    }
209
210
    /**
211
     * Get all controllers for a given luya Module
212
     *
213
     * @param Module $module
214
     * @return array
215
     * @since 1.0.19
216
     */
217
    public static function getControllers(Module $module)
218
    {
219
        $files = [];
220
221
        try { // https://github.com/yiisoft/yii2/blob/master/framework/base/Module.php#L253
222
            if (is_dir($module->controllerPath)) {
223
                foreach (FileHelper::findFiles($module->controllerPath) as $file) {
224
                    $files[self::fileToName($module->controllerPath, $file)] = $file;
225
                }
226
            }
227
        } catch (InvalidParamException $e) {
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
228
        };
229
230
        $staticPath = $module::staticBasePath() . DIRECTORY_SEPARATOR . 'controllers';
231
        if (is_dir($staticPath)) {
232
            foreach (FileHelper::findFiles($staticPath) as $file) {
233
                $files[self::fileToName($staticPath, $file)] = $file;
234
            }
235
        }
236
        
237
        return $files;
238
    }
239
240
    /**
241
     * Namify a controller file
242
     *
243
     * @param string $prefix
244
     * @param string $file
245
     * @return string
246
     * @since 1.0.19
247
     */
248
    private static function fileToName($prefix, $file)
249
    {
250
        return Inflector::camel2id(ltrim(str_replace([$prefix, 'Controller.php'], '', $file), DIRECTORY_SEPARATOR));
251
    }
252
}
253