Issues (413)

app/Services/Tree/Tree.php (7 issues)

1
<?php
2
/**
3
 * Created by PhpStorm.
4
 * User: sheldon
5
 * Date: 18-4-18
6
 * Time: 上午10:39.
7
 */
8
9
namespace Yeelight\Services\Tree;
10
11
use Closure;
12
use Illuminate\Contracts\Support\Renderable;
13
use Illuminate\Database\Eloquent\Model;
14
use Yeelight\Services\Assets\Assets;
15
16
/**
17
 * Class Tree
18
 *
19
 * @category Yeelight
20
 *
21
 * @package Yeelight\Services\Tree
22
 *
23
 * @author Sheldon Lee <[email protected]>
24
 *
25
 * @license https://opensource.org/licenses/MIT MIT
26
 *
27
 * @link https://www.yeelight.com
28
 */
29
class Tree implements Renderable
30
{
31
    /**
32
     * @var array
33
     */
34
    protected $items = [];
35
36
    /**
37
     * @var string
38
     */
39
    protected $elementId = 'tree-';
40
41
    /**
42
     * @var Model
43
     */
44
    protected $model;
45
46
    /**
47
     * @var \Closure
48
     */
49
    protected $queryCallback;
50
51
    /**
52
     * View of tree to render.
53
     *
54
     * @var string
55
     */
56
    protected $view = [
57
        'tree'   => 'backend.tree',
58
        'branch' => 'backend.tree.branch',
59
    ];
60
61
    /**
62
     * @var \Closure
63
     */
64
    protected $callback;
65
66
    /**
67
     * @var null
68
     */
69
    protected $branchCallback = null;
70
71
    /**
72
     * @var bool
73
     */
74
    public $useCreate = true;
75
76
    /**
77
     * @var bool
78
     */
79
    public $useSave = true;
80
81
    /**
82
     * @var bool
83
     */
84
    public $useRefresh = true;
85
86
    /**
87
     * @var array
88
     */
89
    protected $nestableOptions = [];
90
91
    /**
92
     * Menu constructor.
93
     *
94
     * @param Model|null $model
95
     */
96
    public function __construct(Model $model = null, \Closure $callback = null)
97
    {
98
        $this->model = $model;
99
100
        $this->path = app('request')->getPathInfo();
0 ignored issues
show
Bug Best Practice introduced by
The property path does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
101
        $this->elementId .= uniqid();
102
103
        $this->setupTools();
104
105
        if ($callback instanceof \Closure) {
106
            call_user_func($callback, $this);
107
        }
108
109
        $this->initBranchCallback();
110
    }
111
112
    /**
113
     * Setup tree tools.
114
     */
115
    public function setupTools()
116
    {
117
        $this->tools = new Tools($this);
0 ignored issues
show
Bug Best Practice introduced by
The property tools does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
118
    }
119
120
    /**
121
     * Initialize branch callback.
122
     *
123
     * @return void
124
     */
125
    protected function initBranchCallback()
126
    {
127
        if (is_null($this->branchCallback)) {
128
            $this->branchCallback = function ($branch) {
0 ignored issues
show
Documentation Bug introduced by
It seems like function(...) { /* ... */ } of type callable is incompatible with the declared type null of property $branchCallback.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
129
                $key = $branch[$this->model->getKeyName()];
130
                $title = $branch[$this->model->getTitleColumn()];
131
132
                return "$key - $title";
133
            };
134
        }
135
    }
136
137
    /**
138
     * Set branch callback.
139
     *
140
     * @param \Closure $branchCallback
141
     *
142
     * @return $this
143
     */
144
    public function branch(\Closure $branchCallback)
145
    {
146
        $this->branchCallback = $branchCallback;
0 ignored issues
show
Documentation Bug introduced by
It seems like $branchCallback of type Closure is incompatible with the declared type null of property $branchCallback.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
147
148
        return $this;
149
    }
150
151
    /**
152
     * Set query callback this tree.
153
     *
154
     * @return Model
155
     */
156
    public function query(\Closure $callback)
157
    {
158
        $this->queryCallback = $callback;
159
160
        return $this;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this returns the type Yeelight\Services\Tree\Tree which is incompatible with the documented return type Illuminate\Database\Eloquent\Model.
Loading history...
161
    }
162
163
    /**
164
     * Set nestable options.
165
     *
166
     * @param array $options
167
     *
168
     * @return $this
169
     */
170
    public function nestable($options = [])
171
    {
172
        $this->nestableOptions = array_merge($this->nestableOptions, $options);
173
174
        return $this;
175
    }
176
177
    /**
178
     * Disable create.
179
     *
180
     * @return void
181
     */
182
    public function disableCreate()
183
    {
184
        $this->useCreate = false;
185
    }
186
187
    /**
188
     * Disable save.
189
     *
190
     * @return void
191
     */
192
    public function disableSave()
193
    {
194
        $this->useSave = false;
195
    }
196
197
    /**
198
     * Disable refresh.
199
     *
200
     * @return void
201
     */
202
    public function disableRefresh()
203
    {
204
        $this->useRefresh = false;
205
    }
206
207
    /**
208
     * Save tree order from a input.
209
     *
210
     * @param string $serialize
211
     *
212
     * @return bool
213
     */
214
    public function saveOrder($serialize)
215
    {
216
        $tree = json_decode($serialize, true);
217
218
        if (json_last_error() != JSON_ERROR_NONE) {
219
            throw new \InvalidArgumentException(json_last_error_msg());
220
        }
221
222
        $this->model->saveOrder($tree);
223
224
        return true;
225
    }
226
227
    /**
228
     * Build tree grid scripts.
229
     *
230
     * @return string
231
     */
232
    protected function script()
233
    {
234
        $deleteConfirm = trans('backend.delete_confirm');
235
        $saveSucceeded = trans('backend.save_succeeded');
236
        $refreshSucceeded = trans('backend.refresh_succeeded');
237
        $deleteSucceeded = trans('backend.delete_succeeded');
0 ignored issues
show
The assignment to $deleteSucceeded is dead and can be removed.
Loading history...
238
        $confirm = trans('backend.confirm');
239
        $cancel = trans('backend.cancel');
240
241
        $nestableOptions = json_encode($this->nestableOptions);
242
243
        return <<<SCRIPT
244
245
        $('#{$this->elementId}').nestable($nestableOptions);
246
247
        $('.tree_branch_delete').click(function() {
248
            var id = $(this).data('id');
249
            swal({
250
              title: "$deleteConfirm",
251
              type: "warning",
252
              showCancelButton: true,
253
              confirmButtonColor: "#DD6B55",
254
              confirmButtonText: "$confirm",
255
              closeOnConfirm: false,
256
              cancelButtonText: "$cancel"
257
            },
258
            function(){
259
                $.ajax({
260
                    method: 'post',
261
                    url: '{$this->path}/' + id,
262
                    data: {
263
                        _method:'delete',
264
                        _token:Yee.token,
265
                    },
266
                    success: function (data) {
267
                        $.pjax.reload('#pjax-container');
268
269
                        if (typeof data === 'object') {
270
                            if (data.status) {
271
                                swal(data.message, '', 'success');
272
                            } else {
273
                                swal(data.message, '', 'error');
274
                            }
275
                        }
276
                    }
277
                });
278
            });
279
        });
280
281
        $('.{$this->elementId}-save').click(function () {
282
            var serialize = $('#{$this->elementId}').nestable('serialize');
283
284
            $.post('{$this->path}/order', {
285
                _token: Yee.token,
286
                _order: JSON.stringify(serialize)
287
            },
288
            function(data){
289
                $.pjax.reload('#pjax-container');
290
                toastr.success('{$saveSucceeded}');
291
            });
292
        });
293
294
        $('.{$this->elementId}-refresh').click(function () {
295
            $.pjax.reload('#pjax-container');
296
            toastr.success('{$refreshSucceeded}');
297
        });
298
299
        $('.{$this->elementId}-tree-tools').on('click', function(e){
300
            var target = $(e.target),
301
                action = target.data('action');
302
            if (action === 'expand') {
303
                $('.dd').nestable('expandAll');
304
            }
305
            if (action === 'collapse') {
306
                $('.dd').nestable('collapseAll');
307
            }
308
        });
309
310
311
SCRIPT;
312
    }
313
314
    /**
315
     * Set view of tree.
316
     *
317
     * @param string $view
318
     */
319
    public function setView($view)
320
    {
321
        $this->view = $view;
322
    }
323
324
    /**
325
     * Return all items of the tree.
326
     *
327
     * @return
328
     *
329
     * @internal param array $items
330
     */
331
    public function getItems()
332
    {
333
        return $this->model->withQuery($this->queryCallback)->toTree();
334
    }
335
336
    /**
337
     * Variables in tree template.
338
     *
339
     * @return array
340
     */
341
    public function variables()
342
    {
343
        return [
344
            'id'         => $this->elementId,
345
            'tools'      => $this->tools->render(),
346
            'items'      => $this->getItems(),
347
            'useCreate'  => $this->useCreate,
348
            'useSave'    => $this->useSave,
349
            'useRefresh' => $this->useRefresh,
350
        ];
351
    }
352
353
    /**
354
     * Setup grid tools.
355
     *
356
     * @param Closure $callback
357
     *
358
     * @return void
359
     */
360
    public function tools(Closure $callback)
361
    {
362
        call_user_func($callback, $this->tools);
363
    }
364
365
    /**
366
     * Render a tree.
367
     *
368
     * @return \Illuminate\Http\JsonResponse|string
369
     */
370
    public function render()
371
    {
372
        Assets::script($this->script());
373
374
        view()->share([
375
            'path'           => $this->path,
376
            'keyName'        => $this->model->getKeyName(),
377
            'branchView'     => $this->view['branch'],
378
            'branchCallback' => $this->branchCallback,
379
        ]);
380
381
        return view($this->view['tree'], $this->variables())->render();
0 ignored issues
show
The method render() does not exist on Illuminate\Contracts\View\Factory. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

381
        return view($this->view['tree'], $this->variables())->/** @scrutinizer ignore-call */ render();

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
382
    }
383
384
    /**
385
     * Get the string contents of the grid view.
386
     *
387
     * @return string
388
     */
389
    public function __toString()
390
    {
391
        return $this->render();
392
    }
393
}
394