Passed
Push — master ( 7c8a8d...849c13 )
by Blizzz
13:01 queued 11s
created
lib/public/AppFramework/Db/Entity.php 1 patch
Indentation   +234 added lines, -234 removed lines patch added patch discarded remove patch
@@ -34,238 +34,238 @@
 block discarded – undo
34 34
  * @since 7.0.0
35 35
  */
36 36
 abstract class Entity {
37
-	public $id;
38
-
39
-	private $_updatedFields = [];
40
-	private $_fieldTypes = ['id' => 'integer'];
41
-
42
-
43
-	/**
44
-	 * Simple alternative constructor for building entities from a request
45
-	 * @param array $params the array which was obtained via $this->params('key')
46
-	 * in the controller
47
-	 * @return Entity
48
-	 * @since 7.0.0
49
-	 */
50
-	public static function fromParams(array $params) {
51
-		$instance = new static();
52
-
53
-		foreach ($params as $key => $value) {
54
-			$method = 'set' . ucfirst($key);
55
-			$instance->$method($value);
56
-		}
57
-
58
-		return $instance;
59
-	}
60
-
61
-
62
-	/**
63
-	 * Maps the keys of the row array to the attributes
64
-	 * @param array $row the row to map onto the entity
65
-	 * @since 7.0.0
66
-	 */
67
-	public static function fromRow(array $row) {
68
-		$instance = new static();
69
-
70
-		foreach ($row as $key => $value) {
71
-			$prop = ucfirst($instance->columnToProperty($key));
72
-			$setter = 'set' . $prop;
73
-			$instance->$setter($value);
74
-		}
75
-
76
-		$instance->resetUpdatedFields();
77
-
78
-		return $instance;
79
-	}
80
-
81
-
82
-	/**
83
-	 * @return array with attribute and type
84
-	 * @since 7.0.0
85
-	 */
86
-	public function getFieldTypes() {
87
-		return $this->_fieldTypes;
88
-	}
89
-
90
-
91
-	/**
92
-	 * Marks the entity as clean needed for setting the id after the insertion
93
-	 * @since 7.0.0
94
-	 */
95
-	public function resetUpdatedFields() {
96
-		$this->_updatedFields = [];
97
-	}
98
-
99
-	/**
100
-	 * Generic setter for properties
101
-	 * @since 7.0.0
102
-	 */
103
-	protected function setter($name, $args) {
104
-		// setters should only work for existing attributes
105
-		if (property_exists($this, $name)) {
106
-			if ($this->$name === $args[0]) {
107
-				return;
108
-			}
109
-			$this->markFieldUpdated($name);
110
-
111
-			// if type definition exists, cast to correct type
112
-			if ($args[0] !== null && array_key_exists($name, $this->_fieldTypes)) {
113
-				$type = $this->_fieldTypes[$name];
114
-				if ($type === 'blob') {
115
-					// (B)LOB is treated as string when we read from the DB
116
-					$type = 'string';
117
-				}
118
-				settype($args[0], $type);
119
-			}
120
-			$this->$name = $args[0];
121
-		} else {
122
-			throw new \BadFunctionCallException($name .
123
-				' is not a valid attribute');
124
-		}
125
-	}
126
-
127
-	/**
128
-	 * Generic getter for properties
129
-	 * @since 7.0.0
130
-	 */
131
-	protected function getter($name) {
132
-		// getters should only work for existing attributes
133
-		if (property_exists($this, $name)) {
134
-			return $this->$name;
135
-		} else {
136
-			throw new \BadFunctionCallException($name .
137
-				' is not a valid attribute');
138
-		}
139
-	}
140
-
141
-
142
-	/**
143
-	 * Each time a setter is called, push the part after set
144
-	 * into an array: for instance setId will save Id in the
145
-	 * updated fields array so it can be easily used to create the
146
-	 * getter method
147
-	 * @since 7.0.0
148
-	 */
149
-	public function __call($methodName, $args) {
150
-		if (strpos($methodName, 'set') === 0) {
151
-			$this->setter(lcfirst(substr($methodName, 3)), $args);
152
-		} elseif (strpos($methodName, 'get') === 0) {
153
-			return $this->getter(lcfirst(substr($methodName, 3)));
154
-		} elseif ($this->isGetterForBoolProperty($methodName)) {
155
-			return $this->getter(lcfirst(substr($methodName, 2)));
156
-		} else {
157
-			throw new \BadFunctionCallException($methodName .
158
-				' does not exist');
159
-		}
160
-	}
161
-
162
-	/**
163
-	 * @param string $methodName
164
-	 * @return bool
165
-	 * @since 18.0.0
166
-	 */
167
-	protected function isGetterForBoolProperty(string $methodName): bool {
168
-		if (strpos($methodName, 'is') === 0) {
169
-			$fieldName = lcfirst(substr($methodName, 2));
170
-			return isset($this->_fieldTypes[$fieldName]) && strpos($this->_fieldTypes[$fieldName], 'bool') === 0;
171
-		}
172
-		return false;
173
-	}
174
-
175
-	/**
176
-	 * Mark am attribute as updated
177
-	 * @param string $attribute the name of the attribute
178
-	 * @since 7.0.0
179
-	 */
180
-	protected function markFieldUpdated($attribute) {
181
-		$this->_updatedFields[$attribute] = true;
182
-	}
183
-
184
-
185
-	/**
186
-	 * Transform a database columnname to a property
187
-	 * @param string $columnName the name of the column
188
-	 * @return string the property name
189
-	 * @since 7.0.0
190
-	 */
191
-	public function columnToProperty($columnName) {
192
-		$parts = explode('_', $columnName);
193
-		$property = null;
194
-
195
-		foreach ($parts as $part) {
196
-			if ($property === null) {
197
-				$property = $part;
198
-			} else {
199
-				$property .= ucfirst($part);
200
-			}
201
-		}
202
-
203
-		return $property;
204
-	}
205
-
206
-
207
-	/**
208
-	 * Transform a property to a database column name
209
-	 * @param string $property the name of the property
210
-	 * @return string the column name
211
-	 * @since 7.0.0
212
-	 */
213
-	public function propertyToColumn($property) {
214
-		$parts = preg_split('/(?=[A-Z])/', $property);
215
-		$column = null;
216
-
217
-		foreach ($parts as $part) {
218
-			if ($column === null) {
219
-				$column = $part;
220
-			} else {
221
-				$column .= '_' . lcfirst($part);
222
-			}
223
-		}
224
-
225
-		return $column;
226
-	}
227
-
228
-
229
-	/**
230
-	 * @return array array of updated fields for update query
231
-	 * @since 7.0.0
232
-	 */
233
-	public function getUpdatedFields() {
234
-		return $this->_updatedFields;
235
-	}
236
-
237
-
238
-	/**
239
-	 * Adds type information for a field so that its automatically casted to
240
-	 * that value once its being returned from the database
241
-	 * @param string $fieldName the name of the attribute
242
-	 * @param string $type the type which will be used to call settype()
243
-	 * @since 7.0.0
244
-	 */
245
-	protected function addType($fieldName, $type) {
246
-		$this->_fieldTypes[$fieldName] = $type;
247
-	}
248
-
249
-
250
-	/**
251
-	 * Slugify the value of a given attribute
252
-	 * Warning: This doesn't result in a unique value
253
-	 * @param string $attributeName the name of the attribute, which value should be slugified
254
-	 * @return string slugified value
255
-	 * @since 7.0.0
256
-	 */
257
-	public function slugify($attributeName) {
258
-		// toSlug should only work for existing attributes
259
-		if (property_exists($this, $attributeName)) {
260
-			$value = $this->$attributeName;
261
-			// replace everything except alphanumeric with a single '-'
262
-			$value = preg_replace('/[^A-Za-z0-9]+/', '-', $value);
263
-			$value = strtolower($value);
264
-			// trim '-'
265
-			return trim($value, '-');
266
-		} else {
267
-			throw new \BadFunctionCallException($attributeName .
268
-				' is not a valid attribute');
269
-		}
270
-	}
37
+    public $id;
38
+
39
+    private $_updatedFields = [];
40
+    private $_fieldTypes = ['id' => 'integer'];
41
+
42
+
43
+    /**
44
+     * Simple alternative constructor for building entities from a request
45
+     * @param array $params the array which was obtained via $this->params('key')
46
+     * in the controller
47
+     * @return Entity
48
+     * @since 7.0.0
49
+     */
50
+    public static function fromParams(array $params) {
51
+        $instance = new static();
52
+
53
+        foreach ($params as $key => $value) {
54
+            $method = 'set' . ucfirst($key);
55
+            $instance->$method($value);
56
+        }
57
+
58
+        return $instance;
59
+    }
60
+
61
+
62
+    /**
63
+     * Maps the keys of the row array to the attributes
64
+     * @param array $row the row to map onto the entity
65
+     * @since 7.0.0
66
+     */
67
+    public static function fromRow(array $row) {
68
+        $instance = new static();
69
+
70
+        foreach ($row as $key => $value) {
71
+            $prop = ucfirst($instance->columnToProperty($key));
72
+            $setter = 'set' . $prop;
73
+            $instance->$setter($value);
74
+        }
75
+
76
+        $instance->resetUpdatedFields();
77
+
78
+        return $instance;
79
+    }
80
+
81
+
82
+    /**
83
+     * @return array with attribute and type
84
+     * @since 7.0.0
85
+     */
86
+    public function getFieldTypes() {
87
+        return $this->_fieldTypes;
88
+    }
89
+
90
+
91
+    /**
92
+     * Marks the entity as clean needed for setting the id after the insertion
93
+     * @since 7.0.0
94
+     */
95
+    public function resetUpdatedFields() {
96
+        $this->_updatedFields = [];
97
+    }
98
+
99
+    /**
100
+     * Generic setter for properties
101
+     * @since 7.0.0
102
+     */
103
+    protected function setter($name, $args) {
104
+        // setters should only work for existing attributes
105
+        if (property_exists($this, $name)) {
106
+            if ($this->$name === $args[0]) {
107
+                return;
108
+            }
109
+            $this->markFieldUpdated($name);
110
+
111
+            // if type definition exists, cast to correct type
112
+            if ($args[0] !== null && array_key_exists($name, $this->_fieldTypes)) {
113
+                $type = $this->_fieldTypes[$name];
114
+                if ($type === 'blob') {
115
+                    // (B)LOB is treated as string when we read from the DB
116
+                    $type = 'string';
117
+                }
118
+                settype($args[0], $type);
119
+            }
120
+            $this->$name = $args[0];
121
+        } else {
122
+            throw new \BadFunctionCallException($name .
123
+                ' is not a valid attribute');
124
+        }
125
+    }
126
+
127
+    /**
128
+     * Generic getter for properties
129
+     * @since 7.0.0
130
+     */
131
+    protected function getter($name) {
132
+        // getters should only work for existing attributes
133
+        if (property_exists($this, $name)) {
134
+            return $this->$name;
135
+        } else {
136
+            throw new \BadFunctionCallException($name .
137
+                ' is not a valid attribute');
138
+        }
139
+    }
140
+
141
+
142
+    /**
143
+     * Each time a setter is called, push the part after set
144
+     * into an array: for instance setId will save Id in the
145
+     * updated fields array so it can be easily used to create the
146
+     * getter method
147
+     * @since 7.0.0
148
+     */
149
+    public function __call($methodName, $args) {
150
+        if (strpos($methodName, 'set') === 0) {
151
+            $this->setter(lcfirst(substr($methodName, 3)), $args);
152
+        } elseif (strpos($methodName, 'get') === 0) {
153
+            return $this->getter(lcfirst(substr($methodName, 3)));
154
+        } elseif ($this->isGetterForBoolProperty($methodName)) {
155
+            return $this->getter(lcfirst(substr($methodName, 2)));
156
+        } else {
157
+            throw new \BadFunctionCallException($methodName .
158
+                ' does not exist');
159
+        }
160
+    }
161
+
162
+    /**
163
+     * @param string $methodName
164
+     * @return bool
165
+     * @since 18.0.0
166
+     */
167
+    protected function isGetterForBoolProperty(string $methodName): bool {
168
+        if (strpos($methodName, 'is') === 0) {
169
+            $fieldName = lcfirst(substr($methodName, 2));
170
+            return isset($this->_fieldTypes[$fieldName]) && strpos($this->_fieldTypes[$fieldName], 'bool') === 0;
171
+        }
172
+        return false;
173
+    }
174
+
175
+    /**
176
+     * Mark am attribute as updated
177
+     * @param string $attribute the name of the attribute
178
+     * @since 7.0.0
179
+     */
180
+    protected function markFieldUpdated($attribute) {
181
+        $this->_updatedFields[$attribute] = true;
182
+    }
183
+
184
+
185
+    /**
186
+     * Transform a database columnname to a property
187
+     * @param string $columnName the name of the column
188
+     * @return string the property name
189
+     * @since 7.0.0
190
+     */
191
+    public function columnToProperty($columnName) {
192
+        $parts = explode('_', $columnName);
193
+        $property = null;
194
+
195
+        foreach ($parts as $part) {
196
+            if ($property === null) {
197
+                $property = $part;
198
+            } else {
199
+                $property .= ucfirst($part);
200
+            }
201
+        }
202
+
203
+        return $property;
204
+    }
205
+
206
+
207
+    /**
208
+     * Transform a property to a database column name
209
+     * @param string $property the name of the property
210
+     * @return string the column name
211
+     * @since 7.0.0
212
+     */
213
+    public function propertyToColumn($property) {
214
+        $parts = preg_split('/(?=[A-Z])/', $property);
215
+        $column = null;
216
+
217
+        foreach ($parts as $part) {
218
+            if ($column === null) {
219
+                $column = $part;
220
+            } else {
221
+                $column .= '_' . lcfirst($part);
222
+            }
223
+        }
224
+
225
+        return $column;
226
+    }
227
+
228
+
229
+    /**
230
+     * @return array array of updated fields for update query
231
+     * @since 7.0.0
232
+     */
233
+    public function getUpdatedFields() {
234
+        return $this->_updatedFields;
235
+    }
236
+
237
+
238
+    /**
239
+     * Adds type information for a field so that its automatically casted to
240
+     * that value once its being returned from the database
241
+     * @param string $fieldName the name of the attribute
242
+     * @param string $type the type which will be used to call settype()
243
+     * @since 7.0.0
244
+     */
245
+    protected function addType($fieldName, $type) {
246
+        $this->_fieldTypes[$fieldName] = $type;
247
+    }
248
+
249
+
250
+    /**
251
+     * Slugify the value of a given attribute
252
+     * Warning: This doesn't result in a unique value
253
+     * @param string $attributeName the name of the attribute, which value should be slugified
254
+     * @return string slugified value
255
+     * @since 7.0.0
256
+     */
257
+    public function slugify($attributeName) {
258
+        // toSlug should only work for existing attributes
259
+        if (property_exists($this, $attributeName)) {
260
+            $value = $this->$attributeName;
261
+            // replace everything except alphanumeric with a single '-'
262
+            $value = preg_replace('/[^A-Za-z0-9]+/', '-', $value);
263
+            $value = strtolower($value);
264
+            // trim '-'
265
+            return trim($value, '-');
266
+        } else {
267
+            throw new \BadFunctionCallException($attributeName .
268
+                ' is not a valid attribute');
269
+        }
270
+    }
271 271
 }
