Completed
Push — 4.2 ( 9b8943...37bf92 )
by David
56s
created

AbstractTDBMObject::onDelete()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 3
rs 10
c 0
b 0
f 0
cc 1
eloc 1
nc 1
nop 0
1
<?php
2
3
namespace Mouf\Database\TDBM;
4
5
/*
6
 Copyright (C) 2006-2016 David Négrier - THE CODING MACHINE
7
8
 This program is free software; you can redistribute it and/or modify
9
 it under the terms of the GNU General Public License as published by
10
 the Free Software Foundation; either version 2 of the License, or
11
 (at your option) any later version.
12
13
 This program is distributed in the hope that it will be useful,
14
 but WITHOUT ANY WARRANTY; without even the implied warranty of
15
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16
 GNU General Public License for more details.
17
18
 You should have received a copy of the GNU General Public License
19
 along with this program; if not, write to the Free Software
20
 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
21
 */
22
23
use JsonSerializable;
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
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
     *
44
     * @var DbRow[]
45
     */
46
    protected $dbRows = array();
47
48
    /**
49
     * One of TDBMObjectStateEnum::STATE_NEW, TDBMObjectStateEnum::STATE_NOT_LOADED, TDBMObjectStateEnum::STATE_LOADED, TDBMObjectStateEnum::STATE_DELETED.
50
     * $status = TDBMObjectStateEnum::STATE_NEW when a new object is created with DBMObject:getNewObject.
51
     * $status = TDBMObjectStateEnum::STATE_NOT_LOADED when the object has been retrieved with getObject but when no data has been accessed in it yet.
52
     * $status = TDBMObjectStateEnum::STATE_LOADED when the object is cached in memory.
53
     *
54
     * @var string
55
     */
56
    private $status;
57
58
    /**
59
     * Array storing beans related via many to many relationships (pivot tables).
60
     *
61
     * @var \SplObjectStorage[] Key: pivot table name, value: SplObjectStorage
62
     */
63
    private $relationships = [];
64
65
    /**
66
     * @var bool[] Key: pivot table name, value: whether a query was performed to load the data
67
     */
68
    private $loadedRelationships = [];
69
70
    /**
71
     * Array storing beans related via many to one relationships (this bean is pointed by external beans).
72
     *
73
     * @var AlterableResultIterator[] Key: [external_table]___[external_column], value: SplObjectStorage
74
     */
75
    private $manyToOneRelationships = [];
76
77
    /**
78
     * Used with $primaryKeys when we want to retrieve an existing object
79
     * and $primaryKeys=[] if we want a new object.
80
     *
81
     * @param string      $tableName
82
     * @param array       $primaryKeys
83
     * @param TDBMService $tdbmService
84
     *
85
     * @throws TDBMException
86
     * @throws TDBMInvalidOperationException
87
     */
88
    public function __construct($tableName = null, array $primaryKeys = array(), TDBMService $tdbmService = null)
89
    {
90
        // FIXME: lazy loading should be forbidden on tables with inheritance and dynamic type assignation...
91
        if (!empty($tableName)) {
92
            $this->dbRows[$tableName] = new DbRow($this, $tableName, $primaryKeys, $tdbmService);
93
        }
94
95
        if ($tdbmService === null) {
96
            $this->_setStatus(TDBMObjectStateEnum::STATE_DETACHED);
97
        } else {
98
            $this->_attach($tdbmService);
99
            if (!empty($primaryKeys)) {
100
                $this->_setStatus(TDBMObjectStateEnum::STATE_NOT_LOADED);
101
            } else {
102
                $this->_setStatus(TDBMObjectStateEnum::STATE_NEW);
103
            }
104
        }
105
    }
106
107
    /**
108
     * Alternative constructor called when data is fetched from database via a SELECT.
109
     *
110
     * @param array       $beanData    array<table, array<column, value>>
111
     * @param TDBMService $tdbmService
112
     */
113
    public function _constructFromData(array $beanData, TDBMService $tdbmService)
114
    {
115
        $this->tdbmService = $tdbmService;
116
117
        foreach ($beanData as $table => $columns) {
118
            $this->dbRows[$table] = new DbRow($this, $table, $tdbmService->_getPrimaryKeysFromObjectData($table, $columns), $tdbmService, $columns);
119
        }
120
121
        $this->status = TDBMObjectStateEnum::STATE_LOADED;
122
    }
