• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

ICanBoogie / Module / 4245494566

pending completion
4245494566

push

github

Olivier Laviale
Resolve templates using Config instead of Collection

115 of 432 relevant lines covered (26.62%)

0.76 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

0.0
/lib/Module/Operation/SaveOperation.php
1
<?php
2

3
/*
4
 * This file is part of the ICanBoogie package.
5
 *
6
 * (c) Olivier Laviale <olivier.laviale@gmail.com>
7
 *
8
 * For the full copyright and license information, please view the LICENSE
9
 * file that was distributed with this source code.
10
 */
11

12
namespace ICanBoogie\Module\Operation;
13

14
use ICanBoogie\ActiveRecord;
15
use ICanBoogie\ActiveRecord\SchemaColumn;
16
use ICanBoogie\ErrorCollection;
17
use ICanBoogie\Module;
18
use ICanBoogie\Operation;
19
use RuntimeException;
20

21
use function array_intersect_key;
22
use function filter_var;
23
use function is_string;
24
use function trim;
25

26
/**
27
 * The "save" operation is used to create or update a record.
28
 *
29
 * @property array $properties The properties to save.
30
 */
31
class SaveOperation extends Operation
32
{
33
    /**
34
     * Change controls:
35
     *
36
     * - CONTROL_PERMISSION: Module::PERMISSION_CREATE
37
     * - CONTROL_OWNERSHIP: true
38
     * - CONTROL_FORM: true
39
     *
40
     * @return array
41
     */
42
    protected function get_controls()
43
    {
44
        return [
×
45

46
                self::CONTROL_PERMISSION => Module::PERMISSION_CREATE,
×
47
                self::CONTROL_RECORD => true,
×
48
                self::CONTROL_OWNERSHIP => true,
×
49
                self::CONTROL_FORM => true
×
50

51
            ] + parent::get_controls();
×
52
    }
53

54
    /**
55
     * Filters out the operation's parameters, which are not defined as fields by the
56
     * primary model of the module, and take care of filtering or resolving properties values.
57
     *
58
     * Fields defined as 'boolean'
59
     * ---------------------------
60
     *
61
     * The value of the property is filtered using the filter_var() function and the
62
     * FILTER_VALIDATE_BOOLEAN filter. If the property in the operation params is empty, the
63
     * property value is set the `false`.
64
     *
65
     * Fields defined as 'varchar'
66
     * ---------------------------
67
     *
68
     * If the property is not empty in the operation params, the property value is trimmed using the
69
     * trim() function, ensuring that there is no leading or trailing white spaces.
70
     *
71
     * **Note::** The getter should only be called during the {@link process()} method.
72
     *
73
     * @return array The properties of the operation.
74
     */
75
    protected function lazy_get_properties()
76
    {
77
        $schema = $this->module->model->extended_schema;
×
78
        $request = $this->request;
×
79
        $properties = array_intersect_key($request->params, $schema->columns);
×
80

81
        foreach ($schema as $identifier => $column) {
×
82
            $type = $column->type;
×
83

84
            if ($type == SchemaColumn::TYPE_BOOLEAN) {
×
85
                if ($column->null && ($request[$identifier] === null || $request[$identifier] === '')) {
×
86
                    $properties[$identifier] = null;
×
87
                } else {
88
                    if (empty($properties[$identifier])) {
×
89
                        $properties[$identifier] = false;
×
90

91
                        continue;
×
92
                    }
93

94
                    $properties[$identifier] = filter_var($properties[$identifier], FILTER_VALIDATE_BOOLEAN);
×
95
                }
96
            } else {
97
                if ($type == SchemaColumn::TYPE_VARCHAR) {
×
98
                    if (empty($properties[$identifier]) || !is_string($properties[$identifier])) {
×
99
                        continue;
×
100
                    }
101

102
                    $properties[$identifier] = trim($properties[$identifier]);
×
103
                }
104
            }
105
        }
106

107
        unset($properties[$schema->primary]);
×
108

109
        return $properties;
×
110
    }
111

112
    /**
113
     * Overrides the getter to prevent exceptions when the operation key is empty.
114
     */
115
    protected function lazy_get_record()
116
    {
117
        return $this->key ? parent::lazy_get_record() : null;
×
118
    }
119

120
    /**
121
     * Overrides the method in order for the control to pass if the operation key is empty, which
122
     * is the case when creating a new record.
123
     */
124
    protected function control_record()
125
    {
126
        return $this->key ? parent::control_record() : true;
×
127
    }
128

129
    /**
130
     * The method simply returns true.
131
     *
132
     * @param ErrorCollection $errors
133
     *
134
     * @return bool
135
     */
136
    protected function validate(ErrorCollection $errors)
137
    {
138
        return true;
×
139
    }
140

141
    /**
142
     * Creates or updates a record in the module's primary model.
143
     *
144
     * A record is created if the operation's key is empty, otherwise an existing record is
145
     * updated.
146
     *
147
     * The method uses the `properties` property to get the properties used to create or update
148
     * the record.
149
     *
150
     * @return array An array composed of the save mode ('update' or 'new') and the record's
151
     * key.
152
     *
153
     * @throws RuntimeException when saving the record fails.
154
     */
155
    protected function process()
156
    {
157
        $key = $this->key;
×
158
        $properties = $this->properties;
×
159
        $log_params = [ 'key' => $key, 'module' => $this->module->title ];
×
160

161
        try {
162
            $record = $this->record = $key
×
163
                ? $this->update_record($properties)
×
164
                : $this->create_record($properties);
×
165

166
            $record_key = $record->save();
×
167
        } catch (ActiveRecord\RecordNotValid $e) {
×
168
            $this->response->errors->merge($e->errors->to_error_collection());
×
169

170
            throw $e;
×
171
        }
172

173
        if (!$record_key) {
×
174
            throw new RuntimeException(
×
175
                $this->format(
×
176
                    $key ? 'Unable to update record %key in %module.' : 'Unable to create record in %module.',
×
177
                    $log_params
×
178
                )
×
179
            );
×
180
        }
181

182
        $this->response->location = $this->request->uri;
×
183
        $this->response->message = $this->format(
×
184
            $key ? 'The record %key in %module has been saved.' : 'A new record has been saved in %module.',
×
185
            $log_params
×
186
        );
×
187

188
        return [ 'mode' => $key ? 'update' : 'new', 'key' => $record_key ];
×
189
    }
190

191
    /**
192
     * Update the operation record with properties.
193
     *
194
     * @param array $properties
195
     *
196
     * @return ActiveRecord
197
     */
198
    protected function update_record(array $properties)
199
    {
200
        return $this->record->assign($properties);
×
201
    }
202

203
    /**
204
     * Creates a record from properties.
205
     *
206
     * @param array $properties
207
     *
208
     * @return ActiveRecord
209
     */
210
    protected function create_record(array $properties)
211
    {
212
        return $this->module->model->new($properties);
×
213
    }
214
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc