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
|
|
|
class Helper |
12
|
|
|
{ |
13
|
|
|
/** |
14
|
|
|
* Places item of extra columns into results by care of their order. |
15
|
|
|
* |
16
|
|
|
* @param $item |
17
|
|
|
* @param $array |
18
|
|
|
* @return array |
19
|
|
|
*/ |
20
|
|
|
public static function includeInArray($item, $array) |
21
|
|
|
{ |
22
|
|
|
if (self::isItemOrderInvalid($item, $array)) { |
23
|
|
|
return array_merge($array, [$item['name'] => $item['content']]); |
24
|
|
|
} else { |
25
|
|
|
$count = 0; |
26
|
|
|
$last = $array; |
27
|
|
|
$first = []; |
28
|
|
|
foreach ($array as $key => $value) { |
29
|
|
|
if ($count == $item['order']) { |
30
|
|
|
return array_merge($first, [$item['name'] => $item['content']], $last); |
31
|
|
|
} |
32
|
|
|
|
33
|
|
|
unset($last[$key]); |
34
|
|
|
$first[$key] = $value; |
35
|
|
|
|
36
|
|
|
$count++; |
37
|
|
|
} |
38
|
|
|
} |
39
|
|
|
} |
40
|
|
|
|
41
|
|
|
/** |
42
|
|
|
* Check if item order is valid. |
43
|
|
|
* |
44
|
|
|
* @param array $item |
45
|
|
|
* @param array $array |
46
|
|
|
* @return bool |
47
|
|
|
*/ |
48
|
|
|
protected static function isItemOrderInvalid($item, $array) |
49
|
|
|
{ |
50
|
|
|
return $item['order'] === false || $item['order'] >= count($array); |
51
|
|
|
} |
52
|
|
|
|
53
|
|
|
/** |
54
|
|
|
* Determines if content is callable or blade string, processes and returns. |
55
|
|
|
* |
56
|
|
|
* @param string|callable $content Pre-processed content |
57
|
|
|
* @param array $data data to use with blade template |
58
|
|
|
* @param mixed $param parameter to call with callable |
59
|
|
|
* @return string Processed content |
60
|
|
|
*/ |
61
|
|
|
public static function compileContent($content, array $data, $param) |
62
|
|
|
{ |
63
|
|
|
if (is_string($content)) { |
64
|
|
|
return static::compileBlade($content, static::getMixedValue($data, $param)); |
65
|
|
|
} elseif (is_callable($content)) { |
66
|
|
|
return $content($param); |
67
|
|
|
} |
68
|
|
|
|
69
|
|
|
return $content; |
70
|
|
|
} |
71
|
|
|
|
72
|
|
|
/** |
73
|
|
|
* Parses and compiles strings by using Blade Template System. |
74
|
|
|
* |
75
|
|
|
* @param string $str |
76
|
|
|
* @param array $data |
77
|
|
|
* @return string |
78
|
|
|
* @throws \Exception |
79
|
|
|
*/ |
80
|
|
|
public static function compileBlade($str, $data = []) |
81
|
|
|
{ |
82
|
|
|
if (view()->exists($str)) { |
83
|
|
|
return view($str, $data)->render(); |
84
|
|
|
} |
85
|
|
|
|
86
|
|
|
$empty_filesystem_instance = new Filesystem(); |
87
|
|
|
$blade = new BladeCompiler($empty_filesystem_instance, 'datatables'); |
88
|
|
|
$parsed_string = $blade->compileString($str); |
89
|
|
|
|
90
|
|
|
ob_start() && extract($data, EXTR_SKIP); |
91
|
|
|
|
92
|
|
|
try { |
93
|
|
|
eval('?>' . $parsed_string); |
|
|
|
|
94
|
|
|
} catch (\Exception $e) { |
|
|
|
|
95
|
|
|
ob_end_clean(); |
96
|
|
|
throw $e; |
97
|
|
|
} |
98
|
|
|
|
99
|
|
|
$str = ob_get_contents(); |
100
|
|
|
ob_end_clean(); |
101
|
|
|
|
102
|
|
|
return $str; |
103
|
|
|
} |
104
|
|
|
|
105
|
|
|
/** |
106
|
|
|
* @param array $data |
107
|
|
|
* @param mixed $param |
108
|
|
|
* @return array |
109
|
|
|
*/ |
110
|
|
|
public static function getMixedValue(array $data, $param) |
111
|
|
|
{ |
112
|
|
|
$param = self::castToArray($param); |
113
|
|
|
|
114
|
|
|
foreach ($data as $key => $value) { |
115
|
|
|
if (isset($param[$key])) { |
116
|
|
|
$data[$key] = $param[$key]; |
117
|
|
|
} |
118
|
|
|
} |
119
|
|
|
|
120
|
|
|
return $data; |
121
|
|
|
} |
122
|
|
|
|
123
|
|
|
/** |
124
|
|
|
* @param $param |
125
|
|
|
* @return array |
126
|
|
|
*/ |
127
|
|
|
public static function castToArray($param) |
128
|
|
|
{ |
129
|
|
|
if ($param instanceof \stdClass) { |
130
|
|
|
$param = (array) $param; |
131
|
|
|
|
132
|
|
|
return $param; |
133
|
|
|
} |
134
|
|
|
|
135
|
|
|
return $param; |
136
|
|
|
} |
137
|
|
|
|
138
|
|
|
/** |
139
|
|
|
* Get equivalent or method of query builder. |
140
|
|
|
* |
141
|
|
|
* @param string $method |
142
|
|
|
* @return string |
143
|
|
|
*/ |
144
|
|
|
public static function getOrMethod($method) |
145
|
|
|
{ |
146
|
|
|
if (! Str::contains(Str::lower($method), 'or')) { |
147
|
|
|
return 'or' . ucfirst($method); |
148
|
|
|
} |
149
|
|
|
|
150
|
|
|
return $method; |
151
|
|
|
} |
152
|
|
|
|
153
|
|
|
/** |
154
|
|
|
* Wrap value depending on database type. |
155
|
|
|
* |
156
|
|
|
* @param string $database |
157
|
|
|
* @param string $value |
158
|
|
|
* @return string |
159
|
|
|
*/ |
160
|
|
|
public static function wrapDatabaseValue($database, $value) |
161
|
|
|
{ |
162
|
|
|
$parts = explode('.', $value); |
163
|
|
|
$column = ''; |
164
|
|
|
foreach ($parts as $key) { |
165
|
|
|
$column = static::wrapDatabaseColumn($database, $key, $column); |
166
|
|
|
} |
167
|
|
|
|
168
|
|
|
return substr($column, 0, strlen($column) - 1); |
169
|
|
|
} |
170
|
|
|
|
171
|
|
|
/** |
172
|
|
|
* Database column wrapper |
173
|
|
|
* |
174
|
|
|
* @param string $database |
175
|
|
|
* @param string $key |
176
|
|
|
* @param string $column |
177
|
|
|
* @return string |
178
|
|
|
*/ |
179
|
|
|
public static function wrapDatabaseColumn($database, $key, $column) |
180
|
|
|
{ |
181
|
|
|
switch ($database) { |
182
|
|
|
case 'mysql': |
183
|
|
|
$column .= '`' . str_replace('`', '``', $key) . '`' . '.'; |
184
|
|
|
break; |
185
|
|
|
|
186
|
|
|
case 'sqlsrv': |
187
|
|
|
$column .= '[' . str_replace(']', ']]', $key) . ']' . '.'; |
188
|
|
|
break; |
189
|
|
|
|
190
|
|
|
case 'pgsql': |
191
|
|
|
case 'sqlite': |
192
|
|
|
$column .= '"' . str_replace('"', '""', $key) . '"' . '.'; |
193
|
|
|
break; |
194
|
|
|
|
195
|
|
|
default: |
196
|
|
|
$column .= $key . '.'; |
197
|
|
|
} |
198
|
|
|
|
199
|
|
|
return $column; |
200
|
|
|
} |
201
|
|
|
|
202
|
|
|
/** |
203
|
|
|
* Converts array object values to associative array. |
204
|
|
|
* |
205
|
|
|
* @param mixed $row |
206
|
|
|
* @return array |
207
|
|
|
*/ |
208
|
|
|
public static function convertToArray($row) |
209
|
|
|
{ |
210
|
|
|
$data = $row instanceof Arrayable ? $row->toArray() : (array) $row; |
211
|
|
|
foreach (array_keys($data) as $key) { |
212
|
|
|
if (is_object($data[$key]) || is_array($data[$key])) { |
213
|
|
|
$data[$key] = self::convertToArray($data[$key]); |
214
|
|
|
} |
215
|
|
|
} |
216
|
|
|
|
217
|
|
|
return $data; |
218
|
|
|
} |
219
|
|
|
|
220
|
|
|
/** |
221
|
|
|
* @param array $data |
222
|
|
|
* @return array |
223
|
|
|
*/ |
224
|
|
|
public static function transform(array $data) |
225
|
|
|
{ |
226
|
|
|
return array_map(function ($row) { |
227
|
|
|
return self::transformRow($row); |
228
|
|
|
}, $data); |
229
|
|
|
} |
230
|
|
|
|
231
|
|
|
/** |
232
|
|
|
* @param $row |
233
|
|
|
* @return mixed |
234
|
|
|
*/ |
235
|
|
|
protected static function transformRow($row) |
236
|
|
|
{ |
237
|
|
|
foreach ($row as $key => $value) { |
238
|
|
|
if ($value instanceof DateTime) { |
239
|
|
|
$row[$key] = $value->format('Y-m-d H:i:s'); |
240
|
|
|
} else { |
241
|
|
|
if (is_string($value)) { |
242
|
|
|
$row[$key] = (string) $value; |
243
|
|
|
} else { |
244
|
|
|
$row[$key] = $value; |
245
|
|
|
} |
246
|
|
|
} |
247
|
|
|
} |
248
|
|
|
|
249
|
|
|
return $row; |
250
|
|
|
} |
251
|
|
|
|
252
|
|
|
/** |
253
|
|
|
* Build parameters depending on # of arguments passed. |
254
|
|
|
* |
255
|
|
|
* @param array $args |
256
|
|
|
* @return array |
257
|
|
|
*/ |
258
|
|
|
public static function buildParameters(array $args) |
259
|
|
|
{ |
260
|
|
|
$parameters = []; |
261
|
|
|
|
262
|
|
|
if (count($args) > 2) { |
263
|
|
|
$parameters[] = $args[0]; |
264
|
|
|
foreach ($args[1] as $param) { |
265
|
|
|
$parameters[] = $param; |
266
|
|
|
} |
267
|
|
|
} else { |
268
|
|
|
foreach ($args[0] as $param) { |
269
|
|
|
$parameters[] = $param; |
270
|
|
|
} |
271
|
|
|
} |
272
|
|
|
|
273
|
|
|
return $parameters; |
274
|
|
|
} |
275
|
|
|
|
276
|
|
|
/** |
277
|
|
|
* Replace all pattern occurrences with keyword |
278
|
|
|
* |
279
|
|
|
* @param array $subject |
280
|
|
|
* @param string $keyword |
281
|
|
|
* @param string $pattern |
282
|
|
|
* @return array |
283
|
|
|
*/ |
284
|
|
|
public static function replacePatternWithKeyword(array $subject, $keyword, $pattern = '$1') |
285
|
|
|
{ |
286
|
|
|
$parameters = []; |
287
|
|
|
foreach ($subject as $param) { |
288
|
|
|
if (is_array($param)) { |
289
|
|
|
$parameters[] = self::replacePatternWithKeyword($param, $keyword, $pattern); |
290
|
|
|
} else { |
291
|
|
|
$parameters[] = str_replace($pattern, $keyword, $param); |
292
|
|
|
} |
293
|
|
|
} |
294
|
|
|
|
295
|
|
|
return $parameters; |
296
|
|
|
} |
297
|
|
|
} |
298
|
|
|
|
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.