Please login to merge, or discard this patch.
lib/public/AppFramework/Db/QBMapper.php 1 patch
Indentation   +291 added lines, -291 removed lines patch added patch discarded remove patch
@@ -42,295 +42,295 @@
 block discarded – undo
42 42
  */
43 43
 abstract class QBMapper {
44 44
 
45
-	/** @var string */
46
-	protected $tableName;
47
-
48
-	/** @var string */
49
-	protected $entityClass;
50
-
51
-	/** @var IDBConnection */
52
-	protected $db;
53
-
54
-	/**
55
-	 * @param IDBConnection $db Instance of the Db abstraction layer
56
-	 * @param string $tableName the name of the table. set this to allow entity
57
-	 * @param string $entityClass the name of the entity that the sql should be
58
-	 * mapped to queries without using sql
59
-	 * @since 14.0.0
60
-	 */
61
-	public function __construct(IDBConnection $db, string $tableName, string $entityClass=null) {
62
-		$this->db = $db;
63
-		$this->tableName = $tableName;
64
-
65
-		// if not given set the entity name to the class without the mapper part
66
-		// cache it here for later use since reflection is slow
67
-		if ($entityClass === null) {
68
-			$this->entityClass = str_replace('Mapper', '', \get_class($this));
69
-		} else {
70
-			$this->entityClass = $entityClass;
71
-		}
72
-	}
73
-
74
-
75
-	/**
76
-	 * @return string the table name
77
-	 * @since 14.0.0
78
-	 */
79
-	public function getTableName(): string {
80
-		return $this->tableName;
81
-	}
82
-
83
-
84
-	/**
85
-	 * Deletes an entity from the table
86
-	 * @param Entity $entity the entity that should be deleted
87
-	 * @return Entity the deleted entity
88
-	 * @since 14.0.0
89
-	 */
90
-	public function delete(Entity $entity): Entity {
91
-		$qb = $this->db->getQueryBuilder();
92
-
93
-		$idType = $this->getParameterTypeForProperty($entity, 'id');
94
-
95
-		$qb->delete($this->tableName)
96
-			->where(
97
-				$qb->expr()->eq('id', $qb->createNamedParameter($entity->getId(), $idType))
98
-			);
99
-		$qb->execute();
100
-		return $entity;
101
-	}
102
-
103
-
104
-	/**
105
-	 * Creates a new entry in the db from an entity
106
-	 * @param Entity $entity the entity that should be created
107
-	 * @return Entity the saved entity with the set id
108
-	 * @since 14.0.0
109
-	 * @suppress SqlInjectionChecker
110
-	 */
111
-	public function insert(Entity $entity): Entity {
112
-		// get updated fields to save, fields have to be set using a setter to
113
-		// be saved
114
-		$properties = $entity->getUpdatedFields();
115
-
116
-		$qb = $this->db->getQueryBuilder();
117
-		$qb->insert($this->tableName);
118
-
119
-		// build the fields
120
-		foreach ($properties as $property => $updated) {
121
-			$column = $entity->propertyToColumn($property);
122
-			$getter = 'get' . ucfirst($property);
123
-			$value = $entity->$getter();
124
-
125
-			$type = $this->getParameterTypeForProperty($entity, $property);
126
-			$qb->setValue($column, $qb->createNamedParameter($value, $type));
127
-		}
128
-
129
-		$qb->execute();
130
-
131
-		if ($entity->id === null) {
132
-			// When autoincrement is used id is always an int
133
-			$entity->setId((int)$qb->getLastInsertId());
134
-		}
135
-
136
-		return $entity;
137
-	}
138
-
139
-	/**
140
-	 * Tries to creates a new entry in the db from an entity and
141
-	 * updates an existing entry if duplicate keys are detected
142
-	 * by the database
143
-	 *
144
-	 * @param Entity $entity the entity that should be created/updated
145
-	 * @return Entity the saved entity with the (new) id
146
-	 * @throws \InvalidArgumentException if entity has no id
147
-	 * @since 15.0.0
148
-	 * @suppress SqlInjectionChecker
149
-	 */
150
-	public function insertOrUpdate(Entity $entity): Entity {
151
-		try {
152
-			return $this->insert($entity);
153
-		} catch (UniqueConstraintViolationException $ex) {
154
-			return $this->update($entity);
155
-		}
156
-	}
157
-
158
-	/**
159
-	 * Updates an entry in the db from an entity
160
-	 * @throws \InvalidArgumentException if entity has no id
161
-	 * @param Entity $entity the entity that should be created
162
-	 * @return Entity the saved entity with the set id
163
-	 * @since 14.0.0
164
-	 * @suppress SqlInjectionChecker
165
-	 */
166
-	public function update(Entity $entity): Entity {
167
-		// if entity wasn't changed it makes no sense to run a db query
168
-		$properties = $entity->getUpdatedFields();
169
-		if (\count($properties) === 0) {
170
-			return $entity;
171
-		}
172
-
173
-		// entity needs an id
174
-		$id = $entity->getId();
175
-		if ($id === null) {
176
-			throw new \InvalidArgumentException(
177
-				'Entity which should be updated has no id');
178
-		}
179
-
180
-		// get updated fields to save, fields have to be set using a setter to
181
-		// be saved
182
-		// do not update the id field
183
-		unset($properties['id']);
184
-
185
-		$qb = $this->db->getQueryBuilder();
186
-		$qb->update($this->tableName);
187
-
188
-		// build the fields
189
-		foreach ($properties as $property => $updated) {
190
-			$column = $entity->propertyToColumn($property);
191
-			$getter = 'get' . ucfirst($property);
192
-			$value = $entity->$getter();
193
-
194
-			$type = $this->getParameterTypeForProperty($entity, $property);
195
-			$qb->set($column, $qb->createNamedParameter($value, $type));
196
-		}
197
-
198
-		$idType = $this->getParameterTypeForProperty($entity, 'id');
199
-
200
-		$qb->where(
201
-			$qb->expr()->eq('id', $qb->createNamedParameter($id, $idType))
202
-		);
203
-		$qb->execute();
204
-
205
-		return $entity;
206
-	}
207
-
208
-	/**
209
-	 * Returns the type parameter for the QueryBuilder for a specific property
210
-	 * of the $entity
211
-	 *
212
-	 * @param Entity $entity   The entity to get the types from
213
-	 * @param string $property The property of $entity to get the type for
214
-	 * @return int
215
-	 * @since 16.0.0
216
-	 */
217
-	protected function getParameterTypeForProperty(Entity $entity, string $property): int {
218
-		$types = $entity->getFieldTypes();
219
-
220
-		if (!isset($types[ $property ])) {
221
-			return IQueryBuilder::PARAM_STR;
222
-		}
223
-
224
-		switch ($types[ $property ]) {
225
-			case 'int':
226
-			case 'integer':
227
-				return IQueryBuilder::PARAM_INT;
228
-			case 'string':
229
-				return IQueryBuilder::PARAM_STR;
230
-			case 'bool':
231
-			case 'boolean':
232
-				return IQueryBuilder::PARAM_BOOL;
233
-			case 'blob':
234
-				return IQueryBuilder::PARAM_LOB;
235
-		}
236
-
237
-		return IQueryBuilder::PARAM_STR;
238
-	}
239
-
240
-	/**
241
-	 * Returns an db result and throws exceptions when there are more or less
242
-	 * results
243
-	 *
244
-	 * @see findEntity
245
-	 *
246
-	 * @param IQueryBuilder $query
247
-	 * @throws DoesNotExistException if the item does not exist
248
-	 * @throws MultipleObjectsReturnedException if more than one item exist
249
-	 * @return array the result as row
250
-	 * @since 14.0.0
251
-	 */
252
-	protected function findOneQuery(IQueryBuilder $query): array {
253
-		$cursor = $query->execute();
254
-
255
-		$row = $cursor->fetch();
256
-		if ($row === false) {
257
-			$cursor->closeCursor();
258
-			$msg = $this->buildDebugMessage(
259
-				'Did expect one result but found none when executing', $query
260
-			);
261
-			throw new DoesNotExistException($msg);
262
-		}
263
-
264
-		$row2 = $cursor->fetch();
265
-		$cursor->closeCursor();
266
-		if ($row2 !== false) {
267
-			$msg = $this->buildDebugMessage(
268
-				'Did not expect more than one result when executing', $query
269
-			);
270
-			throw new MultipleObjectsReturnedException($msg);
271
-		}
272
-
273
-		return $row;
274
-	}
275
-
276
-	/**
277
-	 * @param string $msg
278
-	 * @param IQueryBuilder $sql
279
-	 * @return string
280
-	 * @since 14.0.0
281
-	 */
282
-	private function buildDebugMessage(string $msg, IQueryBuilder $sql): string {
283
-		return $msg .
284
-			': query "' . $sql->getSQL() . '"; ';
285
-	}
286
-
287
-
288
-	/**
289
-	 * Creates an entity from a row. Automatically determines the entity class
290
-	 * from the current mapper name (MyEntityMapper -> MyEntity)
291
-	 *
292
-	 * @param array $row the row which should be converted to an entity
293
-	 * @return Entity the entity
294
-	 * @since 14.0.0
295
-	 */
296
-	protected function mapRowToEntity(array $row): Entity {
297
-		return \call_user_func($this->entityClass .'::fromRow', $row);
298
-	}
299
-
300
-
301
-	/**
302
-	 * Runs a sql query and returns an array of entities
303
-	 *
304
-	 * @param IQueryBuilder $query
305
-	 * @return Entity[] all fetched entities
306
-	 * @since 14.0.0
307
-	 */
308
-	protected function findEntities(IQueryBuilder $query): array {
309
-		$cursor = $query->execute();
310
-
311
-		$entities = [];
312
-
313
-		while ($row = $cursor->fetch()) {
314
-			$entities[] = $this->mapRowToEntity($row);
315
-		}
316
-
317
-		$cursor->closeCursor();
318
-
319
-		return $entities;
320
-	}
321
-
322
-
323
-	/**
324
-	 * Returns an db result and throws exceptions when there are more or less
325
-	 * results
326
-	 *
327
-	 * @param IQueryBuilder $query
328
-	 * @throws DoesNotExistException if the item does not exist
329
-	 * @throws MultipleObjectsReturnedException if more than one item exist
330
-	 * @return Entity the entity
331
-	 * @since 14.0.0
332
-	 */
333
-	protected function findEntity(IQueryBuilder $query): Entity {
334
-		return $this->mapRowToEntity($this->findOneQuery($query));
335
-	}
45
+    /** @var string */
46
+    protected $tableName;
47
+
48
+    /** @var string */
49
+    protected $entityClass;
50
+
51
+    /** @var IDBConnection */
52
+    protected $db;
53
+
54
+    /**
55
+     * @param IDBConnection $db Instance of the Db abstraction layer
56
+     * @param string $tableName the name of the table. set this to allow entity
57
+     * @param string $entityClass the name of the entity that the sql should be
58
+     * mapped to queries without using sql
59
+     * @since 14.0.0
60
+     */
61
+    public function __construct(IDBConnection $db, string $tableName, string $entityClass=null) {
62
+        $this->db = $db;
63
+        $this->tableName = $tableName;
64
+
65
+        // if not given set the entity name to the class without the mapper part
66
+        // cache it here for later use since reflection is slow
67
+        if ($entityClass === null) {
68
+            $this->entityClass = str_replace('Mapper', '', \get_class($this));
69
+        } else {
70
+            $this->entityClass = $entityClass;
71
+        }
72
+    }
73
+
74
+
75
+    /**
76
+     * @return string the table name
77
+     * @since 14.0.0
78
+     */
79
+    public function getTableName(): string {
80
+        return $this->tableName;
81
+    }
82
+
83
+
84
+    /**
85
+     * Deletes an entity from the table
86
+     * @param Entity $entity the entity that should be deleted
87
+     * @return Entity the deleted entity
88
+     * @since 14.0.0
89
+     */
90
+    public function delete(Entity $entity): Entity {
91
+        $qb = $this->db->getQueryBuilder();
92
+
93
+        $idType = $this->getParameterTypeForProperty($entity, 'id');
94
+
95
+        $qb->delete($this->tableName)
96
+            ->where(
97
+                $qb->expr()->eq('id', $qb->createNamedParameter($entity->getId(), $idType))
98
+            );
99
+        $qb->execute();
100
+        return $entity;
101
+    }
102
+
103
+
104
+    /**
105
+     * Creates a new entry in the db from an entity
106
+     * @param Entity $entity the entity that should be created
107
+     * @return Entity the saved entity with the set id
108
+     * @since 14.0.0
109
+     * @suppress SqlInjectionChecker
110
+     */
111
+    public function insert(Entity $entity): Entity {
112
+        // get updated fields to save, fields have to be set using a setter to
113
+        // be saved
114
+        $properties = $entity->getUpdatedFields();
115
+
116
+        $qb = $this->db->getQueryBuilder();
117
+        $qb->insert($this->tableName);
118
+
119
+        // build the fields
120
+        foreach ($properties as $property => $updated) {
121
+            $column = $entity->propertyToColumn($property);
122
+            $getter = 'get' . ucfirst($property);
123
+            $value = $entity->$getter();
124
+
125
+            $type = $this->getParameterTypeForProperty($entity, $property);
126
+            $qb->setValue($column, $qb->createNamedParameter($value, $type));
127
+        }
128
+
129
+        $qb->execute();
130
+
131
+        if ($entity->id === null) {
132
+            // When autoincrement is used id is always an int
133
+            $entity->setId((int)$qb->getLastInsertId());
134
+        }
135
+
136
+        return $entity;
137
+    }
138
+
139
+    /**
140
+     * Tries to creates a new entry in the db from an entity and
141
+     * updates an existing entry if duplicate keys are detected
142
+     * by the database
143
+     *
144
+     * @param Entity $entity the entity that should be created/updated
145
+     * @return Entity the saved entity with the (new) id
146
+     * @throws \InvalidArgumentException if entity has no id
147
+     * @since 15.0.0
148
+     * @suppress SqlInjectionChecker
149
+     */
150
+    public function insertOrUpdate(Entity $entity): Entity {
151
+        try {
152
+            return $this->insert($entity);
153
+        } catch (UniqueConstraintViolationException $ex) {
154
+            return $this->update($entity);
155
+        }
156
+    }
157
+
158
+    /**
159
+     * Updates an entry in the db from an entity
160
+     * @throws \InvalidArgumentException if entity has no id
161
+     * @param Entity $entity the entity that should be created
162
+     * @return Entity the saved entity with the set id
163
+     * @since 14.0.0
164
+     * @suppress SqlInjectionChecker
165
+     */
166
+    public function update(Entity $entity): Entity {
167
+        // if entity wasn't changed it makes no sense to run a db query
168
+        $properties = $entity->getUpdatedFields();
169
+        if (\count($properties) === 0) {
170
+            return $entity;
171
+        }
172
+
173
+        // entity needs an id
174
+        $id = $entity->getId();
175
+        if ($id === null) {
176
+            throw new \InvalidArgumentException(
177
+                'Entity which should be updated has no id');
178
+        }
179
+
180
+        // get updated fields to save, fields have to be set using a setter to
181
+        // be saved
182
+        // do not update the id field
183
+        unset($properties['id']);
184
+
185
+        $qb = $this->db->getQueryBuilder();
186
+        $qb->update($this->tableName);
187
+
188
+        // build the fields
189
+        foreach ($properties as $property => $updated) {
190
+            $column = $entity->propertyToColumn($property);
191
+            $getter = 'get' . ucfirst($property);
192
+            $value = $entity->$getter();
193
+
194
+            $type = $this->getParameterTypeForProperty($entity, $property);
195
+            $qb->set($column, $qb->createNamedParameter($value, $type));
196
+        }
197
+
198
+        $idType = $this->getParameterTypeForProperty($entity, 'id');
199
+
200
+        $qb->where(
201
+            $qb->expr()->eq('id', $qb->createNamedParameter($id, $idType))
202
+        );
203
+        $qb->execute();
204
+
205
+        return $entity;
206
+    }
207
+
208
+    /**
209
+     * Returns the type parameter for the QueryBuilder for a specific property
210
+     * of the $entity
211
+     *
212
+     * @param Entity $entity   The entity to get the types from
213
+     * @param string $property The property of $entity to get the type for
214
+     * @return int
215
+     * @since 16.0.0
216
+     */
217
+    protected function getParameterTypeForProperty(Entity $entity, string $property): int {
218
+        $types = $entity->getFieldTypes();
219
+
220
+        if (!isset($types[ $property ])) {
221
+            return IQueryBuilder::PARAM_STR;
222
+        }
223
+
224
+        switch ($types[ $property ]) {
225
+            case 'int':
226
+            case 'integer':
227
+                return IQueryBuilder::PARAM_INT;
228
+            case 'string':
229
+                return IQueryBuilder::PARAM_STR;
230
+            case 'bool':
231
+            case 'boolean':
232
+                return IQueryBuilder::PARAM_BOOL;
233
+            case 'blob':
234
+                return IQueryBuilder::PARAM_LOB;
235
+        }
236
+
237
+        return IQueryBuilder::PARAM_STR;
238
+    }
239
+
240
+    /**
241
+     * Returns an db result and throws exceptions when there are more or less
242
+     * results
243
+     *
244
+     * @see findEntity
245
+     *
246
+     * @param IQueryBuilder $query
247
+     * @throws DoesNotExistException if the item does not exist
248
+     * @throws MultipleObjectsReturnedException if more than one item exist
249
+     * @return array the result as row
250
+     * @since 14.0.0
251
+     */
252
+    protected function findOneQuery(IQueryBuilder $query): array {
253
+        $cursor = $query->execute();
254
+
255
+        $row = $cursor->fetch();
256
+        if ($row === false) {
257
+            $cursor->closeCursor();
258
+            $msg = $this->buildDebugMessage(
259
+                'Did expect one result but found none when executing', $query
260
+            );
261
+            throw new DoesNotExistException($msg);
262
+        }
263
+
264
+        $row2 = $cursor->fetch();
265
+        $cursor->closeCursor();
266
+        if ($row2 !== false) {
267
+            $msg = $this->buildDebugMessage(
268
+                'Did not expect more than one result when executing', $query
269
+            );
270
+            throw new MultipleObjectsReturnedException($msg);
271
+        }
272
+
273
+        return $row;
274
+    }
275
+
276
+    /**
277
+     * @param string $msg
278
+     * @param IQueryBuilder $sql
279
+     * @return string
280
+     * @since 14.0.0
281
+     */
282
+    private function buildDebugMessage(string $msg, IQueryBuilder $sql): string {
283
+        return $msg .
284
+            ': query "' . $sql->getSQL() . '"; ';
285
+    }
286
+
287
+
288
+    /**
289
+     * Creates an entity from a row. Automatically determines the entity class
290
+     * from the current mapper name (MyEntityMapper -> MyEntity)
291
+     *
292
+     * @param array $row the row which should be converted to an entity
293
+     * @return Entity the entity
294
+     * @since 14.0.0
295
+     */
296
+    protected function mapRowToEntity(array $row): Entity {
297
+        return \call_user_func($this->entityClass .'::fromRow', $row);
298
+    }
299
+
300
+
301
+    /**
302
+     * Runs a sql query and returns an array of entities
303
+     *
304
+     * @param IQueryBuilder $query
305
+     * @return Entity[] all fetched entities
306
+     * @since 14.0.0
307
+     */
308
+    protected function findEntities(IQueryBuilder $query): array {
309
+        $cursor = $query->execute();
310
+
311
+        $entities = [];
312
+
313
+        while ($row = $cursor->fetch()) {
314
+            $entities[] = $this->mapRowToEntity($row);
315
+        }
316
+
317
+        $cursor->closeCursor();
318
+
319
+        return $entities;
320
+    }
321
+
322
+
323
+    /**
324
+     * Returns an db result and throws exceptions when there are more or less
325
+     * results
326
+     *
327
+     * @param IQueryBuilder $query
328
+     * @throws DoesNotExistException if the item does not exist
329
+     * @throws MultipleObjectsReturnedException if more than one item exist
330
+     * @return Entity the entity
331
+     * @since 14.0.0
332
+     */
333
+    protected function findEntity(IQueryBuilder $query): Entity {
334
+        return $this->mapRowToEntity($this->findOneQuery($query));
335
+    }
336 336
 }