123
124
    /**
125
     * Alternative constructor called when bean is lazily loaded.
126
     *
127
     * @param string      $tableName
128
     * @param array       $primaryKeys
129
     * @param TDBMService $tdbmService
130
     */
131
    public function _constructLazy($tableName, array $primaryKeys, TDBMService $tdbmService)
132
    {
133
        $this->tdbmService = $tdbmService;
134
135
        $this->dbRows[$tableName] = new DbRow($this, $tableName, $primaryKeys, $tdbmService);
136
137
        $this->status = TDBMObjectStateEnum::STATE_NOT_LOADED;
138
    }
139
140
    public function _attach(TDBMService $tdbmService)
141
    {
142
        if ($this->status !== TDBMObjectStateEnum::STATE_DETACHED) {
143
            throw new TDBMInvalidOperationException('Cannot attach an object that is already attached to TDBM.');
144
        }
145
        $this->tdbmService = $tdbmService;
146
147
        // If we attach this object, we must work to make sure the tables are in ascending order (from low level to top level)
148
        $tableNames = $this->getUsedTables();
149
150
        $newDbRows = [];
151
152
        foreach ($tableNames as $table) {
153
            if (!isset($this->dbRows[$table])) {
154
                $this->registerTable($table);
155
            }
156
            $newDbRows[$table] = $this->dbRows[$table];
157
        }
158
        $this->dbRows = $newDbRows;
159
160
        $this->status = TDBMObjectStateEnum::STATE_NEW;
161
        foreach ($this->dbRows as $dbRow) {
162
            $dbRow->_attach($tdbmService);
163
        }
164
    }
165
166
    /**
167
     * Sets the state of the TDBM Object
168
     * One of TDBMObjectStateEnum::STATE_NEW, TDBMObjectStateEnum::STATE_NOT_LOADED, TDBMObjectStateEnum::STATE_LOADED, TDBMObjectStateEnum::STATE_DELETED.
169
     * $status = TDBMObjectStateEnum::STATE_NEW when a new object is created with DBMObject:getNewObject.
170
     * $status = TDBMObjectStateEnum::STATE_NOT_LOADED when the object has been retrieved with getObject but when no data has been accessed in it yet.
171
     * $status = TDBMObjectStateEnum::STATE_LOADED when the object is cached in memory.
172
     *
173
     * @param string $state
174
     */
175
    public function _setStatus($state)
176
    {
177
        $this->status = $state;
178
179
        // TODO: we might ignore the loaded => dirty state here! dirty status comes from the db_row itself.
180
        foreach ($this->dbRows as $dbRow) {
181
            $dbRow->_setStatus($state);
182
        }
183
184
        if ($state === TDBMObjectStateEnum::STATE_DELETED) {
185
            $this->onDelete();
186
        }
187
    }
188
189
    /**
190
     * Checks that $tableName is ok, or returns the only possible table name if "$tableName = null"
191
     * or throws an error.
192
     *
193
     * @param string $tableName
194
     *
195
     * @return string
196
     */
197
    private function checkTableName($tableName = null)
198
    {
199 View Code Duplication
        if ($tableName === null) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
200
            if (count($this->dbRows) > 1) {
201
                throw new TDBMException('This object is based on several tables. You must specify which table you are retrieving data from.');
202
            } elseif (count($this->dbRows) === 1) {
203
                $tableName = array_keys($this->dbRows)[0];
204
            }
205
        }
206
207
        if (!isset($this->dbRows[$tableName])) {
208
            if (count($this->dbRows === 0)) {
209
                throw new TDBMException('Object is not yet bound to any table.');
210
            } else {
211
                throw new TDBMException('Unknown table "'.$tableName.'"" in object.');
212
            }
213
        }
214
215
        return $tableName;
216
    }
217
218
    protected function get($var, $tableName = null)
219
    {
220
        $tableName = $this->checkTableName($tableName);
221
222
        return $this->dbRows[$tableName]->get($var);
223
    }
224
225
    protected function set($var, $value, $tableName = null)
