Passed
Push — ft/pagefield ( db2ad6...f2722b )
by Ben
10:27
created

SavingFields::saveQueuedFields()   B

Complexity

Conditions 7
Paths 12

Size

Total Lines 28
Code Lines 12

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 6
CRAP Score 7

Importance

Changes 2
Bugs 0 Features 0
Metric Value
eloc 12
c 2
b 0
f 0
dl 0
loc 28
ccs 6
cts 6
cp 1
rs 8.8333
cc 7
nc 12
nop 0
crap 7
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Thinktomorrow\Chief\Fields;
6
7
use Illuminate\Http\Request;
8
use Illuminate\Support\Str;
9
use Thinktomorrow\Chief\Fields\Types\Field;
10
use Thinktomorrow\Chief\Fields\Types\FieldType;
11
use Thinktomorrow\Chief\Fields\Types\FileField;
12
use Thinktomorrow\Chief\Fields\Types\ImageField;
13
use Thinktomorrow\Chief\Media\Application\FileFieldHandler;
14
use Thinktomorrow\Chief\Media\Application\ImageFieldHandler;
15
16
trait SavingFields
17
{
18
    // If there is a save<key>Field this has priority over the set<Key>Field methods
19
    protected $saveAssistantMethods = [];
20
    protected $saveMethods = [];
21
22
    protected $queued_translations = [];
23
24 112
    public function saveCreateFields(Request $request): void
25
    {
26 112
        $this->saveFields($request, $this->createFields());
0 ignored issues
show
Bug introduced by
It seems like createFields() must be provided by classes using this trait. How about adding it as abstract method to this trait? ( Ignorable by Annotation )

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

26
        $this->saveFields($request, $this->/** @scrutinizer ignore-call */ createFields());
Loading history...
27
    }
28
29 112
    public function saveEditFields(Request $request): void
30 104
    {
31
        $this->saveFields($request, $this->editFields());
0 ignored issues
show
Bug introduced by
The method editFields() does not exist on Thinktomorrow\Chief\Fields\SavingFields. Did you maybe mean saveEditFields()? ( Ignorable by Annotation )

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

31
        $this->saveFields($request, $this->/** @scrutinizer ignore-call */ editFields());

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...
32
    }
33
34 83
    protected function saveFields(Request $request, Fields $fields)
35 83
    {
36 34
        foreach ($fields as $field) {
37 83
38
            // Custom save methods
39
            if ($this->detectCustomSaveMethods($field)) {
40
                continue;
41 112
            }
42
43 112
            // Custom set methods - default is the generic setField() method.
44
            $methodName = 'set' . ucfirst(Str::camel($field->getKey())) . 'Field';
45
            (method_exists($this, $methodName))
46 110
                ? $this->$methodName($field, $request)
47 110
                : $this->setField($field, $request);
48
        }
49 112
50
        // Save the model
51 112
        $this->saveQueuedFields();
52 112
53
        $this->saveQueuedMethods($request);
54 112
55 112
        // Attach the updated model to our manager.
56 92
        $this->manage($this->model);
0 ignored issues
show
Bug introduced by
It seems like manage() must be provided by classes using this trait. How about adding it as abstract method to this trait? ( Ignorable by Annotation )

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

56
        $this->/** @scrutinizer ignore-call */ 
57
               manage($this->model);
Loading history...
57 92
    }
58 92
59 92
    protected function detectCustomSaveMethods(Field $field): bool
60
    {
61
        $saveMethodByKey = 'save' . ucfirst(Str::camel($field->getKey())) . 'Field';
62 92
        $saveMethodByType = 'save' . ucfirst(Str::camel($field->getType()->get())) . 'Fields';
63
64
        foreach ([$saveMethodByKey, $saveMethodByType] as $saveMethod) {
65
            foreach ($this->assistants() as $assistant) {
0 ignored issues
show
Bug introduced by
It seems like assistants() must be provided by classes using this trait. How about adding it as abstract method to this trait? ( Ignorable by Annotation )

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

65
            foreach ($this->/** @scrutinizer ignore-call */ assistants() as $assistant) {
Loading history...
66 112
                if (method_exists($assistant, $saveMethod)) {
67 104
                    $this->saveAssistantMethods[$field->getKey()] = [
68
                        'field'     => $field,
69 112
                        'method'    => $saveMethod,
70
                        'assistant' => $assistant,
71
                    ];
72
73 83
                    return true;
74
                }
75
            }
76 112
77
            if (method_exists($this, $saveMethod)) {
78 112
                $this->saveMethods[$field->getKey()] = ['field' => $field, 'method' => $saveMethod];
79 92
80 92
                return true;
81
            }
82
        }
83 112
84 104
        return false;
85 104
    }
86
87 110
    private function saveQueuedMethods($request)
88
    {
89 83
        foreach ($this->saveAssistantMethods as $data) {
90
            $method = $data['method'];
91
            $data['assistant']->$method($data['field'], $request);
92 83
        }
93 81
94 26
        foreach ($this->saveMethods as $data) {
95
            $method = $data['method'];
96
            $this->$method($data['field'], $request);
97
        }
98 56
    }
99
100
    public function setField(Field $field, Request $request)
101
    {
102
        // Is field set as translatable?
103
        if ($field->isTranslatable()) {
0 ignored issues
show
Bug introduced by
The method isTranslatable() does not exist on Thinktomorrow\Chief\Fields\Types\Field. Since it exists in all sub-types, consider adding an abstract or default implementation to Thinktomorrow\Chief\Fields\Types\Field. ( Ignorable by Annotation )

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

103
        if ($field->/** @scrutinizer ignore-call */ isTranslatable()) {
Loading history...
104
            if (!$this->requestContainsTranslations($request)) {
0 ignored issues
show
Bug introduced by
It seems like requestContainsTranslations() must be provided by classes using this trait. How about adding it as abstract method to this trait? ( Ignorable by Annotation )

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

104
            if (!$this->/** @scrutinizer ignore-call */ requestContainsTranslations($request)) {
Loading history...
105 56
                return;
106 56
            }
107
108 56
            // Make our media fields able to be translatable as well...
109
            if ($field->ofType(FieldType::FILE, FieldType::IMAGE)) {
110
                throw new \Exception('Cannot process the ' . $field->getKey() . ' media field. Currently no support for translatable media files. We should fix this!');
111
            }
112 44
113 44
            // Okay so this is a bit odd but since all translations are expected to be inside the trans
114
            // array, we can add all these translations at once. Just make sure to keep track of the
115 112
            // keys since this is what our translation engine requires as well for proper update.
116
            $this->queued_translations = $request->input('trans');
117 112
            $this->translation_columns[] = $field->getColumn();
0 ignored issues
show
Bug Best Practice introduced by
The property translation_columns does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
118
119
            return;
120 112
        }
121 53
122
        // By default we assume the key matches the attribute / column naming
123
        $this->model->{$field->getColumn()} = $request->input($field->getKey());
124 112
    }
125
126
    private function saveQueuedFields()
127 47
    {
128
        $queued_translations = $this->queued_translations;
129 47
130 46
        foreach ($queued_translations as $locale => $translations) {
131
            foreach ($translations as $key => $value) {
132 88
                if (method_exists($this->model, 'isDynamicKey') && $this->model->isDynamicKey($key)) {
133
                    $this->model->setDynamic($key, $value, $locale);
134 88
135 87
                    // Remove from queued translations
136
                    unset($queued_translations[$locale][$key]);
137
                }
138
139
                // remove any empty locale entries
140
                if (empty($queued_translations[$locale])) {
141
                    unset($queued_translations[$locale]);
142
                }
143
            }
144
        }
145
146
        $this->model->save();
147
148
        // Translations
149
        if (!empty($queued_translations)) {
150
            $this->saveTranslations($queued_translations, $this->model, $this->translation_columns);
0 ignored issues
show
Bug introduced by
It seems like saveTranslations() must be provided by classes using this trait. How about adding it as abstract method to this trait? ( Ignorable by Annotation )

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

150
            $this->/** @scrutinizer ignore-call */ 
151
                   saveTranslations($queued_translations, $this->model, $this->translation_columns);
Loading history...
151
        }
152
153
        return (new static($this->registration))->manage($this->model);
0 ignored issues
show
Unused Code introduced by
The call to Thinktomorrow\Chief\Fiel...ngFields::__construct() has too many arguments starting with $this->registration. ( Ignorable by Annotation )

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

153
        return (/** @scrutinizer ignore-call */ new static($this->registration))->manage($this->model);

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above.

Loading history...
154
    }
155
156
    public function saveFileFields(FileField $field, Request $request)
157
    {
158
        app(FileFieldHandler::class)->handle($this->model, $field, $request);
159
    }
160
161
    public function saveImageFields(ImageField $field, Request $request)
162
    {
163
        app(ImageFieldHandler::class)->handle($this->model, $field, $request->input('images.' . $field->getName(), []), $request);
164
    }
165
}
166