Passed
Push — master ( b52e35...baab09 )
by Laurent
03:12
created

app_TraceableRecord::getDeletedStatuses()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 7
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 5
c 1
b 0
f 0
nc 1
nop 0
dl 0
loc 7
rs 10
1
<?php
2
//-------------------------------------------------------------------------
3
// OVIDENTIA http://www.ovidentia.org
4
// Ovidentia is free software; you can redistribute it and/or modify
5
// it under the terms of the GNU General Public License as published by
6
// the Free Software Foundation; either version 2, or (at your option)
7
// any later version.
8
//
9
// This program is distributed in the hope that it will be useful, but
10
// WITHOUT ANY WARRANTY; without even the implied warranty of
11
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
// See the GNU General Public License for more details.
13
//
14
// You should have received a copy of the GNU General Public License
15
// along with this program; if not, write to the Free Software
16
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
17
// USA.
18
//-------------------------------------------------------------------------
19
/**
20
 * @license http://opensource.org/licenses/gpl-license.php GNU General Public License (GPL)
21
 * @copyright Copyright (c) 2018 by CANTICO ({@link http://www.cantico.fr})
22
 */
23
24
$App = app_App();
25
$App->includeRecordSet();
26
27
28
/**
29
 *
30
 * @property ORM_IntField       $createdBy
31
 * @property ORM_DateTimeField  $createdOn
32
 * @property ORM_IntField       $modifiedBy
33
 * @property ORM_DateTimeField  $modifiedOn
34
 * @property ORM_IntField       $deletedBy
35
 * @property ORM_DateTimeField  $deletedOn
36
 * @property ORM_EnumField      $deleted
37
 * @property ORM_StringField    $uuid
38
 *
39
 * @method app_TraceableRecord    get(mixed $criteria)
40
 * @method app_TraceableRecord    request(mixed $criteria)
41
 * @method app_TraceableRecord[]  select(\ORM_Criteria $criteria = null)
42
 * @method app_TraceableRecord    newRecord()
43
 */