226
    {
227 View Code Duplication
        if ($tableName === null) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
228
            if (count($this->dbRows) > 1) {
229
                throw new TDBMException('This object is based on several tables. You must specify which table you are retrieving data from.');
230
            } elseif (count($this->dbRows) === 1) {
231
                $tableName = array_keys($this->dbRows)[0];
232
            } else {
233
                throw new TDBMException('Please specify a table for this object.');
234
            }
235
        }
236
237
        if (!isset($this->dbRows[$tableName])) {
238
            $this->registerTable($tableName);
239
        }
240
241
        $this->dbRows[$tableName]->set($var, $value);
242
        if ($this->dbRows[$tableName]->_getStatus() === TDBMObjectStateEnum::STATE_DIRTY) {
243
            $this->status = TDBMObjectStateEnum::STATE_DIRTY;
244
        }
245
    }
246
247
    /**
248
     * @param string             $foreignKeyName
249
     * @param AbstractTDBMObject $bean
250
     */
251
    protected function setRef($foreignKeyName, AbstractTDBMObject $bean = null, $tableName = null)
252
    {
253 View Code Duplication
        if ($tableName === null) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
254
            if (count($this->dbRows) > 1) {
255
                throw new TDBMException('This object is based on several tables. You must specify which table you are retrieving data from.');
256
            } elseif (count($this->dbRows) === 1) {
257
                $tableName = array_keys($this->dbRows)[0];
258
            } else {
259
                throw new TDBMException('Please specify a table for this object.');
260
            }
261
        }
262
263
        if (!isset($this->dbRows[$tableName])) {
264
            $this->registerTable($tableName);
265
        }
266
267
        $oldLinkedBean = $this->dbRows[$tableName]->getRef($foreignKeyName);
268
        if ($oldLinkedBean !== null) {
269
            $oldLinkedBean->removeManyToOneRelationship($tableName, $foreignKeyName, $this);
270
        }
271
272
        $this->dbRows[$tableName]->setRef($foreignKeyName, $bean);
273
        if ($this->dbRows[$tableName]->_getStatus() === TDBMObjectStateEnum::STATE_DIRTY) {
274
            $this->status = TDBMObjectStateEnum::STATE_DIRTY;
275
        }
276
277
        if ($bean !== null) {
278
            $bean->setManyToOneRelationship($tableName, $foreignKeyName, $this);
279
        }
280
    }
281
282
    /**
283
     * @param string $foreignKeyName A unique name for this reference
284
     *
285
     * @return AbstractTDBMObject|null
286
     */
287
    protected function getRef($foreignKeyName, $tableName = null)
288
    {
289
        $tableName = $this->checkTableName($tableName);
290
291
        return $this->dbRows[$tableName]->getRef($foreignKeyName);
292
    }
293
294
    /**
295
     * Adds a many to many relationship to this bean.
296
     *
297
     * @param string             $pivotTableName
298
     * @param AbstractTDBMObject $remoteBean
299
     */
300
    protected function addRelationship($pivotTableName, AbstractTDBMObject $remoteBean)
301
    {
302
        $this->setRelationship($pivotTableName, $remoteBean, 'new');
303
    }
304
305
    /**
306
     * Returns true if there is a relationship to this bean.
307
     *
308
     * @param string             $pivotTableName
309
     * @param AbstractTDBMObject $remoteBean
310
     *
311
     * @return bool
312
     */
313
    protected function hasRelationship($pivotTableName, AbstractTDBMObject $remoteBean)
314
    {
315
        $storage = $this->retrieveRelationshipsStorage($pivotTableName);
316
317
        if ($storage->contains($remoteBean)) {
318
            if ($storage[$remoteBean]['status'] !== 'delete') {
319
                return true;
320
            }
321
        }
322
323
        return false;
324
    }
325
326
    /**
327
     * Internal TDBM method. Removes a many to many relationship from this bean.
328
     *
329
     * @param string             $pivotTableName
330
     * @param AbstractTDBMObject $remoteBean
331
     */
332
    public function _removeRelationship($pivotTableName, AbstractTDBMObject $remoteBean)
333
    {
334
        if (isset($this->relationships[$pivotTableName][$remoteBean]) && $this->relationships[$pivotTableName][$remoteBean]['status'] === 'new') {
335
            unset($this->relationships[$pivotTableName][$remoteBean]);
336
            unset($remoteBean->relationships[$pivotTableName][$this]);
337
        } else {
338
            $this->setRelationship($pivotTableName, $remoteBean, 'delete');
339
        }
340
    }
