Completed
Push — master ( f76fe9...ec1209 )
by Basil
03:07
created

ObjectHelper::getControllers()   B

Complexity

Conditions 6
Paths 14

Size

Total Lines 23

Duplication

Lines 0
Ratio 0 %

Importance

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

Scrutinizer analyzes your composer.json/composer.lock file if available to determine the classes, and functions that are defined by your dependencies.

It seems like the listed class was neither found in your dependencies, nor was it found in the analyzed files in your repository. If you are using some other form of dependency management, you might want to disable this analysis.

Loading history...
218
            
219
        };
220
221
        $staticPath = $module::staticBasePath() . DIRECTORY_SEPARATOR . 'controllers';
222
        if (is_dir($staticPath)) {
223
            foreach (FileHelper::findFiles($staticPath) as $file) {
224
                $files[self::fileToName($staticPath, $file)] = $file;
225
            }
226
        }
227
        
228
        return $files;
229
    }
230
231
    /**
232
     * Namify a controller file
233
     *
234
     * @param string $prefix
235
     * @param string $file
236
     * @return string
237
     * @since 1.0.19
238
     */
239
    private static function fileToName($prefix, $file)
240
    {
241
        return Inflector::camel2id(ltrim(str_replace([$prefix, 'Controller.php'], '', $file), DIRECTORY_SEPARATOR));
242
    }
243
}
244