Issues (17)

Security Analysis    not enabled

This project does not seem to handle request data directly as such no vulnerable execution paths were found.

  Cross-Site Scripting
Cross-Site Scripting enables an attacker to inject code into the response of a web-request that is viewed by other users. It can for example be used to bypass access controls, or even to take over other users' accounts.
  File Exposure
File Exposure allows an attacker to gain access to local files that he should not be able to access. These files can for example include database credentials, or other configuration files.
  File Manipulation
File Manipulation enables an attacker to write custom data to files. This potentially leads to injection of arbitrary code on the server.
  Object Injection
Object Injection enables an attacker to inject an object into PHP code, and can lead to arbitrary code execution, file exposure, or file manipulation attacks.
  Code Injection
Code Injection enables an attacker to execute arbitrary code on the server.
  Response Splitting
Response Splitting can be used to send arbitrary responses.
  File Inclusion
File Inclusion enables an attacker to inject custom files into PHP's file loading mechanism, either explicitly passed to include, or for example via PHP's auto-loading mechanism.
  Command Injection
Command Injection enables an attacker to inject a shell command that is execute with the privileges of the web-server. This can be used to expose sensitive data, or gain access of your server.
  SQL Injection
SQL Injection enables an attacker to execute arbitrary SQL code on your database server gaining access to user data, or manipulating user data.
  XPath Injection
XPath Injection enables an attacker to modify the parts of XML document that are read. If that XML document is for example used for authentication, this can lead to further vulnerabilities similar to SQL Injection.
  LDAP Injection
LDAP Injection enables an attacker to inject LDAP statements potentially granting permission to run unauthorized queries, or modify content inside the LDAP tree.
  Header Injection
  Other Vulnerability
This category comprises other attack vectors such as manipulating the PHP runtime, loading custom extensions, freezing the runtime, or similar.
  Regex Injection
Regex Injection enables an attacker to execute arbitrary code in your PHP process.
  XML Injection
XML Injection enables an attacker to read files on your local filesystem including configuration files, or can be abused to freeze your web-server process.
  Variable Injection
Variable Injection enables an attacker to overwrite program variables with custom data, and can lead to further vulnerabilities.
Unfortunately, the security analysis is currently not available for your project. If you are a non-commercial open-source project, please contact support to gain access.

