Completed
Push — master ( f50fbb...681f17 )
by David
20s queued 12s
created

src/AbstractTDBMObject.php (1 issue)

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

659
    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...
660
    {
661
        return new ForeignKeys([]);
662
    }
663
664
    public function _getManyToManyRelationshipDescriptor(string $pathKey): ManyToManyRelationshipPathDescriptor
665
    {
666
        throw new TDBMException('Could not find many to many relationship descriptor key for "'.$pathKey.'"');
667
    }
668
669
    /**
670
     * @return string[]
671
     */
672
    public function _getManyToManyRelationshipDescriptorKeys(): array
673
    {
674
        return [];
675
    }
676
}
677