Passed
Branchfeature/useWidgetsNamespaces (54f503)
by Robin
04:17
created

AppTraceableRecordSet::getDisplayNameField()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 5
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 4
c 0
b 0
f 0
dl 0
loc 5
rs 10
cc 2
nc 2
nop 0
1
<?php
2
3
// -------------------------------------------------------------------------
4
// OVIDENTIA http://www.ovidentia.org
5
// Ovidentia is free software; you can redistribute it and/or modify
6
// it under the terms of the GNU General Public License as published by
7
// the Free Software Foundation; either version 2, or (at your option)
8
// any later version.
9
//
10
// This program is distributed in the hope that it will be useful, but
11
// WITHOUT ANY WARRANTY; without even the implied warranty of
12
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
13
// See the GNU General Public License for more details.
14
//
15
// You should have received a copy of the GNU General Public License
16
// along with this program; if not, write to the Free Software
17
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
18
// USA.
19
// -------------------------------------------------------------------------
20
/**
21
 * @license http://opensource.org/licenses/gpl-license.php GNU General Public License (GPL)
22
 * @copyright Copyright (c) 2022 by SI4YOU ({@link https://www.siforyou.com})
23
 */
24
namespace Capwelton\LibApp\Set;
25
26
use Capwelton\LibApp\Func_App;
27
use Capwelton\LibOrm\Criteria\ORMCriteria;
0 ignored issues
show
Bug introduced by
The type Capwelton\LibOrm\Criteria\ORMCriteria was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
28
use Capwelton\LibOrm\ORMRecord;
0 ignored issues
show
Bug introduced by
The type Capwelton\LibOrm\ORMRecord was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
29
use Capwelton\LibOrm\Criteria\ORMIsCriterion;
0 ignored issues
show
Bug introduced by
The type Capwelton\LibOrm\Criteria\ORMIsCriterion was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
30
use function Capwelton\LibOrm\ORM_StringField;
0 ignored issues
show
introduced by
The function Capwelton\LibOrm\ORM_StringField was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
31
use function Capwelton\LibOrm\ORM_UserField;
0 ignored issues
show
introduced by
The function Capwelton\LibOrm\ORM_UserField was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
32
use function Capwelton\LibOrm\ORM_DatetimeField;
0 ignored issues
show
introduced by
The function Capwelton\LibOrm\ORM_DatetimeField was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
33
use function Capwelton\LibOrm\ORM_IntField;
0 ignored issues
show
introduced by
The function Capwelton\LibOrm\ORM_IntField was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
34
use function Capwelton\LibOrm\ORM_EnumField;
0 ignored issues
show
introduced by
The function Capwelton\LibOrm\ORM_EnumField was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
35
36
/**
37
 * @property ORMUserField $createdBy
38
 * @property ORMDateTimeField $createdOn
39
 * @property ORMIntField $modifiedBy
40
 * @property ORMDateTimeField $modifiedOn
41
 * @property ORMIntField $deletedBy
42
 * @property ORMDateTimeField $deletedOn
43
 * @property ORMEnumField $deleted
44
 * @property ORMStringField $uuid
45
 *
46
 * @method AppTraceableRecord                       get(mixed $criteria)
47
 * @method AppTraceableRecord                       request(mixed $criteria)
48
 * @method AppTraceableRecord[]|ORMMySqlIterator    select(ORMCriteria $criteria = null)
49
 * @method AppTraceableRecord                       newRecord()
50
 */