Please login to merge, or discard this patch.
apps/contactsinteraction/lib/Db/RecentContact.php 1 patch
Indentation   +20 added lines, -20 removed lines patch added patch discarded remove patch
@@ -43,30 +43,30 @@
 block discarded – undo
43 43
  */
44 44
 class RecentContact extends Entity {
45 45
 
46
-	/** @var string */
47
-	protected $actorUid;
46
+    /** @var string */
47
+    protected $actorUid;
48 48
 
49
-	/** @var string|null */
50
-	protected $uid;
49
+    /** @var string|null */
50
+    protected $uid;
51 51
 
52
-	/** @var string|null */
53
-	protected $email;
52
+    /** @var string|null */
53
+    protected $email;
54 54
 
55
-	/** @var string|null */
56
-	protected $federatedCloudId;
55
+    /** @var string|null */
56
+    protected $federatedCloudId;
57 57
 
58
-	/** @var string */
59
-	protected $card;
58
+    /** @var string */
59
+    protected $card;
60 60
 
61
-	/** @var int */
62
-	protected $lastContact;
61
+    /** @var int */
62
+    protected $lastContact;
63 63
 
64
-	public function __construct() {
65
-		$this->addType('actorUid', 'string');
66
-		$this->addType('uid', 'string');
67
-		$this->addType('email', 'string');
68
-		$this->addType('federatedCloudId', 'string');
69
-		$this->addType('card', 'blob');
70
-		$this->addType('lastContact', 'int');
71
-	}
64
+    public function __construct() {
65
+        $this->addType('actorUid', 'string');
66
+        $this->addType('uid', 'string');
67
+        $this->addType('email', 'string');
68
+        $this->addType('federatedCloudId', 'string');
69
+        $this->addType('card', 'blob');
70
+        $this->addType('lastContact', 'int');
71
+    }
72 72
 }
Please login to merge, or discard this patch.