341
342
    /**
343
     * Sets many to many relationships for this bean.
344
     * Adds new relationships and removes unused ones.
345
     *
346
     * @param $pivotTableName
347
     * @param array $remoteBeans
348
     */
349
    protected function setRelationships($pivotTableName, array $remoteBeans)
350
    {
351
        $storage = $this->retrieveRelationshipsStorage($pivotTableName);
352
353
        foreach ($storage as $oldRemoteBean) {
354
            if (!in_array($oldRemoteBean, $remoteBeans, true)) {
355
                // $oldRemoteBean must be removed
356
                $this->_removeRelationship($pivotTableName, $oldRemoteBean);
357
            }
358
        }
359
360
        foreach ($remoteBeans as $remoteBean) {
361
            if (!$storage->contains($remoteBean) || $storage[$remoteBean]['status'] === 'delete') {
362
                // $remoteBean must be added
363
                $this->addRelationship($pivotTableName, $remoteBean);
364
            }
365
        }
366
    }
367
368
    /**
369
     * Returns the list of objects linked to this bean via $pivotTableName.
370
     *
371
     * @param $pivotTableName
372
     *
373
     * @return \SplObjectStorage
374
     */
375
    private function retrieveRelationshipsStorage($pivotTableName)
376
    {
377
        $storage = $this->getRelationshipStorage($pivotTableName);
378
        if ($this->status === TDBMObjectStateEnum::STATE_DETACHED || $this->status === TDBMObjectStateEnum::STATE_NEW || (isset($this->loadedRelationships[$pivotTableName]) && $this->loadedRelationships[$pivotTableName])) {
379
            return $storage;
380
        }
381
382
        $beans = $this->tdbmService->_getRelatedBeans($pivotTableName, $this);
383
        $this->loadedRelationships[$pivotTableName] = true;
384
385
        foreach ($beans as $bean) {
386
            if (isset($storage[$bean])) {
387
                $oldStatus = $storage[$bean]['status'];
388
                if ($oldStatus === 'delete') {
389
                    // Keep deleted things deleted
390
                    continue;
391
                }
392
            }
393
            $this->setRelationship($pivotTableName, $bean, 'loaded');
394
        }
395
396
        return $storage;
397
    }
398
399
    /**
400
     * Internal TDBM method. Returns the list of objects linked to this bean via $pivotTableName.
401
     *
402
     * @param $pivotTableName
403
     *
404
     * @return AbstractTDBMObject[]
405
     */
406
    public function _getRelationships($pivotTableName)
407
    {
408
        return $this->relationshipStorageToArray($this->retrieveRelationshipsStorage($pivotTableName));
409
    }
410
411
    private function relationshipStorageToArray(\SplObjectStorage $storage)
412
    {
413
        $beans = [];
414
        foreach ($storage as $bean) {
415
            $statusArr = $storage[$bean];
416
            if ($statusArr['status'] !== 'delete') {
417
                $beans[] = $bean;
418
            }
419
        }
420
421
        return $beans;
422
    }
423
424
    /**
425
     * Declares a relationship between.
426
     *
427
     * @param string             $pivotTableName
428
     * @param AbstractTDBMObject $remoteBean
429
     * @param string             $status
430
     */
431
    private function setRelationship($pivotTableName, AbstractTDBMObject $remoteBean, $status)
432
    {
433
        $storage = $this->getRelationshipStorage($pivotTableName);
434
        $storage->attach($remoteBean, ['status' => $status, 'reverse' => false]);
435
        if ($this->status === TDBMObjectStateEnum::STATE_LOADED) {
436
            $this->_setStatus(TDBMObjectStateEnum::STATE_DIRTY);
437
        }
438
439
        $remoteStorage = $remoteBean->getRelationshipStorage($pivotTableName);
440
        $remoteStorage->attach($this, ['status' => $status, 'reverse' => true]);
441
    }
442
443
    /**
444
     * Returns the SplObjectStorage associated to this relationship (creates it if it does not exists).
445
     *
446
     * @param string $pivotTableName
447
     *
448
     * @return \SplObjectStorage
449
     */
450
    private function getRelationshipStorage(string $pivotTableName) : \SplObjectStorage
