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

app_RecordSet::isRemovable()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 1
c 0
b 0
f 0
nc 1
nop 0
dl 0
loc 3
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
25
$App = app_App();
26
$App->includeBase();
27
28
29
/**
30
 *
31
 * @property ORM_PkField        $id
32
 *
33
 * @method app_Record   get(mixed $criteria)
34
 * @method app_Record   request(mixed $criteria)
35
 * @method app_Record[] select(\ORM_Criteria $criteria = null)
36
 * @method app_Record   newRecord()
37
 */
38
class app_RecordSet extends ORM_RecordSet implements app_Object_Interface
39
{
40
    /**
41
     * @var Func_App
42
     */
43
    protected $app = null;
44
45
    protected $accessRights = null;
46
47
    /**
48
     * @var app_AccessManager
49
     */
50
    private $accessManager = null;
51
52
    /**
53
     * @var array
54
     */
55
    private $customFields = null;
56
57
58
    /**
59
     * @param Func_App $app
60
     */
61
    public function __construct(Func_App $app)
62
    {
63
        parent::__construct();
64
        $this->setApp($app);
65
        $this->accessRights = array();
66
67
        $this->setAccessManager($app->AccessManager());
68
        $this->setPrimaryKey('id');
69
    }
70
71
    /**
72
     * {@inheritDoc}
73
     * @see app_Object_Interface::setApp()
74
     */
75
    public function setApp(Func_App $app)
76
    {
77
        $this->app = $app;
78
        return $this;
79
    }
80
81
82
    /**
83
     * {@inheritDoc}
84
     * @see app_Object_Interface::App()
85
     */
86
    public function App()
87
    {
88
        return $this->app;
89
    }
90
91
    /**
92
     * @param string $setName
93
     */
94
    protected function extractSetPrefixAndName($setName)
95
    {
96
        return explode('_', $setName);
97
    }
98
99
    /**
100
     * Similar to the ORM_RecordSet::join() method but instanciates the
101
     * joined RecordSet using App methods.
102
     *
103
     * @see ORM_RecordSet::join()
104
     */
105
    public function join($fkFieldName)
106
    {
107
        $fkField = $this->getField($fkFieldName);
108
        if (!($fkField instanceof ORM_FkField)) {
109
            return $this;
110
        }
111
        $setName = $fkField->getForeignSetName();
112
113
        if (!$setName || 'Set' === $setName) {
114
            throw new Exception('The set name is missing on foreign key field '.$fkFieldName);
115
        }
116
117
        list($prefix, $appSetName) = $this->extractSetPrefixAndName($setName);
118
119
        $set = $this->App()->$appSetName();
120
        $set->setName($fkField->getName());
121
        $set->setDescription($fkField->getDescription());
122
123
        $this->aField[$fkFieldName] = $set;
124
        $set->setParentSet($this);
125
        return $this;
126
    }
127
128
129
//     /**
130
//      *
131
//      * @param string $accessName
132
//      * @param string $type
133
//      */
134
//     public function addAccessRight($accessName, $type = 'acl')
135
//     {
136
//         $this->accessRights[$accessName] = $type;
137
//     }
138
139
140
//     /**
141
//      * @return array
142
//      */
143
//     public function getAccessRights()
144
//     {
145
//         return $this->accessRights;
146
//     }
147
148
149
150
    /**
151
     * @return app_CustomField[]
152
     */
153
    public function getCustomFields()
154
    {
155
        $App = $this->App();
156
157
        if (null === $this->customFields) {
158
            $this->customFields = array();
159
160
            if (isset($App->CustomField)) {
161
                $customFieldSet = $App->CustomFieldSet();
162
                $object = mb_substr(get_class($this), mb_strlen($App->classPrefix), -mb_strlen('Set'));
163
                try {
164
                    $customFields = $customFieldSet->select($customFieldSet->object->is($object));
165
166
                    foreach ($customFields as $customfield) {
167
                        $this->customFields[] = $customfield;
168
169
                        /*@var $customfield app_CustomField */
170
171
                    }
172
                } catch (ORM_BackEndSelectException $e) {
173
                    // table does not exist, this error is thrown by the install program while creating the sets
174
                }
175
            }
176
        }
177
178
        return $this->customFields;
179
    }
180
181
182
183
184
    /**
185
     * @return app_CustomField[]
186
     */
187
    public function selectCustomFields()
188
    {
189
        $App = $this->App();
190
191
        $customFieldSet= $App->CustomFieldSet();
192
        $object = mb_substr(get_class($this), mb_strlen($App->classPrefix), -mb_strlen('Set'));
193
194
        $customFields = $customFieldSet->select($customFieldSet->object->is($object));
195
196
        return $customFields;
197
    }
198
199
200
    /**
201
     * @return self
202
     */
203
    public function addCustomFields()
204
    {
205
        $customFields = $this->selectCustomFields();
206
        foreach ($customFields as $customField) {
207
            /*@var $customField app_CustomField */
208
            $description = $customField->name;
209
            $ormField = $customField->getORMField()
210
                ->setDescription($description);
211
            if ($ormField instanceof ORM_FkField) {
212
                $this->hasOne($customField->fieldname, $ormField->getForeignSetName())
213
                    ->setDescription($description);
214
            } else {
215
                $this->addFields($ormField);
216
            }
217
        }
218
219
        return $this;
220
    }
221
222
223
    /**
224
     * Similar to ORM_RecordSet::get() method  but throws a app_NotFoundException if the
225
     * record is not found.
226
     *
227
     * @since 1.0.18
228
     *
229
     * @throws ORM_Exception
230
     * @throws app_NotFoundException
231
     *
232
     * @param ORM_Criteria|string $mixedParam    Criteria for selecting records
233
     *                                           or the value for selecting record
234
     * @param string              $sPropertyName The name of the property on which
235
     *                                           the value applies. If not
236
     *                                           specified or null, the set's
237
     *                                           primary key will be used.
238
     *
239
     * @return app_Record
240
     */
241
    public function request($mixedParam = null, $sPropertyName = null)
242
    {
243
        $record = $this->get($mixedParam, $sPropertyName);
0 ignored issues
show
Unused Code introduced by
The call to app_RecordSet::get() has too many arguments starting with $sPropertyName. ( Ignorable by Annotation )

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

243
        /** @scrutinizer ignore-call */ 
244
        $record = $this->get($mixedParam, $sPropertyName);

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...
244
        if (!isset($record)) {
245
            // This will remove the default criteria for TraceableRecords and
246
            // fetch even 'deleted' ones.
247
            $this->setDefaultCriteria(null);
248
            $record = $this->get($mixedParam, $sPropertyName);
249
            if (isset($record)) {
250
                throw new app_DeletedRecordException($record, $mixedParam);
0 ignored issues
show
Unused Code introduced by
The call to app_DeletedRecordException::__construct() has too many arguments starting with $mixedParam. ( Ignorable by Annotation )

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

250
                throw /** @scrutinizer ignore-call */ new app_DeletedRecordException($record, $mixedParam);

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...
251
            }
252
            throw new app_NotFoundException($this, $mixedParam);
0 ignored issues
show
Bug introduced by
It seems like $mixedParam can also be of type ORM_Criteria; however, parameter $id of app_NotFoundException::__construct() does only seem to accept string, 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

252
            throw new app_NotFoundException($this, /** @scrutinizer ignore-type */ $mixedParam);
Loading history...
253
        }
254
        return $record;
255
    }
256
257
258
259
    /**
260
     * @param app_AccessManager $accessManager
261
     * @return self
262
     */
263
    public function setAccessManager(app_AccessManager $accessManager)
264
    {
265
        $this->accessManager = $accessManager;
266
        return $this;
267
    }
268
269
270
    /**
271
     * @return app_AccessManager
272
     */
273
    public function getAccessManager()
274
    {
275
        return $this->accessManager;
276
    }
277
278
279
    /**
280
     * Defines if records can be created by the current user.
281
     *
282
     * @return boolean
283
     */
284
    public function isCreatable()
285
    {
286
        return false;
287
    }
288
289
290
291
    /**
292
     *
293
     * @return ORM_Criteria
294
     */
295
    public function isReadable()
296
    {
297
        return $this->hasAccess('read');
298
    }
299
300
    /**
301
     *
302
     * @return ORM_Criteria
303
     */
304
    public function isUpdatable()
305
    {
306
        return $this->hasAccess('update');
307
    }
308
309
    /**
310
     *
311
     * @return ORM_Criteria
312
     */
313
    public function isDeletable()
314
    {
315
        return $this->hasAccess('delete');
316
    }
317
318
319
320
    /**
321
     * Returns a criterion matching records that can be put to trash by the current user.
322
     *
323
     * @return ORM_Criterion
324
     */
325
    public function isRemovable()
326
    {
327
        return $this->isUpdatable();
328
    }
329
330
331
    /**
332
     * Returns a criterion matching records deletable by the current user.
333
     *
334
     * @param string    $accessType
335
     * @param int|null  $user
336
     *
337
     * @return ORM_Criterion
338
     */
339
    public function hasAccess($accessType, $user = null)
340
    {
341
        $accessManager = $this->getAccessManager();
342
        return $accessManager->getAccessCriterion($this, $accessType, $user);
0 ignored issues
show
Bug Best Practice introduced by
The expression return $accessManager->g...is, $accessType, $user) returns the type ORM_FalseCriterion which is incompatible with the documented return type ORM_Criterion.
Loading history...
343
    }