44
class app_TraceableRecordSet extends app_RecordSet
45
{
46
    /**
47
     * @var bool
48
     */
49
    private $loggable = false;
50
51
    /**
52
     * @var bool
53
     */
54
    private $traceable = true;
55
56
    /**
57
     * @param Func_App $App
58
     */
59
    public function __construct(Func_App $App)
60
    {
61
        parent::__construct($App);
62
63
        $this->addFields(
64
            ORM_UserField('createdBy')
65
                ->setDescription('Created by'),
66
            ORM_DateTimeField('createdOn')
67
                ->setDescription('Created on'),
68
            ORM_UserField('modifiedBy')
69
                ->setDescription('Modified by'),
70
            ORM_DateTimeField('modifiedOn')
71
                ->setDescription('Modified on'),
72
            ORM_IntField('deletedBy')
73
                ->setDescription('Deleted by'),
74
            ORM_DateTimeField('deletedOn')
75
                ->setDescription('Deleted on'),
76
            ORM_EnumField('deleted', app_TraceableRecord::getDeletedStatuses())
77
                ->setDescription('Deleted'),
78
            ORM_StringField('uuid')
79
                ->setDescription('Universally Unique IDentifier')
80
81
        );
82
83
        // This condition will be applied whenever we select or join Records from this RecordSet.
84
        $this->setDefaultCriteria($this->deleted->is(false));
85
    }
86
87
88
    /**
89
     * Defines if the insertions/updates/deletions on the recordSet will be logged.
90
     *
91
     * @param bool $loggable
92
     * @return self
93
     */
94
    protected function setLoggable($loggable)
95
    {
96
        $this->loggable = $loggable;
97
        return $this;
98
    }
99
100
101
    /**
102
     * Checks if the insertions/updates/deletions on the recordSet will be logged.
103
     *
104
     * @return bool
105
     */
106
    protected function isLoggable()
107
    {
108
        return $this->loggable;
109
    }
110
111
112
113
114
    /**
115
     * Defines if the insertions/updates/deletions on the recordSet will be traced.
116
     *
117
     * @param bool $traceable
118
     * @return self
119
     */
120
    public function setTraceable($traceable)
121
    {
122
        $this->traceable = $traceable;
123
        return $this;
124
    }
125
126
127
    /**
128
     * Checks if the insertions/updates/deletions on the recordSet will be traced.
129
     *
130
     * @return bool
131
     */
132
    public function isTraceable()
133
    {
134
        return $this->traceable;
135
    }
136
137
138
    /**
139
     * @param app_TraceableRecord   $record
140
     * @param bool                  $noTrace
141
     */
142
    protected function logSave(app_TraceableRecord $record, $noTrace)
143
    {
144
        if (!$this->isLoggable()) {
145
            return;
146
        }
147
        $App = $this->App();
148
        $userId = bab_getUserId();
149
        $logSet = $App->LogSet();
150
        $log = $logSet->newRecord();
151
        $log->noTrace = $noTrace;
152
        $log->objectClass = get_class($record);
153
        $log->objectId = $record->id;
154
        $now = date('Y-m-d H:i:s');
155
        $log->modifiedOn = $now;
156
        $log->modifiedBy = $userId;
157
        $log->data = $logSet->serialize($record);
0 ignored issues
show
Documentation Bug introduced by
It seems like $logSet->serialize($record) of type array is incompatible with the declared type string of property $data.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
158
        $log->save();
159
    }
160
161
162
    /**
163
     * @param ORM_Criteria          $criteria
164
     * @param bool                  $noTrace
165
     */
166
    protected function logDelete(ORM_Criteria $criteria, $noTrace)
167
    {
168
        if (!$this->isLoggable()) {
169
            return;
170
        }
171
        $App = $this->App();
172
        $userId = bab_getUserId();
173
        $logSet = $App->LogSet();
174
        $deletedRecords = $this->select($criteria);
175
        foreach ($deletedRecords as $record) {
176
            $log = $logSet->newRecord();
177
            $log->noTrace = $noTrace;
178
            $log->objectClass = get_class($record);
179
            $log->objectId = $record->id;
180
            $now = date('Y-m-d H:i:s');
181
            $log->modifiedOn = $now;
182
            $log->modifiedBy = $userId;
183
            $log->data = '';
184
            $log->save();
185
        }
186
    }
187
188
    /**
189
     * Returns an iterator on records matching the specified criteria.
190
     * The iterator will not include records flagged as deleted unless
191
     * the $includeDeleted parameter is set to true.
192
     *
193
     * @param ORM_Criteria  $criteria       Criteria for selecting records.
194
     * @param bool          $includeDeleted True to include delete-flagged records.
195
     *
196
     * @return app_TraceableRecord[]        Iterator on success, null if the backend has not been set
197
     */
198
    public function select(ORM_Criteria $criteria = null, $includeDeleted = false)
199
    {
200
        if ($includeDeleted) {
201
            $this->setDefaultCriteria(null);
202
        }
203
        return parent::select($criteria);
204
    }
205
206
207
    /**
208
     * Returns the first item matching the specified criteria.
209
     * The item will not include records flagged as deleted unless
210
     * the $includeDeleted parameter is set to true.
211
     *
212
     * @param ORM_Criteria	$criteria			Criteria for selecting records.
213
     * @param string		$sPropertyName		The name of the property on which the value applies. If not specified or null, the set's primary key will be used.
214
     * @param bool			$includeDeleted		True to include delete-flagged records.
215
     *
216
     * @return ORM_Item				Iterator on success, null if the backend has not been set
217
     */
218
    /*public function get(ORM_Criteria $criteria = null, $sPropertyName = null, $includeDeleted = false)
219
    {
220
        if ($includeDeleted) {
221
            $this->setDefaultCriteria(null);
222
        }
223
        return parent::get($criteria, $sPropertyName);
224
    }*/
225
226
227
    /**
228
     * Deleted records matching the specified criteria.
229
     * If $deletedStatus is true, records are not permanently deleted
230
     * If $deletedStatus is one of the crm_TraceableRecord::DELETED_STATUS_xxx constants, it is just
231
     * flagged with this status and kept in the database.
232
     *
233
     * @param ORM_Criteria  $criteria		The criteria for selecting the records to delete.
234
     * @param int|bool      $deletedStatus  True to delete permanently the record.
235
     *
236
     * @return bool     True on success, false otherwise
237
     */
238
    public function delete(ORM_Criteria $criteria = null, $deletedStatus = app_TraceableRecord::DELETED_STATUS_DELETED)
239
    {
240
        $definitive = ($deletedStatus === true) || !$this->isTraceable();
241
        $this->logDelete($criteria, $definitive);
0 ignored issues
show
Bug introduced by
It seems like $criteria can also be of type null; however, parameter $criteria of app_TraceableRecordSet::logDelete() does only seem to accept ORM_Criteria, maybe add an additional type check? ( Ignorable by Annotation )

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

241
        $this->logDelete(/** @scrutinizer ignore-type */ $criteria, $definitive);
Loading history...
242
        if ($definitive) {
243
            return parent::delete($criteria);
244
        }
245
246
        require_once $GLOBALS['babInstallPath'] . '/utilit/dateTime.php';
247
        $now = BAB_DateTime::now()->getIsoDateTime();
248
249
        $records = $this->select($criteria);
250
251
252
        foreach ($records as $record) {
253
            /* @var $record app_TraceableRecord */
254
            // Could be optimized at ORM level
255
            $record->deleted = $deletedStatus;
0 ignored issues
show
Documentation Bug introduced by
It seems like $deletedStatus can also be of type integer. However, the property $deleted is declared as type boolean. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
256
            $record->deletedOn = $now;
257
            $record->deletedBy = bab_getUserId();
258
259
            if (!parent::save($record)) {
260
                return false;
261
            }
262
        }
263
        return true;
264
    }
265
266
    /**
267
     * Saves a record and keeps traces of the user doing it.
268
     *
269
     * @param app_TraceableRecord	$record			The record to save.
270
     * @param bool					$noTrace		True to bypass the tracing of modifications.
271
     *
272
     * @return boolean				True on success, false otherwise
273
     */
274
    public function save(ORM_Record $record, $noTrace = false)
275
    {
276
        $noTrace = $noTrace || !$this->isTraceable();
277
        $this->logSave($record, $noTrace);
278
        if ($noTrace) {
279
            return parent::save($record);
280
        }
281
282
        require_once $GLOBALS['babInstallPath'] . '/utilit/dateTime.php';
283
284
        $now = BAB_DateTime::now()->getIsoDateTime();
285
286
        // We first check if the record already has a createdBy.
287
        $set = $record->getParentSet();
288
        $primaryKey = $set->getPrimaryKey();
289
290
        if (empty($record->{$primaryKey})) {
291
            $record->initValue('createdBy', bab_getUserId());
292
            $record->initValue('createdOn', $now);
293
            $record->initValue('uuid', $this->uuid());
294
        }
295
296
        $record->initValue('modifiedBy', bab_getUserId());
297
        $record->initValue('modifiedOn', $now);
298
299
        return parent::save($record);
300
    }
301
302
303
304
305
    /**
306
     * Generates a Universally Unique IDentifier, version 4.
307
     * RFC 4122 (http://www.ietf.org/rfc/rfc4122.txt)
308
     * @return string
309
     */
310
    private function uuid()
311
    {
312
        return sprintf( '%04x%04x-%04x-%04x-%04x-%04x%04x%04x',
313
            mt_rand( 0, 0xffff ), mt_rand( 0, 0xffff ), mt_rand( 0, 0xffff ),
314
            mt_rand( 0, 0x0fff ) | 0x4000,
315
            mt_rand( 0, 0x3fff ) | 0x8000,
316
            mt_rand( 0, 0xffff ), mt_rand( 0, 0xffff ), mt_rand( 0, 0xffff ) );
317
    }
318
319
    /**
320
     * Get record by UUID or null if the record does not exists or is deleted or if the uuid is empty
321
     * @param	string	$uuid
322
     * @return app_TraceableRecord
323
     */
324
    public function getRecordByUuid($uuid)
325
    {
326
        if ('' === (string) $uuid) {
327
            return null;
328
        }
329
330
331
        $record = $this->get($this->uuid->is($uuid));
332
333
        if (!isset($record)) {
334
            return null;
335
        }
336
337
        if (!($record instanceOf app_TraceableRecord)) {
0 ignored issues
show
introduced by
$record is always a sub-type of app_TraceableRecord.
Loading history...
338
            return null;
339
        }
340
341
        if ($record->deleted) {
342
            return null;
343
        }
344
345
        return $record;
346
    }
347
348
349
350
351
352
353
354
    /**
355
     * Returns an iterator of traceableRecord linked to the specified source,
356
     * optionally filtered on the specified link type.
357
     *
358
     * @param	app_Record | array		$source			source can be an array of record
359
     * @param	string					$linkType
360
     *
361
     * @return ORM_Iterator
362
     */
363
    public function selectLinkedTo($source, $linkType = null)
364
    {
365
        $linkSet = $this->App()->LinkSet();
366
        if (is_array($source) || ($source instanceof Iterator)) {
367
            return $linkSet->selectForSources($source, $this->getRecordClassName(), $linkType);
368
        } else {
369
            return $linkSet->selectForSource($source, $this->getRecordClassName(), $linkType);
370
        }
371
    }
372
373
    /**
374
     * Returns an iterator of traceableRecord linked to the specified target,
375
     * optionally filtered on the specified link type.
376
     *
377
     * @param	app_Record | array		$target			target can be an array of record
378
     * @param	string					$linkType
379
     *
380
     * @return ORM_Iterator
381
     */
382
    public function selectLinkedFrom($target, $linkType = null)
383
    {
384
        $linkSet = $this->App()->LinkSet();
385
        if (is_array($target) || ($target instanceof Iterator)) {
386
            return $linkSet->selectForTargets($target, $this->getRecordClassName(), $linkType);
387
        } else {
388
            return $linkSet->selectForTarget($target, $this->getRecordClassName(), $linkType);
389
        }
390
    }
391
392
393
    /**
394
     * Returns a criteria usable to select records of this set which are source of app_Links to the specified app_Record.
395
     *
396
     * @param app_Record $target
397
     * @param string     $linkType
398
     * @return ORM_Criteria
399
     */
400
    public function isSourceOf(app_Record $target, $linkType = null)
401
    {
402
        $linkSet = $this->App()->LinkSet();
403
404
        $linkSet->hasOne('sourceId', get_class($this));
405
406
        $criteria =	$linkSet->targetClass->is(get_class($target))
407
            ->_AND_($linkSet->targetId->is($target->id))
408
            ->_AND_($linkSet->sourceClass->is($this->getRecordClassName()));
409
        if (isset($linkType)) {
410
            if (is_array($linkType)) {
0 ignored issues
show
introduced by
The condition is_array($linkType) is always false.
Loading history...
411
                $criteria = $criteria->_AND_($linkSet->type->in($linkType));
412
            } else {
413
                $criteria = $criteria->_AND_($linkSet->type->is($linkType));
414
            }
415
        }
416
        $criteria = $this->id->in($criteria);
417
418
        return $criteria;
419
    }
420
421
422
423
    /**
424
     * Returns a criteria usable to select records of this set which are target of app_Links to the specified app_Record.
425
     *
426
     * @param app_Record            $source
427
     * @param null|string|string[]  $linkType
428
     * @return ORM_Criteria
429
     */
430
    public function isTargetOf(app_Record $source, $linkType = null)
431
    {
432
        $linkSet = $this->App()->LinkSet();
433
434
        $linkSet->hasOne('targetId', get_class($this));
435
436
        $criteria =	$linkSet->sourceClass->is(get_class($source))
437
            ->_AND_($linkSet->sourceId->is($source->id))
438
            ->_AND_($linkSet->targetClass->is($this->getRecordClassName()));
439
        if (isset($linkType)) {
440
            if (is_array($linkType)) {
441
                $criteria = $criteria->_AND_($linkSet->type->in($linkType));
442
            } else {
443
                $criteria = $criteria->_AND_($linkSet->type->is($linkType));
444
            }
445
        }
446
        $criteria = $this->id->in($criteria);
447
448
        return $criteria;
449
    }
450
451
452
    /**
453
     * Returns a criteria usable to select records of this set which are target of app_Links from the specified app_Records.
454
     *
455
     * @since 1.0.23
456
     *
457
     * @param app_Record[]          $sources
458
     * @param null|string|string[]  $linkType
459
     * @return ORM_Criteria
460
     */
461
    public function isTargetOfAny($sources, $linkType = null)
462
    {
463
        $linkSet = $this->App()->LinkSet();
464
        $linkSet->hasOne('targetId', get_class($this));
465
466
        $sourceIdsByClasses = array();
467
        foreach ($sources as $source) {
468
            $sourceClass = get_class($source);
469
            if (!isset($sourceIdsByClasses[$sourceClass])) {
470
                $sourceIdsByClasses[$sourceClass] = array();
471
            }
472
            $sourceIdsByClasses[$sourceClass][] = $source->id;
473
        }
474
475
        $sourcesCriteria = array();
476
        foreach ($sourceIdsByClasses as $sourceClass => $sourceIds) {
477
            $sourcesCriteria[] = $linkSet->sourceClass->is($sourceClass)->_AND_($linkSet->sourceId->in($sourceIds));
478
        }
479
480
        $criteria =	$linkSet->all(
481
            $linkSet->targetClass->is($this->getRecordClassName()),
482
            $linkSet->any($sourcesCriteria)
483
        );
484
        if (isset($linkType)) {
485
            if (is_array($linkType)) {
486
                $criteria = $criteria->_AND_($linkSet->type->in($linkType));
487
            } else {
488
                $criteria = $criteria->_AND_($linkSet->type->is($linkType));
489
            }
490
        }
491
        $criteria = $this->id->in($criteria);
492
493
        return $criteria;
494
    }
495
496
497
    /**
498
     * Returns a criteria usable to select records of this set which are source of app_Links to the specified app_Records.
499
     *
500
     * @since 1.0.23
501
     *
502
     * @param app_Record[]     $targets
503
     * @param string|null      $linkType
504
     * @return ORM_Criteria
505
     */
506
    public function isSourceOfAny($targets, $linkType = null)
507
    {
508
        $linkSet = $this->App()->LinkSet();
509
        $linkSet->hasOne('sourceId', get_class($this));
510
511
        $targetIdsByClasses = array();
512
        foreach ($targets as $target) {
513
            $targetClass = get_class($target);
514
            if (!isset($targetIdsByClasses[$targetClass])) {
515
                $targetIdsByClasses[$targetClass] = array();
516
            }
517
            $targetIdsByClasses[$targetClass][] = $target->id;
518
        }
519
520
        $targetsCriteria = array();
521
        foreach ($targetIdsByClasses as $targetClass => $targetIds) {
522
            $targetsCriteria[] = $linkSet->targetClass->is($targetClass)->_AND_($linkSet->targetId->in($targetIds));
523
        }
524
525
        $criteria =	$linkSet->all(
526
            $linkSet->sourceClass->is($this->getRecordClassName()),
527
            $linkSet->any($targetsCriteria)
528
        );
529
        if (isset($linkType)) {
530
            if (is_array($linkType)) {
0 ignored issues
show
introduced by
The condition is_array($linkType) is always false.
Loading history...
531
                $criteria = $criteria->_AND_($linkSet->type->in($linkType));
532
            } else {
533
                $criteria = $criteria->_AND_($linkSet->type->is($linkType));
534
            }
535
        }
536
        $criteria = $this->id->in($criteria);
537
538
        return $criteria;
539
    }
540
541
542
    /**
543
     * Match records created by the specified user or the current connected user if none specified.
544
     *
545
	 * @param int|null $userId
546
	 *
547
	 * @return ORM_IsCriterion
548
	 */
549
    public function isOwn($userId = null)
550
    {
551
        if (!isset($userId)) {
552
            $userId = bab_getUserId();
553
        }
554
        return $this->createdBy->is($userId);
555
    }
556
557
}
558
559
560
/**
561
 * A traceable record automatically stores by whom and when it was created,
562
 * modified and even deleted.
563
 *
564
 * By default "deleted" records (through the standard delete() methods)
565
 * actually stay in the database and are only flagged as deleted.
566
 *
567
 * @property int        $createdBy
568
 * @property string     $createdOn
569
 * @property int        $modifiedBy
570
 * @property string     $modifiedOn
571
 * @property int        $deletedBy
572
 * @property string     $deletedOn
573
 * @property string     $uuid
574
 * @property bool       $deleted
575
 */
