Completed
Push — master ( 7890f3...cc2256 )
by Arjay
01:49
created

Helper::wrapDatabaseValue()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 10
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

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