Completed
Push — master ( 64ceeb...01d429 )
by Terzi
04:48
created

Generic::makeFrom()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 1
nc 1
nop 1
dl 0
loc 3
rs 10
c 0
b 0
f 0
1
<?php
2
3
namespace Terranet\Administrator\Field;
4
5
use Coduo\PHPHumanizer\StringHumanizer;
6
use Illuminate\Database\Eloquent\Model;
7
use Illuminate\Support\Facades\View;
8
use Terranet\Administrator\Field\Traits\AcceptsCustomFormat;
9
use Terranet\Administrator\Scaffolding;
10
11
abstract class Generic
12
{
13
    use AcceptsCustomFormat;
14
15
    /** @var string */
16
    protected $id;
17
18
    /** @var string */
19
    protected $title;
20
21
    /** @var mixed */
22
    protected $value;
23
24
    /** @var string */
25
    protected $description;
26
27
    /** @var Model */
28
    protected $model;
29
30
    /** @var bool */
31
    protected $showLabel = true;
32
33
    /** @var array */
34
    protected $visibility = [
35
        Scaffolding::PAGE_INDEX => true,
36
        Scaffolding::PAGE_EDIT => true,
37
        Scaffolding::PAGE_VIEW => true,
38
    ];
39
40
    /** @var array */
41
    protected $attributes = [];
42
43
    /**
44
     * Generic constructor.
45
     *
46
     * @param $title
47
     * @param null $id
0 ignored issues
show
Documentation Bug introduced by
Are you sure the doc-type for parameter $id is correct as it would always require null to be passed?
Loading history...
48
     */
49
    private function __construct($title, $id = null)
50
    {
51
        $this->title = StringHumanizer::humanize($title);
52
        $this->id = snake_case($id ?: $this->title);
53
    }
54
55
    /**
56
     * @param $title
57
     * @param null $id
0 ignored issues
show
Documentation Bug introduced by
Are you sure the doc-type for parameter $id is correct as it would always require null to be passed?
Loading history...
58
     * @param \Closure $callback
59
     *
60
     * @return static
61
     */
62
    public static function make($title, $id = null, \Closure $callback = null): self
63
    {
64
        $instance = new static($title, $id);
65
66
        if (null !== $callback) {
67
            $callback->call($instance, $instance);
68
        }
69
70
        return $instance;
71
    }
72
73
    /**
74
     * Create new element from another.
75
     *
76
     * @param Generic $element
77
     * @return Generic
78
     */
79
    public static function makeFrom(Generic $element)
80
    {
81
        return static::make($element->title(), $element->id());
82
    }
83
84
    /**
85
     * Switch to a new element type.
86
     *
87
     * @param string $className
88
     * @return mixed
89
     */
90
    public function switchTo(string $className)
91
    {
92
        return forward_static_call_array([$className, "make"], [$this->title(), $this->id()]);
93
    }
94
95
    /**
96
     * @param Model $model
97
     *
98
     * @return self
99
     */
100
    public function setModel(Model $model): self
101
    {
102
        $this->model = $model;
103
104
        return $this;
105
    }
106
107
    /**
108
     * @return Model
109
     */
110
    public function getModel()
111
    {
112
        return $this->model;
113
    }
114
115
    /**
116
     * Render Element.
117
     *
118
     * @param string $page
119
     *
120
     * @return mixed
121
     */
122
    final public function render(string $page = 'index')
123
    {
124
        if ($this->format) {
125
            // Each Field can define its own data for custom formatter.
126
            $withData = method_exists($this, 'renderWith')
127
                ? $this->renderWith()
128
                : [$this->value(), $this->model];
129
130
            return $this->callFormatter($withData);
131
        }
132
133
        $data = [
134
            'field' => $this,
135
            'model' => $this->model,
136
        ];
137
138
        if (method_exists($this, $dataGetter = 'on'.title_case($page))) {
139
            $data += call_user_func([$this, $dataGetter]);
140
        }
141
142
        if (View::exists($view = $this->template($page))) {
143
            return View::make($view, $data);
144
        }
145
146
        return View::make($this->template($page, 'Key'), $data);
147
    }
148
149
    /**
150
     * Return Element ID.
151
     *
152
     * @return string
153
     */
154
    public function id(): string
155
    {
156
        return $this->id;
157
    }
158
159
    /**
160
     * Form name.
161
     *
162
     * @return string
163
     */
164
    public function name()
165
    {
166
        $parts = explode('.', $this->id());
167
168
        if (count($parts) > 1) {
169
            $first = array_first($parts);
170
            $other = array_slice($parts, 1);
171
172
            $other = array_map(function ($part) {
173
                return "[$part]";
174
            }, $other);
175
176
            return implode('', array_merge([$first], $other));
177
        }
178
179
        return $this->id();
180
    }
181
182
    /**
183
     * @param string $id
184
     *
185
     * @return self
186
     */
187
    public function setId(string $id): self
188
    {
189
        $this->id = $id;
190
191
        return $this;
192
    }
193
194
    /**
195
     * Return Element title.
196
     *
197
     * @return string
198
     */
199
    public function title(): string
200
    {
201
        return $this->title;
202
    }
203
204
    /**
205
     * @return string
206
     */
207
    public function getDescription(): ?string
208
    {
209
        return $this->description;
210
    }
211
212
    /**
213
     * @param string $title
214
     *
215
     * @return self
216
     */
217
    public function setTitle(string $title): self
218
    {
219
        $this->title = $title;
220
221
        return $this;
222
    }
223
224
    /**
225
     * @param string $description
226
     *
227
     * @return self
228
     */
229
    public function setDescription(string $description): self
230
    {
231
        $this->description = $description;
232
233
        return $this;
234
    }
235
236
    /**
237
     * @param bool $showLabel
238
     *
239
     * @return self
240
     */
241
    public function hideLabel(bool $hideLabel): self
242
    {
243
        $this->showLabel = !$hideLabel;
244
245
        return $this;
246
    }
247
248
    /**
249
     * @return bool
250
     */
251
    public function isHiddenLabel(): bool
252
    {
253
        return !$this->showLabel;
254
    }
255
256
    /**
257
     * string $page.
258
     *
259
     * @return bool
260
     */
261
    public function isVisibleOnPage(string $page): bool
262
    {
263
        return (bool) $this->visibility[$page] ?? false;
264
    }
265
266
    /**
267
     * @param array|string $pages
268
     *
269
     * @return self
270
     */
271
    public function hideOnPages($pages): self
272
    {
273
        return $this->setPagesVisibility((array) $pages, false);
274
    }
275
276
    /**
277
     * @param array|string $pages
278
     *
279
     * @return self
280
     */
281
    public function showOnPages($pages): self
282
    {
283
        return $this->setPagesVisibility((array) $pages, true);
284
    }
285
286
    /**
287
     * Make column sortable.
288
     *
289
     * @param null|\Closure $callback
290
     *
291
     * @return self
292
     */
293
    public function sortable(\Closure $callback = null): self
294
    {
295
        app('scaffold.module')->addSortable(
0 ignored issues
show
Bug introduced by
The method addSortable() does not exist on Illuminate\Foundation\Application. ( Ignorable by Annotation )

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

295
        app('scaffold.module')->/** @scrutinizer ignore-call */ addSortable(

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...
296
            $this->id(),
297
            $callback
298
        );
299
300
        return $this;
301
    }
302
303
    /**
304
     * Remove column from Sortable collection.
305
     *
306
     * @return self
307
     */
308
    public function disableSorting(): self
309
    {
310
        app('scaffold.module')->removeSortable($this->id());
0 ignored issues
show
Bug introduced by
The method removeSortable() does not exist on Illuminate\Foundation\Application. ( Ignorable by Annotation )

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

310
        app('scaffold.module')->/** @scrutinizer ignore-call */ removeSortable($this->id());

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...
311
312
        return $this;
313
    }
314
315
    /**
316
     * Set value.
317
     *
318
     * @param $value
319
     *
320
     * @return Generic
321
     */
322
    public function setValue($value): self
323
    {
324
        $this->value = $value;
325
326
        return $this;
327
    }
328
329
    /**
330
     * Extract Element value.
331
     *
332
     * @return mixed
333
     */
334
    public function value()
335
    {
336
        if (!$this->model) {
337
            return null;
338
        }
339
340
        if (null === $this->value) {
341
            $this->value = $this->model->getAttribute($this->id);
342
        }
343
344
        return $this->value;
345
    }
346
347
    /**
348
     * @param $key
349
     * @param null $value
0 ignored issues
show
Documentation Bug introduced by
Are you sure the doc-type for parameter $value is correct as it would always require null to be passed?
Loading history...
350
     * @param mixed $attribute
351
     *
352
     * @return self
353
     */
354
    public function setAttribute($attribute, $value = null): self
355
    {
356
        if (is_array($attribute)) {
357
            foreach ($attribute as $key => $value) {
358
                $this->setAttribute($key, $value);
359
            }
360
        } else {
361
            if (!array_key_exists($key, $this->attributes)) {
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $key seems to be never defined.
Loading history...
362
                throw new Exception("Unknown attribute {$key}");
0 ignored issues
show
Bug introduced by
The type Terranet\Administrator\Field\Exception was not found. Did you mean Exception? If so, make sure to prefix the type with \.
Loading history...
363
            }
364
            $this->attributes[$key] = $value;
365
        }
366
367
        return $this;
368
    }
369
370
    /**
371
     * @param mixed $pages
372
     * @param bool $visibility
373
     *
374
     * @return $this
375
     */
376
    protected function setPagesVisibility($pages, bool $visibility): self
377
    {
378
        $pages = array_intersect($pages, array_keys($this->visibility));
379
380
        foreach ($pages as $page) {
381
            $this->visibility[$page] = $visibility;
382
        }
383
384
        return $this;
385
    }
386
387
    /**
388
     * @param string $page
389
     * @param string $field
390
     *
391
     * @return string
392
     */
393
    protected function template(string $page, string $field = null): string
394
    {
395
        return sprintf(
396
            'administrator::fields.%s.%s',
397
            snake_case($field ?? class_basename($this)),
398
            $page
399
        );
400
    }
401
}
402