Completed
Pull Request — 3.4 (#46)
by David
06:17
created

AbstractTDBMObject::setRef()   B

Complexity

Conditions 6
Paths 10

Size

Total Lines 20
Code Lines 13

Duplication

Lines 20
Ratio 100 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 20
loc 20
rs 8.8571
cc 6
eloc 13
nc 10
nop 3
1
<?php
2
namespace Mouf\Database\TDBM;
3
4
/*
5
 Copyright (C) 2006-2015 David Négrier - THE CODING MACHINE
6
7
 This program is free software; you can redistribute it and/or modify
8
 it under the terms of the GNU General Public License as published by
9
 the Free Software Foundation; either version 2 of the License, or
10
 (at your option) any later version.
11
12
 This program is distributed in the hope that it will be useful,
13
 but WITHOUT ANY WARRANTY; without even the implied warranty of
14
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15
 GNU General Public License for more details.
16
17
 You should have received a copy of the GNU General Public License
18
 along with this program; if not, write to the Free Software
19
 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
20
 */
21
use Doctrine\DBAL\Driver\Connection;
22
use Mouf\Database\TDBM\Filters\FilterInterface;
23
24
25
/**
26
 * Instances of this class represent a "bean". Usually, a bean is mapped to a row of one table.
27
 * In some special cases (where inheritance is used), beans can be scattered on several tables.
28
 * Therefore, a TDBMObject is really a set of DbRow objects that represent one row in a table.
29
 *
30
 * @author David Negrier
31
 */
32
abstract class AbstractTDBMObject implements \JsonSerializable, FilterInterface {
33
34
	/**
35
	 * The service this object is bound to.
36
	 * 
37
	 * @var TDBMService
38
	 */
39
	protected $tdbmService;
40
41
	/**
42
	 * An array of DbRow, indexed by table name.
43
	 * @var DbRow[]
44
	 */
45
	protected $dbRows = array();
46
47
	/**
48
	 * One of TDBMObjectStateEnum::STATE_NEW, TDBMObjectStateEnum::STATE_NOT_LOADED, TDBMObjectStateEnum::STATE_LOADED, TDBMObjectStateEnum::STATE_DELETED.
49
	 * $status = TDBMObjectStateEnum::STATE_NEW when a new object is created with DBMObject:getNewObject.
50
	 * $status = TDBMObjectStateEnum::STATE_NOT_LOADED when the object has been retrieved with getObject but when no data has been accessed in it yet.
51
	 * $status = TDBMObjectStateEnum::STATE_LOADED when the object is cached in memory.
52
	 *
53
	 * @var string
54
	 */
55
	private $status;
56
57
	/**
58
	 * True if an error has occurred while saving. The user will have to call save() explicitly or to modify one of its members to save it again.
59
	 * TODO: hide this with getters and setters
60
	 *
61
	 * @var boolean
62
	 */
63
	public $db_onerror;
64
65
	private $db_connection;
66
	
67
	/**
68
	 * True to automatically save the object.
69
	 * If false, the user must explicitly call the save() method to save the object. 
70
	 * TODO: hide this with getters and setters
71
	 * 
72
	 * @var boolean
73
	 */
74
	public $db_autosave;
75
76
	/**
77
	 * Array storing beans related via many to many relationships (pivot tables)
78
	 * @var \SplObjectStorage[] Key: pivot table name, value: SplObjectStorage
79
	 */
80
	private $relationships = [];
81
82
	/**
83
	 *
84
	 * @var bool[] Key: pivot table name, value: whether a query was performed to load the data.
85
	 */
86
	private $loadedRelationships = [];
87
88
	/**
89
	 * Used with $primaryKeys when we want to retrieve an existing object
90
	 * and $primaryKeys=[] if we want a new object
91
	 *
92
	 * @param string $tableName
93
	 * @param array $primaryKeys
94
	 * @param TDBMService $tdbmService
95
	 * @throws TDBMException
96
	 * @throws TDBMInvalidOperationException
97
	 */
98
	public function __construct($tableName=null, array $primaryKeys=array(), TDBMService $tdbmService=null) {
99
		// FIXME: lazy loading should be forbidden on tables with inheritance and dynamic type assignation...
100
		if (!empty($tableName)) {
101
			$this->dbRows[$tableName] = new DbRow($this, $tableName, $primaryKeys, $tdbmService);
102
		}
103
104
		if ($tdbmService === null) {
105
			$this->_setStatus(TDBMObjectStateEnum::STATE_DETACHED);
106
		} else {
107
			$this->_attach($tdbmService);
108
			if (!empty($primaryKeys)) {
109
				$this->_setStatus(TDBMObjectStateEnum::STATE_NOT_LOADED);
110
			} else {
111
				$this->_setStatus(TDBMObjectStateEnum::STATE_NEW);
112
			}
113
		}
114
	}
115
116
	/**
117
	 * Alternative constructor called when data is fetched from database via a SELECT.
118
	 *
119
	 * @param array $beanData array<table, array<column, value>>
120
	 * @param TDBMService $tdbmService
121
	 */
122
	public function _constructFromData(array $beanData, TDBMService $tdbmService) {
123
		$this->tdbmService = $tdbmService;
124
125
		foreach ($beanData as $table => $columns) {
126
			$this->dbRows[$table] = new DbRow($this, $table, $tdbmService->_getPrimaryKeysFromObjectData($table, $columns), $tdbmService, $columns);
127
		}
128
129
		$this->status = TDBMObjectStateEnum::STATE_LOADED;
130
	}
131
132
	/**
133
	 * Alternative constructor called when bean is lazily loaded.
134
	 *
135
	 * @param string $tableName
136
	 * @param array $primaryKeys
137
	 * @param TDBMService $tdbmService
138
	 */
139
	public function _constructLazy($tableName, array $primaryKeys, TDBMService $tdbmService) {
140
		$this->tdbmService = $tdbmService;
141
142
		$this->dbRows[$tableName] = new DbRow($this, $tableName, $primaryKeys, $tdbmService);
143
144
		$this->status = TDBMObjectStateEnum::STATE_NOT_LOADED;
145
	}
146
147
	public function _attach(TDBMService $tdbmService) {
148
		if ($this->status !== TDBMObjectStateEnum::STATE_DETACHED) {
149
			throw new TDBMInvalidOperationException('Cannot attach an object that is already attached to TDBM.');
150
		}
151
		$this->tdbmService = $tdbmService;
152
153
		// If we attach this object, we must work to make sure the tables are in ascending order (from low level to top level)
154
		$tableNames = array_keys($this->dbRows);
155
		$tableNames = $this->tdbmService->_getLinkBetweenInheritedTables($tableNames);
156
		$tableNames = array_reverse($tableNames);
157
158
		$newDbRows = [];
159
160
		foreach ($tableNames as $table) {
161
			if (!isset($this->dbRows[$table])) {
162
				$this->registerTable($table);
163
			}
164
			$newDbRows[$table] = $this->dbRows[$table];
165
		}
166
		$this->dbRows = $newDbRows;
167
168
		$this->status = TDBMObjectStateEnum::STATE_NEW;
169
		foreach ($this->dbRows as $dbRow) {
170
			$dbRow->_attach($tdbmService);
171
		}
172
	}
173
174
	/**
175
	 * Returns true if the object will save automatically, false if an explicit call to save() is required.
176
	 *
177
	 * @return boolean
178
	 */
179
	public function getAutoSaveMode() {
180
		return $this->db_autosave;
181
	}
182
	
183
	/**
184
	 * Sets the autosave mode:
185
	 * true if the object will save automatically,
186
	 * false if an explicit call to save() is required.
187
	 *
188
	 * @param boolean $autoSave
189
	 */
190
	public function setAutoSaveMode($autoSave) {
191
		$this->db_autosave = $autoSave;
192
	}
193
194
	/**
195
	 * Sets the state of the TDBM Object
196
	 * One of TDBMObjectStateEnum::STATE_NEW, TDBMObjectStateEnum::STATE_NOT_LOADED, TDBMObjectStateEnum::STATE_LOADED, TDBMObjectStateEnum::STATE_DELETED.
197
	 * $status = TDBMObjectStateEnum::STATE_NEW when a new object is created with DBMObject:getNewObject.
198
	 * $status = TDBMObjectStateEnum::STATE_NOT_LOADED when the object has been retrieved with getObject but when no data has been accessed in it yet.
199
	 * $status = TDBMObjectStateEnum::STATE_LOADED when the object is cached in memory.
200
	 * @param string $state
201
	 */
202
	public function _setStatus($state){
203
		$this->status = $state;
204
205
		// TODO: we might ignore the loaded => dirty state here! dirty status comes from the db_row itself.
206
		foreach ($this->dbRows as $dbRow) {
207
			$dbRow->_setStatus($state);
208
		}
209
	}
210
211 View Code Duplication
	public function get($var, $tableName = null) {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
212
		if ($tableName === null) {
213
			if (count($this->dbRows) > 1) {
214
				throw new TDBMException('This object is based on several tables. You must specify which table you are retrieving data from.');
215
			} elseif (count($this->dbRows) === 1) {
216
				$tableName = array_keys($this->dbRows)[0];
217
			}
218
		}
219
220
		if (!isset($this->dbRows[$tableName])) {
221
			if (count($this->dbRows[$tableName] === 0)) {
222
				throw new TDBMException('Object is not yet bound to any table.');
223
			} else {
224
				throw new TDBMException('Unknown table "'.$tableName.'"" in object.');
225
			}
226
		}
227
228
		return $this->dbRows[$tableName]->get($var);
229
	}
230
231
	/**
232
	 * Returns true if a column is set, false otherwise.
233
	 * 
234
	 * @param string $var
235
	 * @return boolean
236
	 */
237 View Code Duplication
	public function has($var, $tableName = null) {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
238
		if ($tableName === null) {
239
			if (count($this->dbRows) > 1) {
240
				throw new TDBMException('This object is based on several tables. You must specify which table you are retrieving data from.');
241
			} elseif (count($this->dbRows) === 1) {
242
				$tableName = array_keys($this->dbRows)[0];
243
			}
244
		}
245
246
		if (!isset($this->dbRows[$tableName])) {
247
			if (count($this->dbRows[$tableName] === 0)) {
248
				throw new TDBMException('Object is not yet bound to any table.');
249
			} else {
250
				throw new TDBMException('Unknown table "'.$tableName.'"" in object.');
251
			}
252
		}
253
254
		return $this->dbRows[$tableName]->has($var);
0 ignored issues
show
Bug introduced by
The method has() does not seem to exist on object<Mouf\Database\TDBM\DbRow>.

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...
255
	}
256
	
257 View Code Duplication
	public function set($var, $value, $tableName = null) {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
258
		if ($tableName === null) {
259
			if (count($this->dbRows) > 1) {
260
				throw new TDBMException('This object is based on several tables. You must specify which table you are retrieving data from.');
261
			} elseif (count($this->dbRows) === 1) {
262
				$tableName = array_keys($this->dbRows)[0];
263
			} else {
264
				throw new TDBMException("Please specify a table for this object.");
265
			}
266
		}
267
268
		if (!isset($this->dbRows[$tableName])) {
269
			$this->registerTable($tableName);
270
		}
271
272
		$this->dbRows[$tableName]->set($var, $value);
273
		if ($this->dbRows[$tableName]->_getStatus() === TDBMObjectStateEnum::STATE_DIRTY) {
274
			$this->status = TDBMObjectStateEnum::STATE_DIRTY;
275
		}
276
	}
277
278
	/**
279
	 * @param string $foreignKeyName
280
	 * @param AbstractTDBMObject $bean
281
	 */
282 View Code Duplication
	public function setRef($foreignKeyName, AbstractTDBMObject $bean, $tableName = null) {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
283
		if ($tableName === null) {
284
			if (count($this->dbRows) > 1) {
285
				throw new TDBMException('This object is based on several tables. You must specify which table you are retrieving data from.');
286
			} elseif (count($this->dbRows) === 1) {
287
				$tableName = array_keys($this->dbRows)[0];
288
			} else {
289
				throw new TDBMException("Please specify a table for this object.");
290
			}
291
		}
292
293
		if (!isset($this->dbRows[$tableName])) {
294
			$this->registerTable($tableName);
295
		}
296
297
		$this->dbRows[$tableName]->setRef($foreignKeyName, $bean);
298
		if ($this->dbRows[$tableName]->_getStatus() === TDBMObjectStateEnum::STATE_DIRTY) {
299
			$this->status = TDBMObjectStateEnum::STATE_DIRTY;
300
		}
301
	}
302
303
	/**
304
	 * @param string $foreignKeyName A unique name for this reference
305
	 * @return AbstractTDBMObject|null
306
	 */
307 View Code Duplication
	public function getRef($foreignKeyName, $tableName = null) {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
308
		if ($tableName === null) {
309
			if (count($this->dbRows) > 1) {
310
				throw new TDBMException('This object is based on several tables. You must specify which table you are retrieving data from.');
311
			} elseif (count($this->dbRows) === 1) {
312
				$tableName = array_keys($this->dbRows)[0];
313
			}
314
		}
315
316
		if (!isset($this->dbRows[$tableName])) {
317
			if (count($this->dbRows[$tableName] === 0)) {
318
				throw new TDBMException('Object is not yet bound to any table.');
319
			} else {
320
				throw new TDBMException('Unknown table "'.$tableName.'"" in object.');
321
			}
322
		}
323
324
		return $this->dbRows[$tableName]->getRef($foreignKeyName);
325
	}
326
327
	/**
328
	 * Adds a many to many relationship to this bean.
329
	 * @param string $pivotTableName
330
	 * @param AbstractTDBMObject $remoteBean
331
	 */
332
	protected function addRelationship($pivotTableName, AbstractTDBMObject $remoteBean) {
333
		$this->setRelationship($pivotTableName, $remoteBean, 'new');
334
	}
335
336
	/**
337
	 * Returns true if there is a relationship to this bean.
338
	 * @param string $pivotTableName
339
	 * @param AbstractTDBMObject $remoteBean
340
	 * @return bool
341
	 */
342
	protected function hasRelationship($pivotTableName, AbstractTDBMObject $remoteBean) {
343
		$storage = $this->retrieveRelationshipsStorage($pivotTableName);
344
345
		if ($storage->contains($remoteBean)) {
346
			if ($storage[$remoteBean]['status'] !== 'delete') {
347
				return true;
348
			}
349
		}
350
		return false;
351
	}
352
353
	/**
354
	 * Internal TDBM method. Removes a many to many relationship from this bean.
355
	 * @param string $pivotTableName
356
	 * @param AbstractTDBMObject $remoteBean
357
	 */
358
	public function _removeRelationship($pivotTableName, AbstractTDBMObject $remoteBean) {
359
		if (isset($this->relationships[$pivotTableName][$remoteBean]) && $this->relationships[$pivotTableName][$remoteBean]['status'] === 'new') {
360
			unset($this->relationships[$pivotTableName][$remoteBean]);
361
			unset($remoteBean->relationships[$pivotTableName][$this]);
362
		} else {
363
			$this->setRelationship($pivotTableName, $remoteBean, 'delete');
364
		}
365
	}
366
367
	/**
368
	 * Returns the list of objects linked to this bean via $pivotTableName
369
	 * @param $pivotTableName
370
	 * @return \SplObjectStorage
371
	 */
372
	private function retrieveRelationshipsStorage($pivotTableName) {
373
		$storage = $this->getRelationshipStorage($pivotTableName);
374
		if ($this->status === TDBMObjectStateEnum::STATE_DETACHED || $this->status === TDBMObjectStateEnum::STATE_NEW || isset($this->loadedRelationships[$pivotTableName]) && $this->loadedRelationships[$pivotTableName]) {
375
			return $storage;
376
		}
377
378
		$beans = $this->tdbmService->_getRelatedBeans($pivotTableName, $this);
379
		$this->loadedRelationships[$pivotTableName] = true;
380
381
		foreach ($beans as $bean) {
382
			if (isset($storage[$bean])) {
383
				$oldStatus = $storage[$bean]['status'];
384
				if ($oldStatus === 'delete') {
385
					// Keep deleted things deleted
386
					continue;
387
				}
388
			}
389
			$this->setRelationship($pivotTableName, $bean, "loaded");
390
		}
391
392
		return $storage;
393
394
	}
395
396
	/**
397
	 * Internal TDBM method. Returns the list of objects linked to this bean via $pivotTableName
398
	 * @param $pivotTableName
399
	 * @return AbstractTDBMObject[]
400
	 */
401
	public function _getRelationships($pivotTableName) {
402
		return $this->relationshipStorageToArray($this->retrieveRelationshipsStorage($pivotTableName));
403
	}
404
405
	private function relationshipStorageToArray(\SplObjectStorage $storage) {
406
		$beans = [];
407
		foreach ($storage as $bean) {
408
			$statusArr = $storage[$bean];
409
			if ($statusArr['status'] !== 'delete') {
410
				$beans[] = $bean;
411
			}
412
		}
413
		return $beans;
414
	}
415
416
	/**
417
	 * Declares a relationship between
418
	 * @param string $pivotTableName
419
	 * @param AbstractTDBMObject $remoteBean
420
	 * @param string $status
421
	 */
422
	private function setRelationship($pivotTableName, AbstractTDBMObject $remoteBean, $status) {
423
		$storage = $this->getRelationshipStorage($pivotTableName);
424
		$storage->attach($remoteBean, [ 'status' => $status, 'reverse' => false ]);
425
		if ($this->status === TDBMObjectStateEnum::STATE_LOADED) {
426
			$this->_setStatus(TDBMObjectStateEnum::STATE_DIRTY);
427
		}
428
429
		$remoteStorage = $remoteBean->getRelationshipStorage($pivotTableName);
430
		$remoteStorage->attach($this, [ 'status' => $status, 'reverse' => true ]);
431
	}
432
433
	/**
434
	 * Returns the SplObjectStorage associated to this relationship (creates it if it does not exists)
435
	 * @param $pivotTableName
436
	 * @return \SplObjectStorage
437
	 */
438
	private function getRelationshipStorage($pivotTableName) {
439
		if (isset($this->relationships[$pivotTableName])) {
440
			$storage = $this->relationships[$pivotTableName];
441
		} else {
442
			$storage = new \SplObjectStorage();
443
			$this->relationships[$pivotTableName] = $storage;
444
		}
445
		return $storage;
446
	}
447
448
	/*public function __destruct() {
0 ignored issues
show
Unused Code Comprehensibility introduced by
42% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
449
		// In a destructor, no exception can be thrown (PHP 5 limitation)
450
		// So we print the error instead
451
		try {
452
			if (!$this->db_onerror && $this->db_autosave)
453
			{
454
				$this->save();
455
			}
456
		} catch (\Exception $e) {
457
			trigger_error($e->getMessage(), E_USER_ERROR);
458
		}
459
	}*/
460
461
462
	/**
463
	 * Reverts any changes made to the object and resumes it to its DB state.
464
	 * This can only be called on objects that come from database and that have not been deleted.
465
	 * Otherwise, this will throw an exception.
466
	 *
467
	 */
468
	public function discardChanges() {
469
		if ($this->status == TDBMObjectStateEnum::STATE_NEW) {
470
			throw new TDBMException("You cannot call discardChanges() on an object that has been created with getNewObject and that has not yet been saved.");
471
		}
472
473
		if ($this->status == TDBMObjectStateEnum::STATE_DELETED) {
474
			throw new TDBMException("You cannot call discardChanges() on an object that has been deleted.");
475
		}
476
			
477
		$this->_setStatus(TDBMObjectStateEnum::STATE_NOT_LOADED);
478
	}
479
480
	/**
481
	 * Method used internally by TDBM. You should not use it directly.
482
	 * This method returns the status of the TDBMObject.
483
	 * This is one of TDBMObjectStateEnum::STATE_NEW, TDBMObjectStateEnum::STATE_NOT_LOADED, TDBMObjectStateEnum::STATE_LOADED, TDBMObjectStateEnum::STATE_DELETED.
484
	 * $status = TDBMObjectStateEnum::STATE_NEW when a new object is created with DBMObject:getNewObject.
485
	 * $status = TDBMObjectStateEnum::STATE_NOT_LOADED when the object has been retrieved with getObject but when no data has been accessed in it yet.
486
	 * $status = TDBMObjectStateEnum::STATE_LOADED when the object is cached in memory.
487
	 *
488
	 * @return string
489
	 */
490
	public function _getStatus() {
491
		return $this->status;
492
	}
493
494
	
495
	/**
496
	 * Implement the unique JsonSerializable method
497
	 * @return array
498
	 */
499
	public function jsonSerialize(){
500
		// FIXME
501
		$this->_dbLoadIfNotLoaded();
0 ignored issues
show
Bug introduced by
The method _dbLoadIfNotLoaded() does not seem to exist on object<Mouf\Database\TDBM\AbstractTDBMObject>.

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...
502
		return $this->dbRow;
0 ignored issues
show
Bug introduced by
The property dbRow does not seem to exist. Did you mean dbRows?

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
503
	}
504
505
	/**
506
	 * Returns the SQL of the filter (the SQL WHERE clause).
507
	 *
508
	 * @param Connection $dbConnection
509
	 * @return string
510
	 */
511
	public function toSql(Connection $dbConnection) {
512
		return $this->getPrimaryKeyWhereStatement();
513
	}
514
515
	/**
516
	 * Returns the tables used in the filter in an array.
517
	 *
518
	 * @return array<string>
519
	 */
520
	public function getUsedTables() {
521
		return array_keys($this->dbRows);
522
	}
523
524
	/**
525
	 * Returns Where statement to query this object
526
	 *
527
	 * @return string
528
	 */
529
	private function getPrimaryKeyWhereStatement () {
530
		// Let's first get the primary keys
531
		$pk_table = $this->tdbmService->getPrimaryKeyColumns($this->dbTableName);
0 ignored issues
show
Bug introduced by
The property dbTableName does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
532
		// Now for the object_id
533
		$object_id = $this->TDBMObject_id;
0 ignored issues
show
Bug introduced by
The property TDBMObject_id does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
534
		// If there is only one primary key:
535
		if (count($pk_table)==1) {
536
			$sql_where = $this->db_connection->escapeDBItem($this->dbTableName).'.'.$this->db_connection->escapeDBItem($pk_table[0])."=".$this->db_connection->quoteSmart($this->TDBMObject_id);
537
		} else {
538
			$ids = unserialize($object_id);
539
			$i=0;
540
			$sql_where_array = array();
541
			foreach ($pk_table as $pk) {
542
				$sql_where_array[] = $this->db_connection->escapeDBItem($this->dbTableName).'.'.$this->db_connection->escapeDBItem($pk)."=".$this->db_connection->quoteSmart($ids[$i]);
543
				$i++;
544
			}
545
			$sql_where = implode(" AND ",$sql_where_array);
546
		}
547
		return $sql_where;
548
	}
549
550
    /**
551
     * Override the native php clone function for TDBMObjects
552
     */
553 View Code Duplication
    public function __clone(){
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
554
        $this->_dbLoadIfNotLoaded();
0 ignored issues
show
Bug introduced by
The method _dbLoadIfNotLoaded() does not seem to exist on object<Mouf\Database\TDBM\AbstractTDBMObject>.

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...
555
        //First lets set the status to new (to enter the save function)
556
        $this->status = TDBMObjectStateEnum::STATE_NEW;
557
558
        // Add the current TDBMObject to the save object list
559
        $this->tdbmService->_addToToSaveObjectList($this);
0 ignored issues
show
Documentation introduced by
$this is of type this<Mouf\Database\TDBM\AbstractTDBMObject>, but the function expects a object<Mouf\Database\TDBM\DbRow>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
560
561
        //Now unset the PK from the row
562
        $pk_array = $this->tdbmService->getPrimaryKeyColumns($this->dbTableName);
563
        foreach ($pk_array as $pk) {
564
            $this->dbRow[$pk] = null;
0 ignored issues
show
Bug introduced by
The property dbRow does not seem to exist. Did you mean dbRows?

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
565
        }
566
    }
567
568
	/**
569
	 * Returns raw database rows.
570
	 *
571
	 * @return DbRow[] Key: table name, Value: DbRow object
572
	 */
573
	public function _getDbRows() {
574
		return $this->dbRows;
575
	}
576
577
	private function registerTable($tableName) {
578
		$dbRow = new DbRow($this, $tableName);
579
580
		if (in_array($this->status, [ TDBMObjectStateEnum::STATE_NOT_LOADED, TDBMObjectStateEnum::STATE_LOADED, TDBMObjectStateEnum::STATE_DIRTY ])) {
581
			// Let's get the primary key for the new table
582
			$anotherDbRow = array_values($this->dbRows)[0];
583
			/* @var $anotherDbRow DbRow */
584
			$indexedPrimaryKeys = array_values($anotherDbRow->_getPrimaryKeys());
585
			$primaryKeys = $this->tdbmService->_getPrimaryKeysFromIndexedPrimaryKeys($tableName, $indexedPrimaryKeys);
586
			$dbRow->_setPrimaryKeys($primaryKeys);
587
		}
588
589
		$dbRow->_setStatus($this->status);
590
591
		$this->dbRows[$tableName] = $dbRow;
592
		// TODO: look at status (if not new)=> get primary key from tdbmservice
593
	}
594
595
	/**
596
	 * Internal function: return the list of relationships
597
	 * @return \SplObjectStorage[]
598
	 */
599
	public function _getCachedRelationships() {
600
		return $this->relationships;
601
	}
602
}
603