Passed
Pull Request — master (#127)
by
unknown
06:05
created

AbstractTDBMObject::getForeignKeys()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

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

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

671
    protected static function getForeignKeys(/** @scrutinizer ignore-unused */ string $tableName): ForeignKeys

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
672
    {
673
        return new ForeignKeys([]);
674
    }
675
}
676