Completed
Push — master ( 0ba9c9...c4f173 )
by jxlwqq
15s queued 11s
created

src/Actions/Action.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 Encore\Admin\Actions;
4
5
use Encore\Admin\Admin;
6
use Encore\Admin\Form\Field;
7
use Illuminate\Contracts\Support\Renderable;
8
use Illuminate\Http\Request;
9
10
/**
11
 * @method $this                success($title, $text = '', $options = [])
12
 * @method $this                error($title, $text = '', $options = [])
13
 * @method $this                warning($title, $text = '', $options = [])
14
 * @method $this                info($title, $text = '', $options = [])
15
 * @method $this                question($title, $text = '', $options = [])
16
 * @method $this                confirm($title, $text = '', $options = [])
17
 * @method Field\Text           text($column, $label = '')
18
 * @method Field\Email          email($column, $label = '')
19
 * @method Field\Integer        integer($column, $label = '')
20
 * @method Field\Ip             ip($column, $label = '')
21
 * @method Field\Url            url($column, $label = '')
22
 * @method Field\Password       password($column, $label = '')
23
 * @method Field\Mobile         mobile($column, $label = '')
24
 * @method Field\Textarea       textarea($column, $label = '')
25
 * @method Field\Select         select($column, $label = '')
26
 * @method Field\MultipleSelect multipleSelect($column, $label = '')
27
 * @method Field\Checkbox       checkbox($column, $label = '')
28
 * @method Field\Radio          radio($column, $label = '')
29
 * @method Field\File           file($column, $label = '')
30
 * @method Field\Image          image($column, $label = '')
31
 * @method Field\MultipleFile   multipleFile($column, $label = '')
32
 * @method Field\MultipleImage  multipleImage($column, $label = '')
33
 * @method Field\Date           date($column, $label = '')
34
 * @method Field\Datetime       datetime($column, $label = '')
35
 * @method Field\Time           time($column, $label = '')
36
 * @method Field\Hidden         hidden($column, $label = '')
37
 * @method $this                modalLarge()
38
 * @method $this                modalSmall()
39
 */