51
class AppTraceableRecordSet extends AppRecordSet
52
{
53
    
54
    /**
55
     * @var bool
56
     */
57
    private $loggable = false;
58
    
59
    /**
60
     * @var bool
61
     */
62
    private $traceable = true;
63
    
64
    /**
65
     * @param Func_App $App
66
     */
67
    public function __construct(Func_App $App)
68
    {
69
        parent::__construct($App);
70
        
71
        $this->addFields(
72
            ORM_UserField('createdBy')->setDescription('Created by'), 
73
            ORM_DatetimeField('createdOn')->setDescription('Created on'), 
74
            ORM_UserField('modifiedBy')->setDescription('Modified by'), 
75
            ORM_DateTimeField('modifiedOn')->setDescription('Modified on'), 
76
            ORM_IntField('deletedBy')->setDescription('Deleted by'), 
77
            ORM_DateTimeField('deletedOn')->setDescription('Deleted on'), 
78
            ORM_EnumField('deleted', AppTraceableRecord::getDeletedStatuses())->setDescription('Deleted'), 
79
            ORM_StringField('uuid')->setDescription('Universally Unique IDentifier')
80
        );
81
        
82
        // This condition will be applied whenever we select or join Records from this RecordSet.
83
        $this->setDefaultCriteria($this->deleted->is(false));
84
    }
85
    
86
    /**
87
     * Defines if the insertions/updates/deletions on the recordSet will be logged.
88
     *
89
     * @param bool $loggable
90
     * @return self
91
     */
92
    protected function setLoggable($loggable)
93
    {
94
        $this->loggable = $loggable;
95
        return $this;
96
    }
97
    
98
    /**
99
     * Checks if the insertions/updates/deletions on the recordSet will be logged.
100
     *
101
     * @return bool
102
     */
103
    protected function isLoggable()
104
    {
105
        return $this->loggable;
106
    }
107
    
108
    /**
109
     * Defines if the insertions/updates/deletions on the recordSet will be traced.
110
     *
111
     * @param bool $traceable
112
     * @return self
113
     */
114
    public function setTraceable($traceable)
115
    {
116
        $this->traceable = $traceable;
117
        return $this;
118
    }
119
    
120
    /**
121
     * Checks if the insertions/updates/deletions on the recordSet will be traced.
122
     *
123
     * @return bool
124
     */
125
    public function isTraceable()
126
    {
127
        return $this->traceable;
128
    }
129
    
130
    /**
131
     * @param AppTraceableRecord $record
132
     * @param bool $noTrace
133
     */
134
    protected function logSave(AppTraceableRecord $record, $noTrace)
135
    {
136
        if(! $this->isLoggable()){
137
            return;
138
        }
139
        $App = $this->App();
140
        $userId = bab_getUserId();
141
        $logSet = $App->LogSet();
142
        $log = $logSet->newRecord();
143
        $log->noTrace = $noTrace;
144
        $log->objectClass = get_class($record);
145
        $log->objectId = $record->id;
146
        $now = date('Y-m-d H:i:s');
147
        $log->modifiedOn = $now;
148
        $log->modifiedBy = $userId;
149
        $log->data = $logSet->serialize($record);
150
        $log->save();
151
    }
152
    
153
    /**
154
     * @param ORMCriteria $criteria
155
     * @param bool $noTrace
156
     */
157
    protected function logDelete(ORMCriteria $criteria, $noTrace)
158
    {
159
        if(! $this->isLoggable()){
160
            return;
161
        }
162
        $App = $this->App();
163
        $userId = bab_getUserId();
164
        $logSet = $App->LogSet();
165
        $deletedRecords = $this->select($criteria);
166
        foreach ($deletedRecords as $record){
167
            $log = $logSet->newRecord();
168
            $log->noTrace = $noTrace;
169
            $log->objectClass = get_class($record);
170
            $log->objectId = $record->id;
171
            $now = date('Y-m-d H:i:s');
172
            $log->modifiedOn = $now;
173
            $log->modifiedBy = $userId;
174
            $log->data = '';
175
            $log->save();
176
        }
177
    }
178
    
179
    /**
180
     * Returns an iterator on records matching the specified criteria.
181
     * The iterator will not include records flagged as deleted unless
182
     * the $includeDeleted parameter is set to true.
183
     *
184
     * @param ORMCriteria $criteria
185
     *            Criteria for selecting records.
186
     * @param bool $includeDeleted
187
     *            True to include delete-flagged records.
188
     * @return AppTraceableRecord[] Iterator on success, null if the backend has not been set
189
     */
190
    public function select(ORMCriteria $criteria = null, $includeDeleted = false)
191
    {
192
        if($includeDeleted){
193
            $this->setDefaultCriteria(null);
194
        }
195
        return parent::select($criteria);
0 ignored issues
show
Bug Best Practice introduced by
The expression return parent::select($criteria) returns the type Capwelton\LibApp\Set\App...MySql\ORMMySqlRecordSet which is incompatible with the documented return type Capwelton\LibApp\Set\AppTraceableRecord[].
Loading history...
196
    }
197
    
198
    /**
199
     * Returns the first item matching the specified criteria.
200
     * The item will not include records flagged as deleted unless
201
     * the $includeDeleted parameter is set to true.
202
     *
203
     * @param ORMCriteria $criteria
204
     *            Criteria for selecting records.
205
     * @param string $sPropertyName
206
     *            The name of the property on which the value applies. If not specified or null, the set's primary key will be used.
207
     * @param bool $includeDeleted
208
     *            True to include delete-flagged records.
209
     * @return \ORM_Item Iterator on success, null if the backend has not been set
210
     */
211
    /*
212
     * public function get(ORMCriteria $criteria = null, $sPropertyName = null, $includeDeleted = false)
213
     * {
214
     * if ($includeDeleted) {
215
     * $this->setDefaultCriteria(null);
216
     * }
217
     * return parent::get($criteria, $sPropertyName);
218
     * }
219
     */
220
    
221
    /**
222
     * Deleted records matching the specified criteria.
223
     * If $deletedStatus is true, records are not permanently deleted
224
     * If $deletedStatus is one of the crm_TraceableRecord::DELETED_STATUS_xxx constants, it is just
225
     * flagged with this status and kept in the database.
226
     *
227
     * @param ORMCriteria $criteria
228
     *            The criteria for selecting the records to delete.
229
     * @param int|bool $deletedStatus
230
     *            True to delete permanently the record.
231
     * @return bool True on success, false otherwise
232
     */
233
    public function delete(ORMCriteria $criteria = null, $deletedStatus = AppTraceableRecord::DELETED_STATUS_DELETED)
234
    {
235
        $definitive = ($deletedStatus === true) || ! $this->isTraceable();
236
        $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 Capwelton\LibApp\Set\App...eRecordSet::logDelete() does only seem to accept Capwelton\LibOrm\Criteria\ORMCriteria, 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

236
        $this->logDelete(/** @scrutinizer ignore-type */ $criteria, $definitive);
Loading history...
237
        if($definitive){
238
            return parent::delete($criteria);
239
        }
240
        
241
        require_once $GLOBALS['babInstallPath'] . '/utilit/dateTime.php';
242
        $now = \BAB_DateTime::now()->getIsoDateTime();
243
        
244
        $records = $this->select($criteria);
245
        
246
        foreach ($records as $record){
247
            /* @var $record AppTraceableRecord */
248
            // Could be optimized at ORM level
249
            $record->deleted = $deletedStatus;
0 ignored issues
show
Documentation Bug introduced by
It seems like $deletedStatus can also be of type false. However, the property $deleted is declared as type integer. 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...
250
            $record->deletedOn = $now;
251
            $record->deletedBy = bab_getUserId();
252
            
253
            if(! parent::save($record)){
254
                return false;
255
            }
256
        }
257
        return true;
258
    }
259
    
260
    /**
261
     * Saves a record and keeps traces of the user doing it.
262
     *
263
     * @param ORMRecord $record
264
     *            The record to save.
265
     * @param bool $noTrace
266
     *            True to bypass the tracing of modifications.
267
     * @return boolean True on success, false otherwise
268
     */
269
    public function save(ORMRecord $record, $noTrace = false)
270
    {
271
        $noTrace = $noTrace || ! $this->isTraceable();
272
        $this->logSave($record, $noTrace);
273
        if($noTrace){
274
            return parent::save($record);
275
        }
276
        
277
        require_once $GLOBALS['babInstallPath'] . '/utilit/dateTime.php';
278
        
279
        $now = \BAB_DateTime::now()->getIsoDateTime();
280
        
281
        // We first check if the record already has a createdBy.
282
        $set = $record->getParentSet();
283
        $primaryKey = $set->getPrimaryKey();
284
        
285
        if(empty($record->{$primaryKey})){
286
            $record->initValue('createdBy', bab_getUserId());
287
            $record->initValue('createdOn', $now);
288
            $record->initValue('uuid', $this->uuid());
289
        }
290
        
291
        $record->initValue('modifiedBy', bab_getUserId());
292
        $record->initValue('modifiedOn', $now);
293
        
294
        return parent::save($record);
295
    }
296
    
297
    /**
298
     * Generates a Universally Unique IDentifier, version 4.
299
     * RFC 4122 (http://www.ietf.org/rfc/rfc4122.txt)
300
     *
301
     * @return string
302
     */
303
    private function uuid()
304
    {
305
        return sprintf('%04x%04x-%04x-%04x-%04x-%04x%04x%04x', mt_rand(0, 0xffff), mt_rand(0, 0xffff), mt_rand(0, 0xffff), mt_rand(0, 0x0fff) | 0x4000, mt_rand(0, 0x3fff) | 0x8000, mt_rand(0, 0xffff), mt_rand(0, 0xffff), mt_rand(0, 0xffff));
306
    }
307
    
308
    /**
309
     * Get record by UUID or null if the record does not exists or is deleted or if the uuid is empty
310
     *
311
     * @param string $uuid
312
     * @return AppTraceableRecord
313
     */
314
    public function getRecordByUuid($uuid)
315
    {
316
        if('' === (string) $uuid){
317
            return null;
318
        }
319
        
320
        $record = $this->get($this->uuid->is($uuid));
321
        
322
        if(! isset($record)){
323
            return null;
324
        }
325
        
326
        if(! ($record instanceof AppTraceableRecord)){
327
            return null;
328
        }
329
        
330
        if($record->deleted){
331
            return null;
332
        }
333
        
334
        return $record;
335
    }
336
    
337
    /**
338
     * Match records created by the specified user or the current connected user if none specified.
339
     *
340
     * @param int|null $userId
341
     *
342
     * @return ORMIsCriterion
343
     */
344
    public function isOwn($userId = null)
345
    {
346
        if(! isset($userId)){
347
            $userId = bab_getUserId();
348
        }
349
        return $this->createdBy->is($userId);
350
    }
351
352
    public function getDisplayNameField(){
353
        if($this->fieldExist("name")){
354
            return $this->name;
355
        }else{
356
            return $this->uuid;
357
        }
358
    }
359
}
360