Completed
Push — master ( 1d3c0c...8bf0fe )
by Song
03:06
created

Action::formatAttributes()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 10

Duplication

Lines 10
Ratio 100 %

Importance

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