40
abstract class Action implements Renderable
41
{
42
    use Authorizable;
43
44
    /**
45
     * @var Response
46
     */
47
    protected $response;
48
49
    /**
50
     * @var string
51
     */
52
    protected $selector;
53
54
    /**
55
     * @var string
56
     */
57
    public $event = 'click';
58
59
    /**
60
     * @var string
61
     */
62
    protected $method = 'POST';
63
64
    /**
65
     * @var array
66
     */
67
    protected $attributes = [];
68
69
    /**
70
     * @var string
71
     */
72
    public $selectorPrefix = '.action-';
73
74
    /**
75
     * @var Interactor\Interactor
76
     */
77
    protected $interactor;
78
79
    /**
80
     * @var array
81
     */
82
    protected static $selectors = [];
83
84
    /**
85
     * @var string
86
     */
87
    public $name;
88
89
    /**
90
     * Action constructor.
91
     */
92
    public function __construct()
93
    {
94
        $this->initInteractor();
95
    }
96
97
    /**
98
     * @throws \Exception
99
     */
100
    protected function initInteractor()
101
    {
102
        if ($hasForm = method_exists($this, 'form')) {
103
            $this->interactor = new Interactor\Form($this);
104
        }
105
106
        if ($hasDialog = method_exists($this, 'dialog')) {
107
            $this->interactor = new Interactor\Dialog($this);
108
        }
109
110
        if ($hasForm && $hasDialog) {
111
            throw new \Exception('Can only define one of the methods in `form` and `dialog`');
112
        }
113
    }
114
115
    /**
116
     * Get batch action title.
117
     *
118
     * @return string
119
     */
120
    public function name()
121
    {
122
        return $this->name;
123
    }
124
125
    /**
126
     * @param string $prefix
127
     *
128
     * @return mixed|string
129
     */
130
    public function selector($prefix)
131
    {
132
        if (is_null($this->selector)) {
133
            return static::makeSelector(get_called_class().spl_object_id($this), $prefix);
134
        }
135
136
        return $this->selector;
137
    }
138
139
    /**
140
     * @param string $class
141
     * @param string $prefix
142
     *
143
     * @return string
144
     */
145
    public static function makeSelector($class, $prefix)
146
    {
147
        if (!isset(static::$selectors[$class])) {
148
            static::$selectors[$class] = uniqid($prefix).mt_rand(1000, 9999);
149
        }
150
151
        return static::$selectors[$class];
152
    }
153
154
    /**
155
     * @param string $name
156
     * @param string $value
157
     *
158
     * @return $this
159
     */
160
    public function attribute($name, $value)
161
    {
162
        $this->attributes[$name] = $value;
163
164
        return $this;
165
    }
166
167
    /**
168
     * Format the field attributes.
169
     *
170
     * @return string
171
     */
172 View Code Duplication
    protected function formatAttributes()
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...
173
    {
174
        $html = [];
175
176
        foreach ($this->attributes as $name => $value) {
177
            $html[] = $name.'="'.e($value).'"';
178
        }
179
180
        return implode(' ', $html);
181
    }
182
183
    /**
184
     * @return string
185
     */
186
    protected function getElementClass()
187
    {
188
        return ltrim($this->selector($this->selectorPrefix), '.');
189
    }
190
191
    /**
192
     * @return Response
193
     */
194
    public function response()
195
    {
196
        if (is_null($this->response)) {
197
            $this->response = new Response();
198
        }
199
200
        if (method_exists($this, 'dialog')) {
201
            $this->response->swal();
202
        } else {
203
            $this->response->toastr();
204
        }
205
206
        return $this->response;
207
    }
208
209
    /**
210
     * @return string
211
     */
212
    public function getMethod()
213
    {
214
        return $this->method;
215
    }
216
217
    /**
218
     * @return mixed
219
     */
220
    public function getCalledClass()
221
    {
222
        return str_replace('\\', '_', get_called_class());
223
    }
224
225
    /**
226
     * @return string
227
     */
228
    public function getHandleRoute()
229
    {
230
        return admin_url('_handle_action_');
231
    }
232
233
    /**
234
     * @return string
235
     */
236
    protected function getModelClass()
237
    {
238
        return '';
239
    }
240
241
    /**
242
     * @return array
243
     */
244
    public function parameters()
245
    {
246
        return [];
247
    }
248
249
    /**
250
     * @param Request $request
251
     *
252
     * @return $this
253
     */
254
    public function validate(Request $request)
255
    {
256
        if ($this->interactor instanceof Interactor\Form) {
257
            $this->interactor->validate($request);
258
        }
259
260
        return $this;
261
    }
262
263
    /**
264
     * @return mixed
265
     */
266
    protected function addScript()
267
    {
268
        if (!is_null($this->interactor)) {
269
            return $this->interactor->addScript();
270
        }
271
272
        $parameters = json_encode($this->parameters());
273
274
        $script = <<<SCRIPT
275
276
(function ($) {
277
    $('{$this->selector($this->selectorPrefix)}').off('{$this->event}').on('{$this->event}', function() {
278
        var data = $(this).data();
279
        var target = $(this);
280
        Object.assign(data, {$parameters});
281
        {$this->actionScript()}
282
        {$this->buildActionPromise()}
283
        {$this->handleActionPromise()}
284
    });
285
})(jQuery);
286
287
SCRIPT;
288
289
        Admin::script($script);
290
    }
291
292
    /**
293
     * @return string
294
     */
295
    public function actionScript()
296
    {
297
        return '';
298
    }
299
300
    /**
301
     * @return string
302
     */
303
    protected function buildActionPromise()
304
    {
305
        return <<<SCRIPT
306
        var process = new Promise(function (resolve,reject) {
307
308
            Object.assign(data, {
309
                _token: $.admin.token,
310
                _action: '{$this->getCalledClass()}',
311
            });
312
313
            $.ajax({
314
                method: '{$this->method}',
315
                url: '{$this->getHandleRoute()}',
316
                data: data,
317
                success: function (data) {
318
                    resolve([data, target]);
319
                },
320
                error:function(request){
321
                    reject(request);
322
                }
323
            });
324
        });
325
326
SCRIPT;
327
    }
328
329
    /**
330
     * @return string
331
     */
332
    public function handleActionPromise()
333
    {
334
        $resolve = <<<'SCRIPT'
335
var actionResolver = function (data) {
336
337
            var response = data[0];
338
            var target   = data[1];
339
340
            if (typeof response !== 'object') {
341
                return $.admin.swal({type: 'error', title: 'Oops!'});
342
            }
343
344
            var then = function (then) {
345
                if (then.action == 'refresh') {
346
                    $.admin.reload();
347
                }
348
349
                if (then.action == 'download') {
350
                    window.open(then.value, '_blank');
351
                }
352
353
                if (then.action == 'redirect') {
354
                    $.admin.redirect(then.value);
355
                }
356
357
                if (then.action == 'location') {
358
                    window.location = then.value;
359
                }
360
361
                if (then.action == 'open') {
362
                    window.open(then.value, '_blank');
363
                }
364
            };
365
366
            if (typeof response.html === 'string') {
367
                target.html(response.html);
368
            }
369
370
            if (typeof response.swal === 'object') {
371
                $.admin.swal(response.swal);
372
            }
373
374
            if (typeof response.toastr === 'object' && response.toastr.type) {
375
                $.admin.toastr[response.toastr.type](response.toastr.content, '', response.toastr.options);
376
            }
377
378
            if (response.then) {
379
              then(response.then);
380
            }
381
        };
382
383
        var actionCatcher = function (request) {
384
            if (request && typeof request.responseJSON === 'object') {
385
                $.admin.toastr.error(request.responseJSON.message, '', {positionClass:"toast-bottom-center", timeOut: 10000}).css("width","500px")
386
            }
387
        };
388
SCRIPT;
389
390
        Admin::script($resolve);
391
392
        return <<<'SCRIPT'
393
process.then(actionResolver).catch(actionCatcher);
394
SCRIPT;
395
    }
396
397
    /**
398
     * @param string $method
399
     * @param array  $arguments
400
     *
401
     * @throws \Exception
402
     *
403
     * @return mixed
404
     */
405
    public function __call($method, $arguments = [])
406
    {
407
        if (in_array($method, Interactor\Interactor::$elements)) {
408
            return $this->interactor->{$method}(...$arguments);
409
        }
410
411
        throw new \BadMethodCallException("Method {$method} does not exist.");
412
    }
413
414
    /**
415
     * @return string
416
     */
417
    public function html()
418
    {
419
    }
420
421
    /**
422
     * @return mixed
423
     */
424
    public function render()
425
    {
426
        $this->addScript();
427
428
        $content = $this->html();
429
430
        if ($content && $this->interactor instanceof Interactor\Form) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $content of type string|null is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
431
            return $this->interactor->addElementAttr($content, $this->selector);
432
        }
433
434
        return $this->html();
435
    }
436
}
437