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;
13
14 /**
15 * The "save" operation is used to create or update a record.
16 */
17 class SaveOperation extends Operation
18 {
19 /**
20 * Change controls:
21 *
22 * - CONTROL_PERMISSION: Module::PERMISSION_CREATE
23 * - CONTROL_OWNERSHIP: true
24 * - CONTROL_FORM: true
25 *
26 * @return array
27 */
28 protected function get_controls()
29 {
30 return [
31
32 self::CONTROL_PERMISSION => Module::PERMISSION_CREATE,
33 self::CONTROL_RECORD => true,
34 self::CONTROL_OWNERSHIP => true,
35 self::CONTROL_FORM => true
36
37 ] + parent::get_controls();
38 }
39
40 /**
41 * Overrides the getter to prevent exceptions when the operation key is empty.
42 */
43 protected function lazy_get_record()
44 {
45 return $this->key ? parent::lazy_get_record() : null;
46 }
47
48 /**
49 * Overrides the method in order for the control to pass if the operation key is empty, which
50 * is the case when creating a new record.
51 */
52 protected function control_record()
53 {
54 return $this->key ? parent::control_record() : true;
55 }
56
57 /**
58 * Filters out the operation's parameters, which are not defined as fields by the
59 * primary model of the module, and take care of filtering or resolving properties values.
60 *
61 * Fields defined as 'boolean'
62 * ---------------------------
63 *
64 * The value of the property is filtered using the filter_var() function and the
65 * FILTER_VALIDATE_BOOLEAN filter. If the property in the operation params is empty, the
66 * property value is set the `false`.
67 *
68 * Fields defined as 'varchar'
69 * ---------------------------
70 *
71 * If the property is not empty in the operation params, the property value is trimed using the
72 * trim() function, ensuring that there is no leading or trailing white spaces.
73 *
74 * @return array The properties of the operation.
75 */
76 protected function lazy_get_properties()
77 {
78 $schema = $this->module->model->extended_schema;
79 $fields = $schema['fields'];
80 $request = $this->request;
81 $properties = array_intersect_key($request->params, $fields);
82
83 foreach ($fields as $identifier => $definition)
84 {
85 $type = $definition['type'];
86
87 if ($type == 'boolean')
88 {
89 if (!empty($definition['null']) && ($request[$identifier] === null || $request[$identifier] === ''))
90 {
91 $properties[$identifier] = null;
92 }
93 else
94 {
95 if (empty($properties[$identifier]))
96 {
97 $properties[$identifier] = false;
98
99 continue;
100 }
101
102 $properties[$identifier] = filter_var($properties[$identifier], FILTER_VALIDATE_BOOLEAN);
103 }
104 }
105 else if ($type == 'varchar')
106 {
107 if (empty($properties[$identifier]) || !is_string($properties[$identifier]))
108 {
109 continue;
110 }
111
112 $properties[$identifier] = trim($properties[$identifier]);
113 }
114 }
115
116 return $properties;
117 }
118
119 /**
120 * The method simply returns true.
121 */
122 protected function validate(Errors $errors)
123 {
124 return true;
125 }
126
127 /**
128 * Creates or updates a record in the module's primary model.
129 *
130 * A record is created if the operation's key is empty, otherwise an existing record is
131 * updated.
132 *
133 * The method uses the `properties` property to get the properties used to create or update
134 * the record.
135 *
136 * @return array An array composed of the save mode ('update' or 'new') and the record's
137 * key.
138 * @throws Exception when saving the record fails.
139 */
140 protected function process()
141 {
142 $key = $this->key;
143 $record_key = $this->module->model->save($this->properties, $key);
144 $log_params = [ 'key' => $key, 'module' => $this->module->title ];
145
146 if (!$record_key)
147 {
148 throw new Exception($key ? 'Unable to update record %key in %module.' : 'Unable to create record in %module.', $log_params);
149 }
150
151 $this->record = $this->module->model[$record_key];
152 $this->response->location = $this->request->uri;
153 $this->response->message = new I18n\FormattedString($key ? 'The record %key in %module has been saved.' : 'A new record has been saved in %module.', $log_params);
154
155 return [ 'mode' => $key ? 'update' : 'new', 'key' => $record_key ];
156 }
157 }