Completed
Push — master ( c8a423...a23ea0 )
by Song
02:21
created

src/Actions/Action.php (1 issue)

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