src/CrudController.php (2 issues)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php
2
3
namespace Eliurkis\Crud;
4
5
use App\Http\Controllers\Controller;
6
use DB;
7
use Illuminate\Database\Eloquent\Builder;
8
use Illuminate\Database\Eloquent\ModelNotFoundException;
9
use Illuminate\Database\QueryException;
10
use Illuminate\Http\Request;
11
use Illuminate\Support\Carbon;
12
use Illuminate\Support\Facades\Route;
13
14
class CrudController extends Controller
15
{
16
    protected $route;
17
    protected $entity;
18
    protected $entityInstance = null;
19
    protected $fields = [];
20
    protected $columns = [];
21
    protected $buttons = [
22
        'show',
23
        'create',
24
        'edit',
25
        'delete',
26
    ];
27
    protected $paginate = null;
28
    protected $searchable = [];
29
    protected $filters = [];
30
    protected $queryFilters = [];
31
    protected $orderBy = [];
32
    protected $orderByRaw = null;
33
    protected $filterRequire = [];
34
    protected $textsGeneral = [
35
        'list_title'   => 'Contents',
36
        'create_title' => '',
37
        'edit_title'   => '',
38
    ];
39
    protected $texts = [];
40
    protected $htmlFilters = [];
41
    protected $action = null;
42
    protected $formColsClasses = [
43
        'col-md-10 col-md-offset-1',
44
        'col-md-2',
45
        'col-md-10',
46
    ];
47
    protected $formCols = [
48
        'show'   => 2,
49
        'create' => 2,
50
        'edit'   => 2,
51
    ];
52
    protected $links = [];
53
    protected $listDisplay = [
54
        'action-buttons' => true,
55
    ];
56
    protected $actions = [];
57
58
    public function __construct($entity, $config = [])
59
    {
60
        $this->entity = $entity;
61
62
        $config = count($config) ? $config : config('crud.'.$this->route);
63
64
        if (is_array($config)) {
65
            foreach ($config as $key => $value) {
66
                $this->$key = $value;
67
            }
68
        }
69
70
        $this->actions = [
71
            'details' => function ($row, $route) {
72
                return '<a href="'.route($route.'.show', $row->{$row->getKeyName()}).'" class="btn-default btn btn-xs">
73
                            <i class="fas fa-eye"></i>
74
                        </a>';
75
            },
76
            'edit'    => function ($row, $route) {
77
                return '<a href="'.route($route.'.edit', $row->{$row->getKeyName()}).'" class="btn-primary btn btn-xs edit_element">
78
                            <i class="far fa-edit"></i>
79
                        </a>';
80
            },
81
            'delete'  => function ($row, $route) {
82
                return '<a href="'.route($route.'.destroy', $row->{$row->getKeyName()}).'"
83
                           class="btn-danger btn btn-xs delete_element"
84
                           onclick="return confirm(\''.trans('eliurkis::crud.confirmation_delete').'\');">
85
                            <i class="far fa-trash-alt"></i>
86
                        </a>';
87
            },
88
        ];
89
    }
90
91
    public function index(Request $request)
92
    {
93
        // If DataTable is activated
94
        if (isset($this->dataTableActivated)) {
95
            return $this->indexDataTable($request);
96
        }
97
98
        $entity = $this->entity;
99
100
        // Relation Fields
101
        if ($belongToFields = $this->getBelongToFields()) {
102
            $entity = $this->entity->with($belongToFields);
103
        }
104
105
        // Filters
106
        $entity = $this->filters($entity, $request);
107
108
        // Search
109
        $entity = $this->search($entity, $request);
110
111
        // Order By
112
        if (!empty($this->orderBy)) {
113
            foreach ($this->orderBy as $column => $direction) {
114
                $entity = $entity->orderBy($column, $direction);
115
            }
116
        }
117
118
        if ($this->orderByRaw) {
119
            $entity = $entity->orderByRaw($this->orderByRaw);
120
        }
121
122
        // Pagination
123
        $rows = $this->paginate > 0 ? $this->paginate($entity, $request) : $entity->get();
124
125
        // Sort By Rows
126
        if (!empty($this->sortBy)) {
127
            foreach ($this->sortBy as $column => $direction) {
128
                $rows = strtolower($direction) == 'desc'
129
                    ? $rows->sortByDesc($column)
130
                    : $rows->sortBy($column);
131
            }
132
        }
133
134
        // HTML Filters
135
        $this->htmlFilters();
136
137
        return view('crud::list', compact('rows'))
138
            ->with('fields', $this->fields)
139
            ->with('columns', $this->columns)
140
            ->with('searchable', $this->searchable)
141
            ->with('buttons', $this->buttons)
142
            ->with('paginate', $this->paginate)
143
            ->with('t', $this->texts)
144
            ->with('htmlFilters', $this->htmlFilters)
145
            ->with('listDisplay', $this->listDisplay)
146
            ->with('links', $this->prepareLinks())
147
            ->with('request', $request)
148
            ->with('actions', $this->actions)
149
            ->with('route', $this->route);
150
    }
151
152 View Code Duplication
    public function show($id)
0 ignored issues
show
This method seems to be duplicated in your project.

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.

Loading history...
153
    {
154
        if (!$this->entityInstance) {
155
            $this->entityInstance = $this->entity->findOrFail($id);
156
        }
157
158
        $this->prepareFields();
159
160
        return view('crud::show')
161
            ->with('type', 'show')
162
            ->with('route', $this->route)
163
            ->with('t', $this->texts)
164
            ->with('formColsClasses', $this->formColsClasses)
165
            ->with('colsNumber', $this->formCols['show'])
166
            ->with('fieldsGroup', collect($this->fields)->split($this->formCols['show']))
167
            ->with('fields', $this->fields)
168
            ->with('data', $this->entityInstance);
169
    }
170
171
    public function create()
172
    {
173
        $this->prepareFields();
174
175
        return view('crud::create')
176
            ->with('type', 'create')
177
            ->with('route', $this->route)
178
            ->with('t', $this->texts)
179
            ->with('formColsClasses', $this->formColsClasses)
180
            ->with('links', $this->prepareLinks())
181
            ->with('colsNumber', $this->formCols['create'])
182
            ->with('fieldsGroup', collect($this->fields)->split($this->formCols['create']))
183
            ->with('fields', $this->fields);
184
    }
185
186
    protected function manageFiles($row, $request)
187
    {
188
        $mediaFiles = [];
189
190
        foreach ($this->fields as $fieldName => $field) {
191
            if (substr($field['type'], 0, 4) === 'file' && $request->file($fieldName)) {
192
                $customProperties = ['route' => $this->route, 'field' => $fieldName];
193
                if (isset($field['storage_path'])) {
194
                    $customProperties['storage_path'] = $field['storage_path'];
195
                }
196
                $mediaFiles[] = $row->addMedia($request->file($fieldName))
197
                    ->withCustomProperties($customProperties)
198
                    ->toMediaCollection($fieldName);
199
            }
200
        }
201
202
        return $mediaFiles;
203
    }
204
205
    public function store(Request $request)
206
    {
207
        $this->validateRequest($request, 'store');
208
209
        DB::beginTransaction();
210
211
        try {
212
            $row = $this->entity->create(array_merge($request->all(), $this->queryFilters));
213
            $this->updateForeignRelations($row, $request);
214
            $mediaFiles = $this->manageFiles($row, $request);
215
        } catch (QueryException $e) {
216
            \Log::error($e);
217
            if (config('app.debug')) {
218
                throw new \Exception($e);
219
            }
220
221
            return redirect()
222
                ->back()
223
                ->with('error', 'Ha ocurrido un error, intente nuevamente');
224
        }
225
226
        DB::commit();
227
228
        event($this->route.'.store', [$row, $mediaFiles]);
229
230
        return redirect()
231
            ->route($this->route.'.index')
232
            ->with('success', isset($this->textsGeneral['save_action'])
233
                ? $this->textsGeneral['save_action']
234
                : trans('eliurkis::crud.save_action'));
235
    }
236
237 View Code Duplication
    public function edit($id)
0 ignored issues
show
This method seems to be duplicated in your project.

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.

Loading history...
238
    {
239
        if (!$this->entityInstance) {
240
            $this->entityInstance = $this->entity->findOrFail($id);
241
        }
242
243
        $this->prepareFields();
244
245
        return view('crud::create')
246
            ->with('type', 'edit')
247
            ->with('route', $this->route)
248
            ->with('t', $this->texts)
249
            ->with('formColsClasses', $this->formColsClasses)
250
            ->with('links', $this->prepareLinks())
251
            ->with('colsNumber', $this->formCols['edit'])
252
            ->with('fieldsGroup', collect($this->fields)->split($this->formCols['edit']))
253
            ->with('fields', $this->fields)
254
            ->with('data', $this->entityInstance);
255
    }
256
257
    public function update(Request $request, $id)
258
    {
259
        $this->validateRequest($request, 'update');
260
261
        DB::beginTransaction();
262
263
        try {
264
            $row = $this->entity->findOrFail($id);
265
            $row->update(
266
                array_merge(
267
                    $request->all(),
268
                    $this->queryFilters
269
                )
270
            );
271
            $this->updateForeignRelations($row, $request);
272
            $mediaFiles = $this->manageFiles($row, $request);
273
        } catch (QueryException $e) {
274
            \Log::error($e);
275
            if (config('app.debug')) {
276
                throw new \Exception($e);
277
            }
278
279
            return redirect()
280
                ->back()
281
                ->with('error', 'Ha ocurrido un error, intente nuevamente');
282
        }
283
284
        DB::commit();
285
286
        event($this->route.'.update', [$row, $mediaFiles]);
287
288
        return redirect()
289
            ->route($this->route.'.index', $this->getParamsFilters($row))
290
            ->with('success', isset($this->textsGeneral['save_action'])
291
                ? $this->textsGeneral['save_action']
292
                : trans('eliurkis::crud.save_action'));
293
    }
294
295
    public function destroy($id)
296
    {
297
        try {
298
            $row = $this->entity->findOrFail($id);
299
            $row->delete();
300
301
            event($this->route.'.destroy', [$row]);
302
        } catch (ModelNotFoundException $e) {
303
            return redirect()
304
                ->route($this->route.'.index')
305
                ->with('error', __('The element that you are trying to delete does not exist'));
306
        } catch (\Exception $e) {
307
            \Log::error($e);
308
            if (config('app.debug')) {
309
                throw new \Exception($e);
310
            }
311
312
            return redirect()
313
                ->route($this->route.'.index')
314
                ->with('error', __('An error occurred, try again'));
315
        }
316
317
        return redirect()
318
            ->route($this->route.'.index')
319
            ->with('success', isset($this->textsGeneral['delete_action'])
320
                ? $this->textsGeneral['delete_action']
321
                : trans('eliurkis::crud.delete_action'));
322
    }
323
324
    public function download($id, $fieldName)
325
    {
326
        if (!$this->entityInstance) {
327
            $this->entityInstance = $this->entity->findOrFail($id);
328
        }
329
330
        $media = $this->entityInstance->getMedia($fieldName)->last();
331
332
        if ($media && $media->disk === 's3') {
333
            $tempImage = tempnam(sys_get_temp_dir(), $media->file_name);
334
            copy($media->getTemporaryUrl(\Carbon::now()->addMinutes(5)), $tempImage);
335
336
            return response()->file($tempImage, ['Content-Type' => $media->mime_type]);
337
        }
338
339
        return $media;
340
    }
341
342
    /* Private Actions */
343
344
    /**
345
     * @param         $entity
346
     * @param Request $request
347
     *
348
     * @return mixed
349
     */
350
    protected function filters($entity, $request)
351
    {
352
        if ($request->query('filter')) {
353
            $filters = is_array($request->query('filter')) ? $request->query('filter') : [];
354
            foreach ($filters as $field => $value) {
355
                $entity = $entity->where($field, $value);
356
            }
357
        }
358
359
        if (count($this->queryFilters)) {
360
            foreach ($this->queryFilters as $field => $value) {
361
                if (is_array($value)) {
362
                    $entity = $entity->whereIn($field, $value);
363
                } else {
364
                    $entity = $entity->where($field, $value);
365
                }
366
            }
367
        }
368
369
        return $entity;
370
    }
371
372
    protected function htmlFilters()
373
    {
374
        $this->htmlFilters = [];
375
        if (count($this->filters)) {
376
            foreach ($this->filters as $filter) {
377
                // Build params
378
                $urlParams = \Input::query();
379
380
                // Default Value
381
                $this->fields[$filter]['config']['default_value'] = isset($urlParams['filter'][$filter])
382
                    ? $urlParams['filter'][$filter]
383
                    : null;
384
385
                // Create URL
386
                if (isset($urlParams['filter'][$filter])) {
387
                    unset($urlParams['filter'][$filter]);
388
                }
389
                $this->fields[$filter]['attributes']['data-filter-url'] = route($this->route.'.index', $urlParams)
390
                    .(count($urlParams) ? '&' : '?');
391
392
                // Create array
393
                $this->action = 'list';
394
                $this->htmlFilters[$filter] = $this->prepareField($filter);
395
            }
396
        }
397
    }
398
399
    /**
400
     * @param         $entity
401
     * @param Request $request
402
     *
403
     * @return mixed
404
     */
405
    protected function paginate($entity, $request)
406
    {
407
        $rows = $entity->paginate($this->paginate);
408
409
        if ($request->get('q') != '') {
410
            $rows->appends(['q' => $request->get('q')]);
411
        }
412
413
        if ($request->get('filter')) {
414
            foreach ($request->get('filter') as $field => $value) {
415
                $rows->appends(['filter['.$field.']' => $value]);
416
            }
417
        }
418
419
        return $rows;
420
    }
421
422
    /**
423
     * @param         $entity
424
     * @param Request $request
425
     *
426
     * @return mixed
427
     */
428
    protected function search($entity, $request)
429
    {
430
        if ($request->get('q') != '') {
431
            $searchableCols = isset($this->searchable['columns']) ? $this->searchable['columns'] : $this->searchable;
432
433
            $entity = $entity->where(function (Builder $query) use ($request, $searchableCols) {
434
                foreach ($searchableCols as $field) {
435
                    $query->orWhere($field, 'like', '%'.$request->get('q').'%');
436
                }
437
            });
438
439
            if (isset($this->searchable['joins'])) {
440
                foreach ($this->searchable['joins'] as $table => $joinFields) {
441
                    $entity = $entity->join($table, $joinFields[0], '=', $joinFields[1]);
442
                }
443
            }
444
        }
445
446
        return $entity;
447
    }
448
449
    protected function getForeignRelationsFields()
450
    {
451
        $foreignRelations = [];
452
        foreach ($this->fields as $field => $options) {
453
            if ($options['type'] === 'foreign') {
454
                $foreignRelations[] = $field;
455
            }
456
        }
457
458
        return $foreignRelations;
459
    }
460
461
    protected function getBelongToFields()
462
    {
463
        $fields = [];
464
        foreach ($this->fields as $field => $options) {
465
            if ($options['type'] === 'select' && isset($options['config']['rel'])) {
466
                $fields[] = $options['config']['rel'];
467
            }
468
        }
469
470
        return $fields;
471
    }
472
473
    /**
474
     * @param object  $row
475
     * @param Request $request
476
     */
477
    protected function updateForeignRelations($row, $request)
478
    {
479
        $foreignRelations = $this->getForeignRelationsFields();
480
481
        foreach ($foreignRelations as $foreignRelation) {
482
            $values = $request->get($foreignRelation);
483
            $row->$foreignRelation()->sync((array) $values);
484
        }
485
    }
486
487
    protected function getParamsFilters($row)
488
    {
489
        $params = [];
490
491
        if (count($this->filterRequire)) {
492
            $params['filter'] = [];
493
494
            foreach ($this->filterRequire as $field) {
495
                $params['filter'][$field] = $row->$field;
496
            }
497
        }
498
499
        return $params;
500
    }
501
502
    protected function prepareLinks()
503
    {
504
        $links = ['index', 'create', 'store'];
505
506
        foreach ($links as $link) {
507
            if (!isset($this->links[$link]) && Route::has($this->route.'.'.$link)) {
508
                $this->links[$link] = route($this->route.'.'.$link);
509
            }
510
        }
511
512
        return $this->links;
513
    }
514
515
    /**
516
     * @param Request $request
517
     * @param         $type
518
     */
519
    protected function validateRequest($request, $type)
520
    {
521
        $validations = [
522
            'rules'            => [],
523
            'messages'         => [],
524
            'customAttributes' => [],
525
        ];
526
527
        foreach ($this->fields as $field => $options) {
528
            $validation = null;
529
            if (isset($options['validation'][$type])) {
530
                $validation = $options['validation'][$type];
531
            } elseif (isset($options['validation']) && is_string($options['validation'])) {
532
                $validation = $options['validation'];
533
            }
534
535
            if ($validation != '') {
536
                $validations['rules'][$field] = $validation;
537
                $validations['customAttributes'][$field] = $options['label'];
538
            }
539
        }
540
541
        if ($validations['rules']) {
542
            $this->validate(
543
                $request,
544
                $validations['rules'],
545
                $validations['messages'],
546
                $validations['customAttributes']
547
            );
548
        }
549
    }
550
551
    protected function prepareRelationalFields($name)
552
    {
553
        // Default values
554
        $config = isset($this->fields[$name]['config']) ? $this->fields[$name]['config'] : [];
555
        $config['options'] = isset($config['options']) ? $config['options'] : [];
556
        $config['cols'] = isset($config['cols']) ? $config['cols'] : 1;
557
558
        // Get foreign values
559
        if (!count($config['options']) && isset($config['entity'])) {
560
            $config['options'] = $config['entity']::get()
561
                ->pluck($config['field_value'], $config['field_key'])
562
                ->toArray();
563
        }
564
565
        // No selection for filters
566
        if ($this->action == 'list' && isset($config['filter_no_selection'])) {
567
            $config['options'] = array_merge([
568
                '-1' => $config['filter_no_selection'],
569
            ], $config['options']);
570
        }
571
572
        if (isset($config['pre_options'])) {
573
            $config['options'] = $config['pre_options'] + $config['options'];
574
        }
575
576
        $this->fields[$name]['config'] = $config;
577
578
        return $this->fields[$name];
579
    }
580
581
    protected function prepareFields()
582
    {
583
        if ($this->entityInstance) {
584
            \Form::model($this->entityInstance);
585
        }
586
587
        foreach ($this->fields as $name => $properties) {
588
            $this->fields[$name]['html'] = $this->prepareField($name, $properties);
589
            $this->fields[$name]['value'] = $this->entityInstance->$name ?? null;
590
            $this->fields[$name]['value_text'] = $this->prepareFieldShow($name, $properties);
591
        }
592
593
        return $this->fields;
594
    }
595
596
    protected function prepareFieldShow($name, $properties = [])
597
    {
598
        // Init
599
        if (empty($properties)) {
600
            $properties = $this->fields[$name];
601
        }
602
603
        $this->fields[$name]['config'] = isset($properties['config']) ? $properties['config'] : [];
604
        $this->fields[$name]['attributes'] = isset($properties['attributes']) ? $properties['attributes'] : [];
605
        $config = $this->fields[$name]['config'];
606
607
        $value = $this->entityInstance
608
            ? ($this->entityInstance->$name ?? null)
609
            : (isset($config['default_value']) ? $config['default_value'] : null);
610
611
        if ($this->entityInstance) {
612
            if (($properties['type'] === 'date' || $properties['type'] === 'datetime') &&
613
                $this->entityInstance->$name != '') {
614
                $fieldValue = $this->entityInstance->$name;
615
616
                if (!is_object($fieldValue)) {
617
                    $fieldValue = Carbon::parse($this->entityInstance->$name);
618
                }
619
620
                $value = $fieldValue->diff(Carbon::now())->format('%y') != date('Y')
621
                    ? $fieldValue->format($properties['type'] === 'date' ? 'm/d/Y' : 'm/d/Y h:ia')
622
                    : null;
623
            }
624
625
            if (substr($properties['type'], 0, 4) === 'file' && $this->entityInstance->getMedia($name)->last()) {
626
                $value = '<a href="'.route($this->route.'.download', [$this->entityInstance->id, $name]).
627
                    '" target="_blank">'.(
628
                    isset($this->fields[$name]['link_name'])
629
                        ? $this->fields[$name]['link_name']
630
                        : 'download'
631
                    ).'</a>';
632
            }
633
634
            if (isset($config['entity'])) {
635
                $value = isset($this->entityInstance->{$config['rel']}->{$config['field_value']})
636
                    ? $this->entityInstance->{$config['rel']}->{$config['field_value']}
637
                    : null;
638
            } elseif (isset($config['options']) && count($config['options'])) {
639
                $value = $config['options'][$value] ?? null;
640
            }
641
        }
642
643
        return empty($value) ? 'N/A' : $value;
644
    }
645
646
    protected function prepareField($name, $properties = [])
647
    {
648
        // Init
649
        if (empty($properties)) {
650
            $properties = $this->fields[$name];
651
        }
652
653
        $this->fields[$name]['config'] = isset($properties['config']) ? $properties['config'] : [];
654
        $this->fields[$name]['attributes'] = isset($properties['attributes']) ? $properties['attributes'] : [];
655
        $this->fields[$name]['attributes']['class'] = 'form-control';
656
        $this->fields[$name]['html'] = null;
657
658
        $config = $this->fields[$name]['config'];
659
660
        $value = $this->entityInstance
661
            ? isset($properties['value_alias'])
662
                ? $this->entityInstance->{$properties['value_alias']}
663
                : $this->entityInstance->$name
664
            : ($this->fields[$name]['default_value'] ?? null);
665
666
        // Define field type class namespace
667
        $className = '\Eliurkis\Crud\FieldTypes\\'.studly_case($properties['type']);
668
        if (!class_exists($className)) {
669
            return;
670
        }
671
672
        if ($properties['type'] == 'foreign' || $properties['type'] == 'select') {
673
            $properties = $this->prepareRelationalFields($name);
674
675
            if ($properties['type'] == 'foreign' && $this->entityInstance) {
676
                $value = $this->entityInstance->{$config['rel']}->pluck($config['field_key'])->toArray();
677
            }
678
679
            if ($properties['type'] == 'select') {
680
                $properties['attributes']['class'] = 'form-control chosen-select-width';
681
            }
682
683
            return $className::prepare(
684
                $name,
685
                $properties['config']['options'],
686
                $value,
687
                $properties
688
            );
689
        }
690
691
        return $className::prepare(
692
            $name,
693
            $value,
694
            $this->fields[$name]
695
        );
696
    }
697
}
698