451
    {
452
        return $this->relationships[$pivotTableName] ?? $this->relationships[$pivotTableName] = new \SplObjectStorage();
453
    }
454
455
    /**
456
     * Returns the SplObjectStorage associated to this relationship (creates it if it does not exists).
457
     *
458
     * @param string $tableName
459
     * @param string $foreignKeyName
460
     *
461
     * @return AlterableResultIterator
462
     */
463
    private function getManyToOneAlterableResultIterator(string $tableName, string $foreignKeyName) : AlterableResultIterator
464
    {
465
        $key = $tableName.'___'.$foreignKeyName;
466
467
        return $this->manyToOneRelationships[$key] ?? $this->manyToOneRelationships[$key] = new AlterableResultIterator();
468
    }
469
470
    /**
471
     * Declares a relationship between this bean and the bean pointing to it.
472
     *
473
     * @param string             $tableName
474
     * @param string             $foreignKeyName
475
     * @param AbstractTDBMObject $remoteBean
476
     */
477
    private function setManyToOneRelationship(string $tableName, string $foreignKeyName, AbstractTDBMObject $remoteBean)
478
    {
479
        $alterableResultIterator = $this->getManyToOneAlterableResultIterator($tableName, $foreignKeyName);
480
        $alterableResultIterator->add($remoteBean);
481
    }
482
483
    /**
484
     * Declares a relationship between this bean and the bean pointing to it.
485
     *
486
     * @param string             $tableName
487
     * @param string             $foreignKeyName
488
     * @param AbstractTDBMObject $remoteBean
489
     */
490
    private function removeManyToOneRelationship(string $tableName, string $foreignKeyName, AbstractTDBMObject $remoteBean)
491
    {
492
        $alterableResultIterator = $this->getManyToOneAlterableResultIterator($tableName, $foreignKeyName);
493
        $alterableResultIterator->remove($remoteBean);
494
    }
495
496
    /**
497
     * Returns the list of objects linked to this bean via a given foreign key.
498
     *
499
     * @param string $tableName
500
     * @param string $foreignKeyName
501
     * @param string $searchTableName
502
     * @param array  $searchFilter
503
     * @param string $orderString     The ORDER BY part of the query. All columns must be prefixed by the table name (in the form: table.column). WARNING : This parameter is not kept when there is an additionnal or removal object !
504
     *
505
     * @return AlterableResultIterator
506
     */
507
    protected function retrieveManyToOneRelationshipsStorage(string $tableName, string $foreignKeyName, string $searchTableName, array $searchFilter, $orderString = null) : AlterableResultIterator
508
    {
509
        $key = $tableName.'___'.$foreignKeyName;
510
        $alterableResultIterator = $this->getManyToOneAlterableResultIterator($tableName, $foreignKeyName);
511
        if ($this->status === TDBMObjectStateEnum::STATE_DETACHED || $this->status === TDBMObjectStateEnum::STATE_NEW || (isset($this->manyToOneRelationships[$key]) && $this->manyToOneRelationships[$key]->getUnderlyingResultIterator() !== null)) {
512
            return $alterableResultIterator;
513
        }
514
515
        $unalteredResultIterator = $this->tdbmService->findObjects($searchTableName, $searchFilter, [], $orderString);
516
517
        $alterableResultIterator->setResultIterator($unalteredResultIterator->getIterator());
518
519
        return $alterableResultIterator;
520
    }
521
522
    /**
523
     * Reverts any changes made to the object and resumes it to its DB state.
524
     * This can only be called on objects that come from database and that have not been deleted.
525
     * Otherwise, this will throw an exception.
526
     *
527
     * @throws TDBMException
528
     */
529
    public function discardChanges()
530
    {
531
        if ($this->status === TDBMObjectStateEnum::STATE_NEW || $this->status === TDBMObjectStateEnum::STATE_DETACHED) {
532
            throw new TDBMException("You cannot call discardChanges() on an object that has been created with the 'new' keyword and that has not yet been saved.");
533
        }
534
535
        if ($this->status === TDBMObjectStateEnum::STATE_DELETED) {
536
            throw new TDBMException('You cannot call discardChanges() on an object that has been deleted.');
537
        }
538
539
        $this->_setStatus(TDBMObjectStateEnum::STATE_NOT_LOADED);
540
    }
