Passed
Push — develop-3.3.x ( 79c962...91aefb )
by Mario
02:34
created

main::set_name()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 6
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 2
nc 1
nop 1
dl 0
loc 6
rs 10
c 0
b 0
f 0
1
<?php
2
/**
3
 *
4
 * PayPal Donation extension for the phpBB Forum Software package.
5
 *
6
 * @copyright (c) 2015-2020 Skouat
7
 * @license GNU General Public License, version 2 (GPL-2.0)
8
 *
9
 */
10
11
namespace skouat\ppde\entity;
12
13
use phpbb\db\driver\driver_interface;
14
use phpbb\language\language;
15
16
abstract class main
17
{
18
	/** @type string */
19
	protected $u_action;
20
	/**
21
	 * Declare overridden properties
22
	 */
23
	protected $db;
24
	protected $data;
25
	protected $lang_key_prefix;
26
	protected $lang_key_suffix;
27
	protected $language;
28
	protected $table_name;
29
	protected $table_schema;
30
31
	/**
32
	 * Construct
33
	 *
34
	 * @param driver_interface $db              Database object
35
	 * @param language         $language        Language object
36
	 * @param string           $lang_key_prefix Prefix for the messages thrown by exceptions
37
	 * @param string           $lang_key_suffix Suffix for the messages thrown by exceptions
38
	 * @param string           $table_name      Table name
39
	 * @param array            $table_schema    Array with column names to overwrite and type of data
40
	 *
41
	 * @access public
42
	 */
43
	public function __construct(
44
		driver_interface $db,
45
		language $language,
46
		$lang_key_prefix = '',
47
		$lang_key_suffix = '',
48
		$table_name = '',
49
		$table_schema = []
50
	)
51
	{
52
		$this->db = $db;
53
		$this->language = $language;
54
		$this->lang_key_prefix = $lang_key_prefix;
55
		$this->lang_key_suffix = $lang_key_suffix;
56
		$this->table_name = $table_name;
57
		$this->table_schema = $table_schema;
58
	}
59
60
	/**
61
	 * Set data in the $entity object.
62
	 * Use call_user_func_array() to call $entity function
63
	 *
64
	 * @param array $data_ary
65
	 *
66
	 * @return void
67
	 * @access public
68
	 */
69
	public function set_entity_data(array $data_ary): void
70
	{
71
		foreach ($data_ary as $key => $value)
72
		{
73
			$schema_key = 'item_' . $key;
74
			if (isset($this->table_schema[$schema_key]))
75
			{
76
				settype($value, $this->table_schema[$schema_key]['type']);
77
				$this->data[$this->table_schema[$schema_key]['name']] = $value;
78
			}
79
			else
80
			{
81
				call_user_func_array([$this, 'set_' . $key], [$key]);
82
			}
83
		}
84
	}
85
86
	/**
87
	 * Parse data to the entity
88
	 *
89
	 * @param string $run_before_insert Name of the function to call before SQL INSERT
90
	 *
91
	 * @return string
92
	 * @access public
93
	 */
94
	public function add_edit_data($run_before_insert = ''): string
95
	{
96
		if ($this->get_id())
97
		{
98
			// Save the edited item entity to the database
99
			$this->save($this->check_required_field());
100
			return 'UPDATED';
101
		}
102
103
		// Insert the data to the database
104
		$this->insert($run_before_insert);
105
106
		// Get the newly inserted identifier
107
		$id = $this->get_id();
108
109
		// Reload the data to return a fresh entity
110
		$this->load($id);
111
		return 'ADDED';
112
	}
113
114
	/**
115
	 * Insert the item for the first time
116
	 *
117
	 * Will throw an exception if the item was already inserted (call save() instead)
118
	 *
119
	 * @param string $run_before_insert
120
	 *
121
	 * @return main $this object for chaining calls; load()->set()->save()
122
	 * @access public
123
	 */
124
	public function insert($run_before_insert = '')
125
	{
126
		if (!empty($this->data[$this->table_schema['item_id']['name']]))
127
		{
128
			// The item already exists
129
			$this->display_warning_message($this->lang_key_prefix . '_EXIST');
130
		}
131
132
		// Run some stuff before insert data in database
133
		$this->run_function_before_action($run_before_insert);
134
135
		// Make extra sure there is no item_id set
136
		unset($this->data[$this->table_schema['item_id']['name']]);
137
138
		// Insert the item data to the database
139
		$sql = 'INSERT INTO ' . $this->table_name . ' ' . $this->db->sql_build_array('INSERT', $this->data);
140
		$this->db->sql_query($sql);
141
142
		// Set the item_id using the id created by the SQL insert
143
		$this->data[$this->table_schema['item_id']['name']] = (int) $this->db->sql_last_inserted_id();
144
145
		return $this;
146
	}
147
148
	/**
149
	 * Display a user warning message
150
	 *
151
	 * @param string $lang_key
152
	 * @param string $args
153
	 *
154
	 * @return void
155
	 * @access protected
156
	 */
157
	protected function display_warning_message($lang_key, $args = ''): void
158
	{
159
		$message = call_user_func_array([$this->language, 'lang'], array_merge([strtoupper($lang_key), $args])) . $this->adm_back_link_exists();
160
		trigger_error($message, E_USER_WARNING);
161
	}
162
163
	/**
164
	 * Checks if the adm_back_link function is loaded
165
	 *
166
	 * @return string
167
	 * @access protected
168
	 */
169
	protected function adm_back_link_exists(): string
170
	{
171
		return (function_exists('adm_back_link')) ? adm_back_link($this->u_action) : '';
172
	}
173
174
	/**
175
	 * Run function before do some alter some data in the database
176
	 *
177
	 * @param string $function_name
178
	 *
179
	 * @return bool
180
	 * @access private
181
	 */
182
	private function run_function_before_action($function_name): bool
183
	{
184
		$func_result = true;
185
		if ($function_name)
186
		{
187
			$func_result = (bool) call_user_func([$this, $function_name]);
188
		}
189
190
		return $func_result;
191
	}
192
193
	/**
194
	 * Save the current settings to the database
195
	 *
196
	 * This must be called before closing or any changes will not be saved!
197
	 * If adding a item (saving for the first time), you must call insert() or an exception will be thrown
198
	 *
199
	 * @param bool $required_fields
200
	 *
201
	 * @return main $this object for chaining calls; load()->set()->save()
202
	 * @access public
203
	 */
204
	public function save($required_fields)
205
	{
206
		if ($required_fields)
207
		{
208
			// The item already exists
209
			$this->display_warning_message($this->lang_key_prefix . '_NO_' . $this->lang_key_suffix);
210
		}
211
212
		$sql = 'UPDATE ' . $this->table_name . '
213
			SET ' . $this->db->sql_build_array('UPDATE', $this->data) . '
214
			WHERE ' . $this->db->sql_escape($this->table_schema['item_id']['name']) . ' = ' . $this->get_id();
215
		$this->db->sql_query($sql);
216
217
		return $this;
218
	}
219
220
	/**
221
	 * Get id
222
	 *
223
	 * @return int Item identifier
224
	 * @access public
225
	 */
226
	public function get_id(): int
227
	{
228
		return (int) ($this->data[$this->table_schema['item_id']['name']] ?? 0);
229
	}
230
231
	/**
232
	 * Check the Identifier of the called data exists in the database
233
	 *
234
	 * @param string $sql SQL Query
235
	 *
236
	 * @return bool
237
	 * @access public
238
	 */
239
	public function data_exists($sql): bool
240
	{
241
		$this->db->sql_query($sql);
242
		$this->set_id($this->db->sql_fetchfield($this->table_schema['item_id']['name']));
243
244
		return (bool) $this->data[$this->table_schema['item_id']['name']];
245
	}
246
247
	/**
248
	 * Set item Identifier
249
	 *
250
	 * @param int $id
251
	 *
252
	 * @return main $this object for chaining calls; load()->set()->save()
253
	 * @access public
254
	 */
255
	public function set_id(int $id)
256
	{
257
		$this->data[$this->table_schema['item_id']['name']] = $id;
258
259
		return $this;
260
	}
261
262
	/**
263
	 * SQL Query to return the ID of selected item
264
	 *
265
	 * @return string
266
	 * @access public
267
	 */
268
	public function build_sql_data_exists(): string
269
	{
270
		return 'SELECT ' . $this->table_schema['item_id']['name'] . '
271
 			FROM ' . $this->table_name . '
272
			WHERE ' . $this->db->sql_escape($this->table_schema['item_id']['name']) . ' = ' . (int) $this->data[$this->table_schema['item_id']['name']];
273
	}
274
275
	/**
276
	 * Load the data from the database
277
	 *
278
	 * @param int $id
279
	 *
280
	 * @return main $this object for chaining calls; load()->set()->save()
281
	 * @access public
282
	 */
283
	public function load($id)
284
	{
285
		$sql = 'SELECT *
286
			FROM ' . $this->table_name . '
287
			WHERE ' . $this->db->sql_escape($this->table_schema['item_id']['name']) . ' = ' . (int) $id;
288
		$result = $this->db->sql_query($sql);
289
		$this->data = $this->db->sql_fetchrow($result);
290
		$this->db->sql_freeresult($result);
291
292
		if ($this->data === false)
293
		{
294
			// An item does not exist
295
			$this->display_warning_message($this->lang_key_prefix . '_NO_' . $this->lang_key_suffix);
296
		}
297
298
		return $this;
299
	}
300
301
	/**
302
	 * Get Item name
303
	 *
304
	 * @return string Item name
305
	 * @access public
306
	 */
307
	public function get_name(): string
308
	{
309
		return (string) ($this->data[$this->table_schema['item_name']['name']] ?? '');
310
	}
311
312
	/**
313
	 * Set page url
314
	 *
315
	 * @param string $u_action Custom form action
316
	 *
317
	 * @return void
318
	 * @access public
319
	 */
320
	public function set_page_url($u_action): void
321
	{
322
		$this->u_action = $u_action;
323
	}
324
325
	/**
326
	 * Check if required field is set
327
	 *
328
	 * @return bool
329
	 * @access public
330
	 */
331
	public function check_required_field(): bool
332
	{
333
		return false;
334
	}
335
336
	/**
337
	 * Delete data from the database
338
	 *
339
	 * @param int    $id
340
	 * @param string $action_before_delete Function to start before deleting data.
341
	 * @param string $sql_where
342
	 * @param bool   $all                  Set to true if you want delete all data from the table.
343
	 *
344
	 * @return bool
345
	 * @access public
346
	 */
347
	public function delete($id, $action_before_delete = '', $sql_where = '', $all = false): bool
348
	{
349
		$where_clause = '';
350
351
		if (!$all)
352
		{
353
			if (empty($sql_where) && $this->disallow_deletion($id))
354
			{
355
				// The item selected does not exists
356
				$this->display_warning_message($this->lang_key_prefix . '_NO_' . $this->lang_key_suffix);
357
			}
358
359
			$where_clause = !empty($sql_where) ? $sql_where : ' WHERE ' . $this->db->sql_escape($this->table_schema['item_id']['name']) . ' = ' . (int) $id;
360
		}
361
362
		$this->run_function_before_action($action_before_delete);
363
364
		// Delete data from the database
365
		$sql = 'DELETE FROM ' . $this->table_name . $where_clause;
366
		$this->db->sql_query($sql);
367
368
		return (bool) $this->db->sql_affectedrows();
369
	}
370
371
	/**
372
	 * Returns if we can proceed to item deletion
373
	 *
374
	 * @param int $id
375
	 *
376
	 * @return bool
377
	 */
378
	private function disallow_deletion($id): bool
379
	{
380
		return empty($this->data[$this->table_schema['item_id']['name']]) || ((int) $this->data[$this->table_schema['item_id']['name']] !== $id);
381
	}
382
383
	/**
384
	 * Get data from the database
385
	 *
386
	 * @param string $sql
387
	 * @param array  $additional_table_schema
388
	 * @param int    $limit
389
	 * @param int    $limit_offset
390
	 * @param bool   $override
391
	 *
392
	 * @return array
393
	 * @access public
394
	 */
395
	public function get_data($sql, $additional_table_schema = [], $limit = 0, $limit_offset = 0, $override = false): array
396
	{
397
		$entities = [];
398
		$result = $this->limit_query($sql, $limit, $limit_offset);
399
400
		while ($row = $this->db->sql_fetchrow($result))
401
		{
402
			// Import each row into an entity
403
			$entities[] = $this->import($row, $additional_table_schema, $override);
404
		}
405
		$this->db->sql_freeresult($result);
406
407
		// Return all entities
408
		return $entities;
409
	}
410
411
	/**
412
	 * Use query limit if requested
413
	 *
414
	 * @param string $sql
415
	 * @param int    $limit
416
	 * @param int    $offset
417
	 *
418
	 * @return mixed
419
	 * @access private
420
	 */
421
	private function limit_query($sql, $limit, $offset)
422
	{
423
		return empty($limit) ? $this->db->sql_query($sql) : $this->db->sql_query_limit($sql, $limit, $offset);
424
	}
425
426
	/**
427
	 * Import and validate data
428
	 *
429
	 * Used when the data is already loaded externally.
430
	 * Any existing data on this item is over-written.
431
	 * All data is validated and an exception is thrown if any data is invalid.
432
	 *
433
	 * @param array $data Data array, typically from the database
434
	 * @param array $additional_table_schema
435
	 * @param bool  $override
436
	 *
437
	 * @return array $this->data
438
	 * @access public
439
	 */
440
	public function import($data, $additional_table_schema = [], $override = false): array
441
	{
442
		// Clear out any saved data
443
		$this->data = [];
444
445
		// Adds additional field to the table schema
446
		$this->table_schema = !$override ? array_merge($this->table_schema, $additional_table_schema) : $additional_table_schema;
447
448
		// Go through the basic fields and set them to our data array
449
		foreach ($this->table_schema as $field)
450
		{
451
			// If the data wasn't sent to us, throw an exception
452
			if (!isset($data[$field['name']]))
453
			{
454
				$this->display_warning_message('EXCEPTION_INVALID_FIELD', $field['name']);
455
			}
456
457
			// settype passes values by reference
458
			$value = $data[$field['name']];
459
460
			// We're using settype to enforce data types
461
			settype($value, $field['type']);
462
463
			$this->data[$field['name']] = $value;
464
		}
465
466
		return $this->data;
467
	}
468
}
469