576
class app_TraceableRecord extends app_Record
577
{
578
    const DELETED_STATUS_EXISTING = 0;      // Normal status of a record
579
    const DELETED_STATUS_DELETED = 1;       // Record is deleted by retrievable by admin
580
    const DELETED_STATUS_IN_TRASH = 2;      // Record is deleted by retrievable by authorized users
581
    const DELETED_STATUS_DRAFT = 3;         // Status is in draft (not yet created)
582
583
    public static function getDeletedStatuses()
584
    {
585
        return array(
586
            self::DELETED_STATUS_DRAFT => app_translate('Draft'),
587
            self::DELETED_STATUS_EXISTING => app_translate('Existing'),
588
            self::DELETED_STATUS_DELETED => app_translate('Deleted'),
589
            self::DELETED_STATUS_IN_TRASH => app_translate('In trash'),
590
        );
591
    }
592
593
    /**
594
     * Saves the record.
595
     *
596
     * @param bool  $noTrace        True to bypass the tracing of modifications.
597
     *
598
     * @return bool True on success, false otherwise
599
     */
600
    public function save($noTrace = false)
601
    {
602
        return $this->getParentSet()->save($this, $noTrace);
0 ignored issues
show
Unused Code introduced by
The call to ORM_RecordSet::save() has too many arguments starting with $noTrace. ( Ignorable by Annotation )

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

602
        return $this->getParentSet()->/** @scrutinizer ignore-call */ save($this, $noTrace);

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above.

Loading history...
603
    }
604
605
606
607
    /**
608
     * @return bool
609
     */
610
    public function isLinkedTo(app_Record $source, $linkType = null)
611
    {
612
        $linkSet = $this->App()->LinkSet();
613
614
        $criteria =	$linkSet->sourceClass->is(get_class($source))
615
            ->_AND_($linkSet->sourceId->is($source->id))
616
            ->_AND_($linkSet->targetClass->is(get_class($this)))
617
            ->_AND_($linkSet->targetId->is($this->id));
618
        if (isset($linkType)) {
619
            if (is_array($linkType)) {
620
                $criteria = $criteria->_AND_($linkSet->type->in($linkType));
621
            } else {
622
                $criteria = $criteria->_AND_($linkSet->type->is($linkType));
623
            }
624
        }
625
        $links = $linkSet->select($criteria);
0 ignored issues
show
Unused Code introduced by
The call to app_LinkSet::select() has too many arguments starting with $criteria. ( Ignorable by Annotation )

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

625
        /** @scrutinizer ignore-call */ 
626
        $links = $linkSet->select($criteria);

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above.

Loading history...
626
627
        $isLinked = ($links->count() > 0);
628
629
        $linkSet->__destruct();
630
        unset($linkSet);
631
632
        return $isLinked;
633
    }
634
635
636
637
    /**
638
     * @return bool
639
     */
640
    public function isSourceOf(app_Record $target, $linkType = null)
641
    {
642
        $linkSet = $this->App()->LinkSet();
643
644
        $criteria =	$linkSet->targetClass->is(get_class($target))
645
            ->_AND_($linkSet->targetId->is($target->id))
646
            ->_AND_($linkSet->sourceClass->is(get_class($this)))
647
            ->_AND_($linkSet->sourceId->is($this->id));
648
        if (isset($linkType)) {
649
            if (is_array($linkType)) {
650
                $criteria = $criteria->_AND_($linkSet->type->in($linkType));
651
            } else {
652
                $criteria = $criteria->_AND_($linkSet->type->is($linkType));
653
            }
654
        }
655
        $links = $linkSet->select($criteria);
0 ignored issues
show
Unused Code introduced by
The call to app_LinkSet::select() has too many arguments starting with $criteria. ( Ignorable by Annotation )

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

655
        /** @scrutinizer ignore-call */ 
656
        $links = $linkSet->select($criteria);

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above.

Loading history...
656
657
        $isLinked = ($links->count() > 0);
658
659
        $linkSet->__destruct();
660
        unset($linkSet);
661
662
        return $isLinked;
663
    }
664
665
666
667
    /**
668
     * Link record to $source
669
     *
670
     * @return app_TraceableRecord
671
     */
672
    public function linkTo(app_Record $source, $linkType = '')
673
    {
674
        $linkSet = $this->App()->LinkSet();
675
        /* @var $link app_Link */
676
        $link = $linkSet->newRecord();
677
        $link->sourceClass = get_class($source);
678
        $link->sourceId = $source->id;
679
        $link->targetClass = get_class($this);
680
        $link->targetId = $this->id;
681
        $link->type = $linkType;
682
        $link->save();
683
684
        $link->__destruct();
685
        unset($link);
686
687
        $linkSet->__destruct();
688
        unset($linkSet);
689
690
        return $this;
691
    }
692
}
693