541
542
    /**
543
     * Method used internally by TDBM. You should not use it directly.
544
     * This method returns the status of the TDBMObject.
545
     * This is one of TDBMObjectStateEnum::STATE_NEW, TDBMObjectStateEnum::STATE_NOT_LOADED, TDBMObjectStateEnum::STATE_LOADED, TDBMObjectStateEnum::STATE_DELETED.
546
     * $status = TDBMObjectStateEnum::STATE_NEW when a new object is created with DBMObject:getNewObject.
547
     * $status = TDBMObjectStateEnum::STATE_NOT_LOADED when the object has been retrieved with getObject but when no data has been accessed in it yet.
548
     * $status = TDBMObjectStateEnum::STATE_LOADED when the object is cached in memory.
549
     *
550
     * @return string
551
     */
552
    public function _getStatus()
553
    {
554
        return $this->status;
555
    }
556
557
    /**
558
     * Override the native php clone function for TDBMObjects.
559
     */
560
    public function __clone()
561
    {
562
        // Let's clone the many to many relationships
563
        if ($this->status === TDBMObjectStateEnum::STATE_DETACHED) {
564
            $pivotTableList = array_keys($this->relationships);
565
        } else {
566
            $pivotTableList = $this->tdbmService->_getPivotTablesLinkedToBean($this);
567
        }
568
569
        foreach ($pivotTableList as $pivotTable) {
570
            $storage = $this->retrieveRelationshipsStorage($pivotTable);
0 ignored issues
show
Unused Code introduced by
$storage is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
571
572
            // Let's duplicate the reverse side of the relationship // This is useless: already done by "retrieveRelationshipsStorage"!!!
573
            /*foreach ($storage as $remoteBean) {
0 ignored issues
show
Unused Code Comprehensibility introduced by
66% 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...
574
                $metadata = $storage[$remoteBean];
575
576
                $remoteStorage = $remoteBean->getRelationshipStorage($pivotTable);
577
                $remoteStorage->attach($this, ['status' => $metadata['status'], 'reverse' => !$metadata['reverse']]);
578
            }*/
579
        }
580
581
        // Let's clone each row
582
        foreach ($this->dbRows as $key => &$dbRow) {
583
            $dbRow = clone $dbRow;
584
            $dbRow->setTDBMObject($this);
585
        }
586
587
        $this->manyToOneRelationships = [];
588
589
        // Let's set the status to new (to enter the save function)
590
        $this->status = TDBMObjectStateEnum::STATE_DETACHED;
591
    }
592
593
    /**
594
     * Returns raw database rows.
595
     *
596
     * @return DbRow[] Key: table name, Value: DbRow object
597
     */
598
    public function _getDbRows()
599
    {
600
        return $this->dbRows;
601
    }
602
603
    private function registerTable($tableName)
604
    {
605
        $dbRow = new DbRow($this, $tableName);
606
607
        if (in_array($this->status, [TDBMObjectStateEnum::STATE_NOT_LOADED, TDBMObjectStateEnum::STATE_LOADED, TDBMObjectStateEnum::STATE_DIRTY])) {
608
            // Let's get the primary key for the new table
609
            $anotherDbRow = array_values($this->dbRows)[0];
610
            /* @var $anotherDbRow DbRow */
611
            $indexedPrimaryKeys = array_values($anotherDbRow->_getPrimaryKeys());
612
            $primaryKeys = $this->tdbmService->_getPrimaryKeysFromIndexedPrimaryKeys($tableName, $indexedPrimaryKeys);
613
            $dbRow->_setPrimaryKeys($primaryKeys);
614
        }
615
616
        $dbRow->_setStatus($this->status);
617
618
        $this->dbRows[$tableName] = $dbRow;
619
        // TODO: look at status (if not new)=> get primary key from tdbmservice
620
    }
621
622
    /**
623
     * Internal function: return the list of relationships.
624
     *
625
     * @return \SplObjectStorage[]
626
     */
627
    public function _getCachedRelationships()
628
    {
629
        return $this->relationships;
630
    }
631
632
    /**
633
     * Returns an array of used tables by this bean (from parent to child relationship).
634
     *
635
     * @return string[]
636
     */
637
    abstract protected function getUsedTables();
638
639
    /**
640
     * Method called when the bean is removed from database.
641
     */
642
    protected function onDelete()
643
    {
644
    }
645
}
646