344
}
345
346
347
348
/**
349
 * @property int        $id
350
 *
351
 * @method app_RecordSet getParentSet()
352
 */
353
class app_Record extends ORM_Record implements app_Object_Interface
354
{
355
    /**
356
     * @var Func_App
357
     */
358
    protected $app = null;
359
360
361
362
363
    /**
364
     * Returns the value of the specified field or an iterator if $sFieldName represents a 'Many relation'.
365
     *
366
     * @param string $sFieldName The name of the field or relation for which the value must be returned.
367
     * @param array  $args       Optional arguments.
368
     *
369
     * @return mixed The value of the field or null if the field is not a part of the record.
370
     */
371
    public function __call($sFieldName, $args)
372
    {
373
        $value = $this->oParentSet->getBackend()->getRecordValue($this, $sFieldName);
374
        $field = $this->oParentSet->$sFieldName;
375
        if (!is_null($value) && $field instanceof ORM_FkField) {
376
377
            $sClassName = $field->getForeignSetName();
378
379
            $App = $this->App();
380
            $prefixLength = mb_strlen($App->classPrefix);
381
            $methodName = mb_substr($sClassName, $prefixLength);
382
            $set = $App->$methodName();
383
384
            $set->setName($field->getName());
385
            $set->setDescription($field->getDescription());
386
387
            $record = $set->get($value);
388
            return $record;
389
        }
390
        return $value;
391
    }
392
393
    /**
394
     * {@inheritDoc}
395
     * @see app_Object_Interface::setApp()
396
     */
397
    public function setApp(Func_App $app)
398
    {
399
        $this->app = $app;
400
        return $this;
401
    }
402
403
    /**
404
     * Get APP object to use with this record
405
     *
406
     * @return Func_App
407
     */
408
    public function App()
409
    {
410
        if (!isset($this->app)) {
411
            // If the app object was not specified (through the setApp() method),
412
            // we set it as parent set's App.
413
            $this->setApp($this->getParentSet()->App());
414
        }
415
        return $this->app;
416
    }
417
418
419
    /**
420
     * Returns the base class name of a record.
421
     * For example xxx_Contact will return 'Contact'.
422
     *
423
     * @since 1.0.40
424
     * @return string
425
     */
426
    public function getClassName()
427
    {
428
        list(, $classname) = explode('_', get_class($this));
429
        return $classname;
430
    }
431
432
433
    /**
434
     * Returns the string reference corresponding to the record.
435
     *
436
     * @return string 	A reference string (e.g. Contact:12)
437
     */
438
    public function getRef()
439
    {
440
        if (!isset($this->id)) {
441
            throw new app_Exception('Trying to get the reference string of a record without an id.');
442
        }
443
        $classname = $this->getClassName();
444
        return $classname . ':' . $this->id;
445
    }
446
447
448
    /**
449
     * @return app_Controller
450
     */
451
    public function getController()
452
    {
453
        $App = $this->App();
454
455
        $ctrlName = $this->getClassName();
456
        return $App->Controller()->$ctrlName();
457
    }
458
459
460
    /**
461
     * Deletes the record with respect to referential integrity.
462
     *
463
     * Uses referential integrity as defined by hasManyRelation to delete/update
464
     * referenced elements.
465
     *
466
     * @see app_RecordSet::hasMany()
467
     *
468
     * @return self
469
     */
470
    public function delete($deletedStatus = null)
471
    {
472
        $App = $this->App();
473
474
        if (!isset($deletedStatus)) {
475
            $deletedStatus = app_TraceableRecord::DELETED_STATUS_DELETED;
476
        }
477
478
        $set = $this->getParentSet();
479
        $recordIdName = $set->getPrimaryKey();
480
        $recordId = $this->$recordIdName;
481
482
        // Uses referential integrity as defined by hasManyRelation to delete/update
483
        // referenced elements.
484
        $manyRelations = $set->getHasManyRelations();
485
486
487
        foreach ($manyRelations as $manyRelation) {
488
            /* @var $manyRelation ORM_ManyRelation */
489
490
            $foreignSetClassName = $manyRelation->getForeignSetClassName();
491
            $foreignSetFieldName = $manyRelation->getForeignFieldName();
492
            $method = mb_substr($foreignSetClassName, mb_strlen($App->classPrefix));
493
            $foreignSet = $App->$method();
494
495
            switch ($manyRelation->getOnDeleteMethod()) {
496
497
                case ORM_ManyRelation::ON_DELETE_SET_NULL:
498
499
                    $foreignRecords = $foreignSet->select($foreignSet->$foreignSetFieldName->is($recordId));
500
501
                    foreach ($foreignRecords as $foreignRecord) {
502
                        $foreignRecord->$foreignSetFieldName = 0;
503
                        $foreignRecord->save();
504
                    }
505
506
                    break;
507
508
                case ORM_ManyRelation::ON_DELETE_CASCADE:
509
510
                    $foreignRecords = $foreignSet->select($foreignSet->$foreignSetFieldName->is($recordId));
511
512
                    foreach ($foreignRecords as $foreignRecord) {
513
                        $foreignRecord->delete();
514
                    }
515
516
                    break;
517
518
                case ORM_ManyRelation::ON_DELETE_NO_ACTION:
519
                default:
520
                    break;
521
522
            }
523
        }
524
525
526
        // We remove all links to and from this record.
527
        $linkSet = $App->LinkSet();
528
529
        $linkSet->delete(
530
            $linkSet->sourceClass->is(get_class($this))->_AND_($linkSet->sourceId->is($recordId))
531
            ->_OR_(
532
                $linkSet->targetClass->is(get_class($this))->_AND_($linkSet->targetId->is($recordId))
533
            )
534
        );
535
536
537
        $set->delete($set->$recordIdName->is($recordId), $deletedStatus);
0 ignored issues
show
Unused Code introduced by
The call to ORM_RecordSet::delete() has too many arguments starting with $deletedStatus. ( Ignorable by Annotation )

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

537
        $set->/** @scrutinizer ignore-call */ 
538
              delete($set->$recordIdName->is($recordId), $deletedStatus);

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...
538
539
        return $this;
540
    }
541
542
543
544
    /**
545
     * Reassociates all data asociated to the record to another
546
     * specified one.
547
     *
548
     * @param	int		$id
549
     *
550
     * @return self
551
     */
552
    public function replaceWith($id)
553
    {
554
        $App = $this->App();
555
556
        $set = $this->getParentSet();
557
        $recordIdName = $set->getPrimaryKey();
558
        $recordId = $this->$recordIdName;
559
560
        // Use referential integrity as defined by hasManyRelation to delete/update
561
        // referenced elements.
562
        $manyRelations = $set->getHasManyRelations();
563
564
565
        foreach ($manyRelations as $manyRelation) {
566
            /* @var $manyRelation ORM_ManyRelation */
567
568
            $foreignSetClassName = $manyRelation->getForeignSetClassName();
569
            $foreignSetFieldName = $manyRelation->getForeignFieldName();
570
            $method = mb_substr($foreignSetClassName, mb_strlen($App->classPrefix));
571
            $foreignSet = $App->$method();
572
            // $foreignSet = new $foreignSetClassName($App);
573
            $foreignRecords = $foreignSet->select($foreignSet->$foreignSetFieldName->is($recordId));
574
575
            foreach ($foreignRecords as $foreignRecord) {
576
                $foreignRecord->$foreignSetFieldName = $id;
577
                $foreignRecord->save();
578
            }
579
        }
580
581
582
        // We replace all links to and from this record.
583
        $linkSet = $App->LinkSet();
584
585
        $links = $linkSet->select(
586
            $linkSet->sourceClass->is(get_class($this))->_AND_($linkSet->sourceId->is($recordId))
0 ignored issues
show
Unused Code introduced by
The call to app_LinkSet::select() has too many arguments starting with $linkSet->sourceClass->i...ourceId->is($recordId)). ( Ignorable by Annotation )

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

586
        /** @scrutinizer ignore-call */ 
587
        $links = $linkSet->select(

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...
587
        );
588
589
        foreach ($links as $link) {
590
            $link->sourceId = $id;
591
            $link->save();
592
        }
593
594
        $links = $linkSet->select(
595
            $linkSet->targetClass->is(get_class($this))->_AND_($linkSet->targetId->is($recordId))
596
        );
597
598
        foreach ($links as $link) {
599
            $link->targetId = $id;
600
            $link->save();
601
        }
602
603
        return $this;
604
    }
605
606
607
    /**
608
     *
609
     *
610
     * @return array
611
     */
612
    public function getRelatedRecords()
613
    {
614
        $App = $this->App();
615
616
        $set = $this->getParentSet();
617
        $recordIdName = $set->getPrimaryKey();
618
        $recordId = $this->$recordIdName;
619
620
        // Use referential integrity as defined by hasManyRelation to delete/update
621
        // referenced elements.
622
        $manyRelations = $set->getHasManyRelations();
623
624
        $relatedRecords = array();
625
626
        foreach ($manyRelations as $manyRelation) {
627
            /* @var $manyRelation ORM_ManyRelation */
628
629
            $foreignSetClassName = $manyRelation->getForeignSetClassName();
630
            $foreignSetFieldName = $manyRelation->getForeignFieldName();
631
632
            $method = mb_substr($foreignSetClassName, mb_strlen($App->classPrefix));
633
            $foreignSet = $App->$method();
634
            // $foreignSet = new $foreignSetClassName($App);
635
            $foreignRecords = $foreignSet->select($foreignSet->$foreignSetFieldName->is($recordId));
636
637
638
            if ($foreignRecords->count() > 0) {
639
                $relatedRecords[$foreignSetClassName] = $foreignRecords;
640
            }
641
        }
642
643
        return $relatedRecords;
644
    }
645
646
647
648
649
650
651
    /**
652
     * Upload path for record attachments
653
     *
654
     * @return bab_Path
655
     */
656
    public function uploadPath()
657
    {
658
        $path = $this->App()->uploadPath();
0 ignored issues
show
Bug introduced by
The method uploadPath() does not exist on Func_App. Since you implemented __call, consider adding a @method annotation. ( Ignorable by Annotation )

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

658
        $path = $this->App()->/** @scrutinizer ignore-call */ uploadPath();
Loading history...
659
660
        if (null === $path)
661
        {
662
            throw new Exception('Missing upload path information');
663
            return null;
0 ignored issues
show
Unused Code introduced by
return null is not reachable.

This check looks for unreachable code. It uses sophisticated control flow analysis techniques to find statements which will never be executed.

Unreachable code is most often the result of return, die or exit statements that have been added for debug purposes.

function fx() {
    try {
        doSomething();
        return true;
    }
    catch (\Exception $e) {
        return false;
    }

    return false;
}

In the above example, the last return false will never be executed, because a return statement has already been met in every possible execution path.

Loading history...
664
        }
665
666
        $path->push(get_class($this));
667
        $path->push($this->id);
668
669
        return $path;
670
    }
671
672
673
674
675
676
677
    /**
678
     * import a value into a traceable record property if the value is not equal
679
     *
680
     * @param	string	$name		property name
681
     * @param	mixed	$value		value to set
682
     *
683
     * @return int		1 : the value has been modified | 0 : no change
684
     */
685
    protected function importProperty($name, $value)
686
    {
687
        if (((string) $this->$name) !== ((string) $value)) {
688
            $this->$name = $value;
689
            return 1;
690
        }
691
692
        return 0;
693
    }
694
695
696
697
    /**
698
     * import a value into a tracable record property if the value is not equal, try with multiple date format
699
     * this method work for date field 0000-00-00
700
     *
701
     * @param	string	$name		property name
702
     * @param	mixed	$value		value to set
703
     *
704
     * @return int		1 : the value has been modified | 0 : no change
705
     */
706
    protected function importDate($name, $value)
707
    {
708
        if (preg_match('/[0-9]{4}-[0-9]{2}-[0-9]{2}/',$value)) {
709
            return $this->importProperty($name, $value);
710
        }
711
712
        // try in DD/MM/YYYY format
713
714
        if (preg_match('/(?P<day>[0-9]+)\/(?P<month>[0-9]+)\/(?P<year>[0-9]{2,4})/',$value, $matches)) {
715
716
            $value = sprintf('%04d-%02d-%02d', (int) $matches['year'], (int) $matches['month'], (int) $matches['day']);
717
718
            return $this->importProperty($name, $value);
719
        }
720
721
    }
722
723
724
725
726
    /**
727
     *
728
     * @return string[]
729
     */
730
    public function getViews()
731
    {
732
        $App = $this->App();
733
734
        $customSectionSet = $App->CustomSectionSet();
735
        $customSections = $customSectionSet->select($customSectionSet->object->is($this->getClassName()));
736
        $customSections->groupBy($customSectionSet->view);
737
738
        $views = array();
739
        foreach ($customSections as $customSection) {
740
            $views[] = $customSection->view;
741
        }
742
743
        if (empty($views)) {
744
            $views[] = '';
745
        }
746
747
        return $views;
748
    }
749
750
751
752
    /**
753
     * Checks if the record is readable by the current user.
754
     * @since 1.0.21
755
     * @return bool
756
     */
757
    public function isReadable()
758
    {
759
        $set = $this->getParentSet();
760
        return $set->select($set->isReadable()->_AND_($set->id->is($this->id)))->count() == 1;
761
    }
762
763
764
    /**
765
     * Checks if the record is updatable by the current user.
766
     * @since 1.0.21
767
     * @return bool
768
     */
769
    public function isUpdatable()
770
    {
771
        $set = $this->getParentSet();
772
        return $set->select($set->isUpdatable()->_AND_($set->id->is($this->id)))->count() == 1;
773
    }
774
775
    /**
776
     * Checks if the record is deletable by the current user.
777
     * @since 1.0.21
778
     * @return bool
779
     */
780
    public function isDeletable()
781
    {
782
        $set = $this->getParentSet();
783
        return $set->select($set->isDeletable()->_AND_($set->id->is($this->id)))->count() == 1;
784
    }
785
786
787
    /**
788
     * Checks if the record can be put to the trash by the current user.
789
     * @return bool
790
     */
791
    public function isRemovable()
792
    {
793
        $set = $this->getParentSet();
794
        return $set->select($set->isRemovable()->_AND_($set->id->is($this->id)))->count() == 1;
795
    }
796
797
798
    /**
799
     * Ensures that the record is readable by the current user or throws an exception.
800
     * @since 1.0.40
801
     * @param string $message
802
     * @throws app_AccessException
803
     */
804
    public function requireReadable($message = null)
805
    {
806
        if (!$this->isReadable()) {
807
            $App = $this->App();
808
            if (!isset($message)) {
809
                $message = $App->translate('Access denied');
810
            }
811
            throw new app_AccessException($message);
812
        }
813
    }
814
815
    /**
816
     * Ensures that the record is updatable by the current user or throws an exception.
817
     * @since 1.0.40
818
     * @param string $message
819
     * @throws app_AccessException
820
     */
821
    public function requireUpdatable($message = null)
822
    {
823
        if (!$this->isUpdatable()) {
824
            $App = $this->App();
825
            if (!isset($message)) {
826
                $message = $App->translate('Access denied');
827
            }
828
            throw new app_AccessException($message);
829
        }
830
    }
831
832
    /**
833
     * Ensures that the record is deletable by the current user or throws an exception.
834
     * @since 1.0.40
835
     * @param string $message
836
     * @throws app_AccessException
837
     */
838
    public function requireDeletable($message = null)
839
    {
840
        if (!$this->isDeletable()) {
841
            $App = $this->App();
842
            if (!isset($message)) {
843
                $message = $App->translate('Access denied');
844
            }
845
            throw new app_AccessException($message);
846
        }
847
    }
848
}
849
850