Completed
Push — master ( bb16e7...820610 )
by Arjay
01:46
created

Helper::extractColumnName()   A

Complexity

Conditions 4
Paths 4

Size

Total Lines 18
Code Lines 11

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 4
eloc 11
nc 4
nop 2
dl 0
loc 18
rs 9.2
c 0
b 0
f 0
1
<?php
2
3
namespace Yajra\Datatables;
4
5
use DateTime;
6
use Illuminate\Contracts\Support\Arrayable;
7
use Illuminate\Filesystem\Filesystem;
8
use Illuminate\Support\Str;
9
use Illuminate\View\Compilers\BladeCompiler;
10
11
/**
12
 * Class Helper.
13
 *
14
 * @package Yajra\Datatables
15
 * @author  Arjay Angeles <[email protected]>
16
 */
17
class Helper
18
{
19
    /**
20
     * Places item of extra columns into results by care of their order.
21
     *
22
     * @param array $item
23
     * @param array $array
24
     * @return array
25
     */
26
    public static function includeInArray($item, $array)
27
    {
28
        if (self::isItemOrderInvalid($item, $array)) {
29
            return array_merge($array, [$item['name'] => $item['content']]);
30
        } else {
31
            $count = 0;
32
            $last  = $array;
33
            $first = [];
34
            foreach ($array as $key => $value) {
35
                if ($count == $item['order']) {
36
                    return array_merge($first, [$item['name'] => $item['content']], $last);
37
                }
38
39
                unset($last[$key]);
40
                $first[$key] = $value;
41
42
                $count++;
43
            }
44
        }
45
    }
46
47
    /**
48
     * Check if item order is valid.
49
     *
50
     * @param array $item
51
     * @param array $array
52
     * @return bool
53
     */
54
    protected static function isItemOrderInvalid($item, $array)
55
    {
56
        return $item['order'] === false || $item['order'] >= count($array);
57
    }
58
59
    /**
60
     * Determines if content is callable or blade string, processes and returns.
61
     *
62
     * @param string|callable $content Pre-processed content
63
     * @param array           $data data to use with blade template
64
     * @param mixed           $param parameter to call with callable
65
     * @return string Processed content
66
     */
67
    public static function compileContent($content, array $data, $param)
68
    {
69
        if (is_string($content)) {
70
            return static::compileBlade($content, static::getMixedValue($data, $param));
71
        } elseif (is_callable($content)) {
72
            return $content($param);
73
        }
74
75
        return $content;
76
    }
77
78
    /**
79
     * Parses and compiles strings by using Blade Template System.
80
     *
81
     * @param string $str
82
     * @param array  $data
83
     * @return string
84
     * @throws \Exception
85
     */
86
    public static function compileBlade($str, $data = [])
87
    {
88
        if (view()->exists($str)) {
0 ignored issues
show
Bug introduced by
The method exists does only exist in Illuminate\Contracts\View\Factory, but not in Illuminate\View\View.

It seems like the method you are trying to call exists only in some of the possible types.

Let’s take a look at an example:

class A
{
    public function foo() { }
}

class B extends A
{
    public function bar() { }
}

/**
 * @param A|B $x
 */
function someFunction($x)
{
    $x->foo(); // This call is fine as the method exists in A and B.
    $x->bar(); // This method only exists in B and might cause an error.
}

Available Fixes

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
89
            return view($str, $data)->render();
0 ignored issues
show
Bug introduced by
The method render does only exist in Illuminate\View\View, but not in Illuminate\Contracts\View\Factory.

It seems like the method you are trying to call exists only in some of the possible types.

Let’s take a look at an example:

class A
{
    public function foo() { }
}

class B extends A
{
    public function bar() { }
}

/**
 * @param A|B $x
 */
function someFunction($x)
{
    $x->foo(); // This call is fine as the method exists in A and B.
    $x->bar(); // This method only exists in B and might cause an error.
}

Available Fixes

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
90
        }
91
92
        $empty_filesystem_instance = new Filesystem();
93
        $blade                     = new BladeCompiler($empty_filesystem_instance, 'datatables');
94
        $parsed_string             = $blade->compileString($str);
95
96
        ob_start() && extract($data, EXTR_SKIP);
97
98
        try {
99
            eval('?>' . $parsed_string);
0 ignored issues
show
Coding Style introduced by
It is generally not recommended to use eval unless absolutely required.

On one hand, eval might be exploited by malicious users if they somehow manage to inject dynamic content. On the other hand, with the emergence of faster PHP runtimes like the HHVM, eval prevents some optimization that they perform.

Loading history...
100
        } catch (\Exception $e) {
0 ignored issues
show
Unused Code introduced by
catch (\Exception $e) { ...lean(); throw $e; } does not seem to be reachable.

This check looks for unreachable code. It uses sophisticated control flow analysis techniques to find statements which will never be executed.

Unreachable code is most often the result of return, die or exit statements that have been added for debug purposes.

function fx() {
    try {
        doSomething();
        return true;
    }
    catch (\Exception $e) {
        return false;
    }

    return false;
}

In the above example, the last return false will never be executed, because a return statement has already been met in every possible execution path.

Loading history...
101
            ob_end_clean();
102
            throw $e;
103
        }
104
105
        $str = ob_get_contents();
106
        ob_end_clean();
107
108
        return $str;
109
    }
110
111
    /**
112
     * Get a mixed value of custom data and the parameters.
113
     *
114
     * @param  array $data
115
     * @param  mixed $param
116
     * @return array
117
     */
118
    public static function getMixedValue(array $data, $param)
119
    {
120
        $casted = self::castToArray($param);
121
122
        $data['model'] = $param;
123
124
        foreach ($data as $key => $value) {
125
            if (isset($casted[$key])) {
126
                $data[$key] = $casted[$key];
127
            }
128
        }
129
130
        return $data;
131
    }
132
133
    /**
134
     * Cast the parameter into an array.
135
     *
136
     * @param mixed $param
137
     * @return array
138
     */
139
    public static function castToArray($param)
140
    {
141
        if ($param instanceof \stdClass) {
142
            $param = (array) $param;
143
144
            return $param;
145
        }
146
147
        if ($param instanceof Arrayable) {
148
            return $param->toArray();
149
        }
150
151
        return $param;
152
    }
153
154
    /**
155
     * Get equivalent or method of query builder.
156
     *
157
     * @param string $method
158
     * @return string
159
     */
160
    public static function getOrMethod($method)
161
    {
162
        if (!Str::contains(Str::lower($method), 'or')) {
163
            return 'or' . ucfirst($method);
164
        }
165
166
        return $method;
167
    }
168
169
    /**
170
     * Wrap value depending on database type.
171
     *
172
     * @param string $database
173
     * @param string $value
174
     * @return string
175
     */
176
    public static function wrapDatabaseValue($database, $value)
177
    {
178
        $parts  = explode('.', $value);
179
        $column = '';
180
        foreach ($parts as $key) {
181
            $column = static::wrapDatabaseColumn($database, $key, $column);
182
        }
183
184
        return substr($column, 0, strlen($column) - 1);
185
    }
186
187
    /**
188
     * Database column wrapper.
189
     *
190
     * @param string $database
191
     * @param string $key
192
     * @param string $column
193
     * @return string
194
     */
195
    public static function wrapDatabaseColumn($database, $key, $column)
196
    {
197
        switch ($database) {
198
            case 'mysql':
199
                $column .= '`' . str_replace('`', '``', $key) . '`' . '.';
200
                break;
201
202
            case 'sqlsrv':
203
                $column .= '[' . str_replace(']', ']]', $key) . ']' . '.';
204
                break;
205
206
            case 'pgsql':
207
            case 'sqlite':
208
                $column .= '"' . str_replace('"', '""', $key) . '"' . '.';
209
                break;
210
211
            default:
212
                $column .= $key . '.';
213
        }
214
215
        return $column;
216
    }
217
218
    /**
219
     * Converts array object values to associative array.
220
     *
221
     * @param mixed $row
222
     * @return array
223
     */
224
    public static function convertToArray($row)
225
    {
226
        $data = $row instanceof Arrayable ? $row->toArray() : (array) $row;
227
        foreach (array_keys($data) as $key) {
228
            if (is_object($data[$key]) || is_array($data[$key])) {
229
                $data[$key] = self::convertToArray($data[$key]);
230
            }
231
        }
232
233
        return $data;
234
    }
235
236
    /**
237
     * @param array $data
238
     * @return array
239
     */
240
    public static function transform(array $data)
241
    {
242
        return array_map(function ($row) {
243
            return self::transformRow($row);
244
        }, $data);
245
    }
246
247
    /**
248
     * Transform row data into an array.
249
     *
250
     * @param mixed $row
251
     * @return array
252
     */
253
    protected static function transformRow($row)
254
    {
255
        foreach ($row as $key => $value) {
256
            if ($value instanceof DateTime) {
257
                $row[$key] = $value->format('Y-m-d H:i:s');
258
            } else {
259
                if (is_object($value)) {
260
                    $row[$key] = (string) $value;
261
                } else {
262
                    $row[$key] = $value;
263
                }
264
            }
265
        }
266
267
        return $row;
268
    }
269
270
    /**
271
     * Build parameters depending on # of arguments passed.
272
     *
273
     * @param array $args
274
     * @return array
275
     */
276
    public static function buildParameters(array $args)
277
    {
278
        $parameters = [];
279
280
        if (count($args) > 2) {
281
            $parameters[] = $args[0];
282
            foreach ($args[1] as $param) {
283
                $parameters[] = $param;
284
            }
285
        } else {
286
            foreach ($args[0] as $param) {
287
                $parameters[] = $param;
288
            }
289
        }
290
291
        return $parameters;
292
    }
293
294
    /**
295
     * Replace all pattern occurrences with keyword
296
     *
297
     * @param array  $subject
298
     * @param string $keyword
299
     * @param string $pattern
300
     * @return array
301
     */
302
    public static function replacePatternWithKeyword(array $subject, $keyword, $pattern = '$1')
303
    {
304
        $parameters = [];
305
        foreach ($subject as $param) {
306
            if (is_array($param)) {
307
                $parameters[] = self::replacePatternWithKeyword($param, $keyword, $pattern);
308
            } else {
309
                $parameters[] = str_replace($pattern, $keyword, $param);
310
            }
311
        }
312
313
        return $parameters;
314
    }
315
316
    /**
317
     * Get column name from string.
318
     *
319
     * @param string $str
320
     * @param bool   $wantsAlias
321
     * @return string
322
     */
323
    public static function extractColumnName($str, $wantsAlias)
324
    {
325
        $matches = explode(' as ', Str::lower($str));
326
327
        if (!empty($matches)) {
328
            if ($wantsAlias) {
329
                return array_pop($matches);
330
            } else {
331
                return array_shift($matches);
332
            }
333
        } elseif (strpos($str, '.')) {
334
            $array = explode('.', $str);
335
336
            return array_pop($array);
337
        }
338
339
        return $str;
340
    }
341
342
    /**
343
     * Adds % wildcards to the given string.
344
     *
345
     * @param string $str
346
     * @param bool   $lowercase
347
     * @return string
348
     */
349
    public static function wildcardLikeString($str, $lowercase = true)
350
    {
351
        $wild  = '%';
352
        $chars = preg_split('//u', $str, -1, PREG_SPLIT_NO_EMPTY);
353
354
        if (count($chars) > 0) {
355
            foreach ($chars as $char) {
356
                $wild .= $char . '%';
357
            }
358
        }
359
360
        if ($lowercase) {
361
            $wild = Str::lower($wild);
362
        }
363
364
        return $wild;
365
    }
366
}
367