1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
namespace Encore\Admin\Grid; |
4
|
|
|
|
5
|
|
|
use Closure; |
6
|
|
|
use Encore\Admin\Grid; |
7
|
|
|
use Illuminate\Support\Facades\URL; |
8
|
|
|
|
9
|
|
|
class Column |
10
|
|
|
{ |
11
|
|
|
/** |
12
|
|
|
* @var Grid |
13
|
|
|
*/ |
14
|
|
|
protected $grid; |
15
|
|
|
|
16
|
|
|
/** |
17
|
|
|
* Name of column. |
18
|
|
|
* |
19
|
|
|
* @var string |
20
|
|
|
*/ |
21
|
|
|
protected $name; |
22
|
|
|
|
23
|
|
|
/** |
24
|
|
|
* Label of column. |
25
|
|
|
* |
26
|
|
|
* @var string |
27
|
|
|
*/ |
28
|
|
|
protected $label; |
29
|
|
|
|
30
|
|
|
/** |
31
|
|
|
* Original value of column. |
32
|
|
|
* |
33
|
|
|
* @var mixed |
34
|
|
|
*/ |
35
|
|
|
protected $original; |
36
|
|
|
|
37
|
|
|
/** |
38
|
|
|
* Is column sortable. |
39
|
|
|
* |
40
|
|
|
* @var bool |
41
|
|
|
*/ |
42
|
|
|
protected $sortable = false; |
43
|
|
|
|
44
|
|
|
/** |
45
|
|
|
* Sort arguments. |
46
|
|
|
* |
47
|
|
|
* @var array |
48
|
|
|
*/ |
49
|
|
|
protected $sort; |
50
|
|
|
|
51
|
|
|
/** |
52
|
|
|
* Attributes of column. |
53
|
|
|
* |
54
|
|
|
* @var array |
55
|
|
|
*/ |
56
|
|
|
protected $attributes = []; |
57
|
|
|
|
58
|
|
|
/** |
59
|
|
|
* Value callback. |
60
|
|
|
* |
61
|
|
|
* @var \Closure |
62
|
|
|
*/ |
63
|
|
|
protected $valueCallback; |
64
|
|
|
|
65
|
|
|
/** |
66
|
|
|
* Html callback. |
67
|
|
|
* |
68
|
|
|
* @var array |
69
|
|
|
*/ |
70
|
|
|
protected $htmlCallbacks = []; |
71
|
|
|
|
72
|
|
|
/** |
73
|
|
|
* Relation name. |
74
|
|
|
* |
75
|
|
|
* @var bool |
76
|
|
|
*/ |
77
|
|
|
protected $relation = false; |
78
|
|
|
|
79
|
|
|
/** |
80
|
|
|
* Relation column. |
81
|
|
|
* |
82
|
|
|
* @var string |
83
|
|
|
*/ |
84
|
|
|
protected $relationColumn; |
85
|
|
|
|
86
|
|
|
/** |
87
|
|
|
* @param string $name |
88
|
|
|
* @param string $label |
89
|
|
|
*/ |
90
|
|
|
public function __construct($name, $label) |
91
|
|
|
{ |
92
|
|
|
$this->name = $name; |
93
|
|
|
|
94
|
|
|
$this->label = $this->formatLabel($label); |
95
|
|
|
} |
96
|
|
|
|
97
|
|
|
/** |
98
|
|
|
* @param Grid $grid |
99
|
|
|
*/ |
100
|
|
|
public function setGrid(Grid $grid) |
101
|
|
|
{ |
102
|
|
|
$this->grid = $grid; |
103
|
|
|
} |
104
|
|
|
|
105
|
|
|
/** |
106
|
|
|
* Get name of this column. |
107
|
|
|
* |
108
|
|
|
* @return mixed |
109
|
|
|
*/ |
110
|
|
|
public function getName() |
111
|
|
|
{ |
112
|
|
|
return $this->name; |
113
|
|
|
} |
114
|
|
|
|
115
|
|
|
/** |
116
|
|
|
* Format label. |
117
|
|
|
* |
118
|
|
|
* @param $label |
119
|
|
|
* |
120
|
|
|
* @return mixed |
121
|
|
|
*/ |
122
|
|
|
protected function formatLabel($label) |
123
|
|
|
{ |
124
|
|
|
$label = $label ?: ucfirst($this->name); |
125
|
|
|
|
126
|
|
|
return str_replace(['.', '_'], ' ', $label); |
127
|
|
|
} |
128
|
|
|
|
129
|
|
|
/** |
130
|
|
|
* Get label of the column. |
131
|
|
|
* |
132
|
|
|
* @return mixed |
133
|
|
|
*/ |
134
|
|
|
public function getLabel() |
135
|
|
|
{ |
136
|
|
|
return $this->label; |
137
|
|
|
} |
138
|
|
|
|
139
|
|
|
/** |
140
|
|
|
* Set relation. |
141
|
|
|
* |
142
|
|
|
* @param $relation |
143
|
|
|
* |
144
|
|
|
* @return $this |
145
|
|
|
*/ |
146
|
|
|
public function setRelation($relation) |
147
|
|
|
{ |
148
|
|
|
$this->relation = $relation; |
149
|
|
|
|
150
|
|
|
return $this; |
151
|
|
|
} |
152
|
|
|
|
153
|
|
|
/** |
154
|
|
|
* If this column is relation column. |
155
|
|
|
* |
156
|
|
|
* @return bool |
157
|
|
|
*/ |
158
|
|
|
protected function isRelation() |
159
|
|
|
{ |
160
|
|
|
return (bool) $this->relation; |
161
|
|
|
} |
162
|
|
|
|
163
|
|
|
/** |
164
|
|
|
* Mark this column as sortable. |
165
|
|
|
* |
166
|
|
|
* @return Column |
167
|
|
|
*/ |
168
|
|
|
public function sortable() |
169
|
|
|
{ |
170
|
|
|
$this->sortable = true; |
171
|
|
|
|
172
|
|
|
return $this; |
173
|
|
|
} |
174
|
|
|
|
175
|
|
|
/** |
176
|
|
|
* Wrap value with badge. |
177
|
|
|
* |
178
|
|
|
* @param string $style |
179
|
|
|
* |
180
|
|
|
* @return $this |
181
|
|
|
*/ |
182
|
|
|
public function badge($style = 'red') |
183
|
|
|
{ |
184
|
|
|
$callback = "<span class='badge bg-{$style}'>{value}</span>"; |
185
|
|
|
|
186
|
|
|
$this->htmlCallback($callback); |
187
|
|
|
|
188
|
|
|
return $this; |
189
|
|
|
} |
190
|
|
|
|
191
|
|
|
/** |
192
|
|
|
* Wrap value with label. |
193
|
|
|
* |
194
|
|
|
* @param string $style |
195
|
|
|
* |
196
|
|
|
* @return $this |
197
|
|
|
*/ |
198
|
|
|
public function label($style = 'success') |
199
|
|
|
{ |
200
|
|
|
$callback = "<span class='label label-{$style}'>{value}</span>"; |
201
|
|
|
|
202
|
|
|
$this->htmlCallback($callback); |
203
|
|
|
|
204
|
|
|
return $this; |
205
|
|
|
} |
206
|
|
|
|
207
|
|
|
/** |
208
|
|
|
* Wrap value as a link. |
209
|
|
|
* |
210
|
|
|
* @param $href |
211
|
|
|
* @param string $target |
212
|
|
|
* |
213
|
|
|
* @return $this |
214
|
|
|
*/ |
215
|
|
|
public function link($href = '', $target = '_blank') |
216
|
|
|
{ |
217
|
|
|
if (empty($href)) { |
218
|
|
|
$href = '{$value}'; |
219
|
|
|
} |
220
|
|
|
|
221
|
|
|
$callback = "<a href='$href' target='$target'>{value}</a>"; |
222
|
|
|
|
223
|
|
|
$this->htmlCallback($callback); |
224
|
|
|
|
225
|
|
|
return $this; |
226
|
|
|
} |
227
|
|
|
|
228
|
|
|
/** |
229
|
|
|
* Wrap value as a button. |
230
|
|
|
* |
231
|
|
|
* @param string $style |
232
|
|
|
* |
233
|
|
|
* @return $this |
234
|
|
|
*/ |
235
|
|
View Code Duplication |
public function button($style = 'default') |
|
|
|
|
236
|
|
|
{ |
237
|
|
|
if (is_array($style)) { |
238
|
|
|
$style = array_map(function ($style) { |
239
|
|
|
return 'btn-'.$style; |
240
|
|
|
}, $style); |
241
|
|
|
|
242
|
|
|
$style = implode(' ', $style); |
243
|
|
|
} elseif (is_string($style)) { |
244
|
|
|
$style = 'btn-'.$style; |
245
|
|
|
} |
246
|
|
|
|
247
|
|
|
$callback = "<span class='btn $style'>{value}</span>"; |
248
|
|
|
|
249
|
|
|
$this->htmlCallback($callback); |
250
|
|
|
|
251
|
|
|
return $this; |
252
|
|
|
} |
253
|
|
|
|
254
|
|
|
/** |
255
|
|
|
* Wrap value as a progressbar. |
256
|
|
|
* |
257
|
|
|
* @param string $style |
258
|
|
|
* @param string $size |
259
|
|
|
* @param int $max |
260
|
|
|
* |
261
|
|
|
* @return $this |
262
|
|
|
*/ |
263
|
|
View Code Duplication |
public function progressBar($style = 'primary', $size = 'sm', $max = 100) |
|
|
|
|
264
|
|
|
{ |
265
|
|
|
if (is_array($style)) { |
266
|
|
|
$style = array_map(function ($style) { |
267
|
|
|
return 'progress-bar-'.$style; |
268
|
|
|
}, $style); |
269
|
|
|
|
270
|
|
|
$style = implode(' ', $style); |
271
|
|
|
} elseif (is_string($style)) { |
272
|
|
|
$style = 'progress-bar-'.$style; |
273
|
|
|
} |
274
|
|
|
|
275
|
|
|
$callback = <<<EOT |
276
|
|
|
|
277
|
|
|
<div class="progress progress-$size"> |
278
|
|
|
<div class="progress-bar $style" role="progressbar" aria-valuenow="{value}" aria-valuemin="0" aria-valuemax="$max" style="width: {value}%"> |
279
|
|
|
<span class="sr-only">{value}</span> |
280
|
|
|
</div> |
281
|
|
|
</div> |
282
|
|
|
|
283
|
|
|
EOT; |
284
|
|
|
|
285
|
|
|
$this->htmlCallback($callback); |
286
|
|
|
|
287
|
|
|
return $this; |
288
|
|
|
} |
289
|
|
|
|
290
|
|
|
/** |
291
|
|
|
* Wrap value as a image. |
292
|
|
|
* |
293
|
|
|
* @param string $server |
294
|
|
|
* @param int $width |
295
|
|
|
* @param int $height |
296
|
|
|
* |
297
|
|
|
* @return $this |
298
|
|
|
*/ |
299
|
|
|
public function image($server = '', $width = 200, $height = 200) |
300
|
|
|
{ |
301
|
|
|
$server = $server ?: config('admin.upload.host'); |
302
|
|
|
|
303
|
|
|
$callback = "<img src='$server/{\$value}' style='max-width:{$width}px;max-height:{$height}px' class='img img-thumbnail' />"; |
304
|
|
|
|
305
|
|
|
$this->htmlCallback($callback); |
306
|
|
|
|
307
|
|
|
return $this; |
308
|
|
|
} |
309
|
|
|
|
310
|
|
|
/** |
311
|
|
|
* Make the column editable. |
312
|
|
|
* |
313
|
|
|
* @return $this |
314
|
|
|
*/ |
315
|
|
|
public function editable() |
316
|
|
|
{ |
317
|
|
|
$editable = new Editable($this->name, func_get_args()); |
318
|
|
|
$editable->setResource($this->grid->resource()); |
319
|
|
|
|
320
|
|
|
$this->htmlCallback($editable->html()); |
321
|
|
|
|
322
|
|
|
return $this; |
323
|
|
|
} |
324
|
|
|
|
325
|
|
|
/** |
326
|
|
|
* Add a value callback. |
327
|
|
|
* |
328
|
|
|
* @param callable $callable |
329
|
|
|
* |
330
|
|
|
* @return $this |
331
|
|
|
*/ |
332
|
|
|
public function value(Closure $callable) |
333
|
|
|
{ |
334
|
|
|
$this->valueCallback = $callable->bindTo($this); |
335
|
|
|
|
336
|
|
|
return $this; |
337
|
|
|
} |
338
|
|
|
|
339
|
|
|
/** |
340
|
|
|
* Alias for value method. |
341
|
|
|
* |
342
|
|
|
* @param callable $callable |
343
|
|
|
* |
344
|
|
|
* @return $this |
345
|
|
|
*/ |
346
|
|
|
public function display(Closure $callable) |
347
|
|
|
{ |
348
|
|
|
return $this->value($callable); |
349
|
|
|
} |
350
|
|
|
|
351
|
|
|
/** |
352
|
|
|
* If has a value callback. |
353
|
|
|
* |
354
|
|
|
* @return bool |
355
|
|
|
*/ |
356
|
|
|
protected function hasValueCallback() |
357
|
|
|
{ |
358
|
|
|
return (bool) $this->valueCallback; |
359
|
|
|
} |
360
|
|
|
|
361
|
|
|
/** |
362
|
|
|
* Set html callback. |
363
|
|
|
* |
364
|
|
|
* @param $callback |
365
|
|
|
*/ |
366
|
|
|
protected function htmlCallback($callback) |
367
|
|
|
{ |
368
|
|
|
$this->htmlCallbacks[] = $callback; |
369
|
|
|
} |
370
|
|
|
|
371
|
|
|
/** |
372
|
|
|
* If column has html callback. |
373
|
|
|
* |
374
|
|
|
* @return bool |
375
|
|
|
*/ |
376
|
|
|
protected function hasHtmlCallback() |
377
|
|
|
{ |
378
|
|
|
return !empty($this->htmlCallbacks); |
379
|
|
|
} |
380
|
|
|
|
381
|
|
|
/** |
382
|
|
|
* Wrap value with callback. |
383
|
|
|
* |
384
|
|
|
* @param $value |
385
|
|
|
* |
386
|
|
|
* @return mixed |
387
|
|
|
*/ |
388
|
|
|
protected function htmlWrap($value, $row = []) |
389
|
|
|
{ |
390
|
|
|
foreach ($this->htmlCallbacks as $callback) { |
391
|
|
|
$value = str_replace('{value}', $value, $callback); |
392
|
|
|
} |
393
|
|
|
|
394
|
|
|
$value = str_replace( |
395
|
|
|
'{$value}', |
396
|
|
|
is_null($this->original) ? 'NULL' : $this->htmlEntityEncode($this->original), |
397
|
|
|
$value |
398
|
|
|
); |
399
|
|
|
$value = str_replace('{pk}', array_get($row, $this->grid->getKeyName()), $value); |
400
|
|
|
|
401
|
|
|
return $value; |
402
|
|
|
} |
403
|
|
|
|
404
|
|
|
/** |
405
|
|
|
* Fill all data to every column. |
406
|
|
|
* |
407
|
|
|
* @param array $data |
408
|
|
|
* |
409
|
|
|
* @return mixed |
410
|
|
|
*/ |
411
|
|
|
public function fill(array $data) |
412
|
|
|
{ |
413
|
|
|
foreach ($data as &$item) { |
414
|
|
|
$this->original = $value = array_get($item, $this->name); |
415
|
|
|
|
416
|
|
|
$value = $this->htmlEntityEncode($value); |
417
|
|
|
|
418
|
|
|
array_set($item, $this->name, $value); |
419
|
|
|
|
420
|
|
|
if ($this->hasValueCallback()) { |
421
|
|
|
$value = call_user_func($this->valueCallback, $this->original); |
422
|
|
|
array_set($item, $this->name, $value); |
423
|
|
|
} |
424
|
|
|
|
425
|
|
|
if ($this->hasHtmlCallback()) { |
426
|
|
|
$value = $this->htmlWrap($value, $item); |
427
|
|
|
array_set($item, $this->name, $value); |
428
|
|
|
} |
429
|
|
|
} |
430
|
|
|
|
431
|
|
|
return $data; |
432
|
|
|
} |
433
|
|
|
|
434
|
|
|
/** |
435
|
|
|
* Convert characters to HTML entities recursively. |
436
|
|
|
* |
437
|
|
|
* @param array|string $item |
438
|
|
|
* |
439
|
|
|
* @return mixed |
440
|
|
|
*/ |
441
|
|
|
protected function htmlEntityEncode($item) |
442
|
|
|
{ |
443
|
|
|
if (is_array($item)) { |
444
|
|
|
array_walk_recursive($item, function (&$value) { |
445
|
|
|
$value = htmlentities($value); |
446
|
|
|
}); |
447
|
|
|
} else { |
448
|
|
|
$item = htmlentities($item); |
449
|
|
|
} |
450
|
|
|
|
451
|
|
|
return $item; |
452
|
|
|
} |
453
|
|
|
|
454
|
|
|
/** |
455
|
|
|
* Create the column sorter. |
456
|
|
|
* |
457
|
|
|
* @return string|void |
458
|
|
|
*/ |
459
|
|
|
public function sorter() |
460
|
|
|
{ |
461
|
|
|
if (!$this->sortable) { |
462
|
|
|
return; |
463
|
|
|
} |
464
|
|
|
|
465
|
|
|
$icon = 'fa-sort'; |
466
|
|
|
$type = 'desc'; |
467
|
|
|
|
468
|
|
|
if ($this->isSorted()) { |
469
|
|
|
$type = $this->sort['type'] == 'desc' ? 'asc' : 'desc'; |
470
|
|
|
$icon .= "-amount-{$this->sort['type']}"; |
471
|
|
|
} |
472
|
|
|
|
473
|
|
|
$query = app('request')->all(); |
474
|
|
|
$query = array_merge($query, [$this->grid->model()->getSortName() => ['column' => $this->name, 'type' => $type]]); |
475
|
|
|
|
476
|
|
|
$url = Url::current().'?'.http_build_query($query); |
477
|
|
|
|
478
|
|
|
return "<a class=\"fa fa-fw $icon\" href=\"$url\"></a>"; |
479
|
|
|
} |
480
|
|
|
|
481
|
|
|
/** |
482
|
|
|
* Determine if this column is currently sorted. |
483
|
|
|
* |
484
|
|
|
* @return bool |
485
|
|
|
*/ |
486
|
|
|
protected function isSorted() |
487
|
|
|
{ |
488
|
|
|
$this->sort = app('request')->get($this->grid->model()->getSortName()); |
489
|
|
|
|
490
|
|
|
if (empty($this->sort)) { |
491
|
|
|
return false; |
492
|
|
|
} |
493
|
|
|
|
494
|
|
|
return isset($this->sort['column']) && $this->sort['column'] == $this->name; |
495
|
|
|
} |
496
|
|
|
|
497
|
|
|
/** |
498
|
|
|
* @param string $method |
499
|
|
|
* @param array $arguments |
500
|
|
|
* |
501
|
|
|
* @return $this |
502
|
|
|
*/ |
503
|
|
|
public function __call($method, $arguments) |
504
|
|
|
{ |
505
|
|
|
if ($this->isRelation()) { |
506
|
|
|
$this->name = "{$this->relation}.$method"; |
507
|
|
|
$this->label = isset($arguments[0]) ? $arguments[0] : ucfirst($method); |
508
|
|
|
|
509
|
|
|
$this->relationColumn = $method; |
510
|
|
|
|
511
|
|
|
return $this; |
512
|
|
|
} |
513
|
|
|
} |
514
|
|
|
} |
515
|
|
|
|
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.
You can also find more detailed suggestions in the “Code” section of your repository.