Passed
Push — EXTRACT_CLASSES ( 9f3ede...ff35ec )
by Rafael
76:09 queued 20:57
created

Evaluation::getNomUrl()   F

Complexity

Conditions 34
Paths > 20000

Size

Total Lines 103
Code Lines 67

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 34
eloc 67
nc 20736
nop 5
dl 0
loc 103
rs 0
c 0
b 0
f 0

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
/* Copyright (C) 2017       Laurent Destailleur         <[email protected]>
4
 * Copyright (C) 2021       Gauthier VERDOL             <[email protected]>
5
 * Copyright (C) 2021       Greg Rastklan               <[email protected]>
6
 * Copyright (C) 2021       Jean-Pascal BOUDET          <[email protected]>
7
 * Copyright (C) 2021       Grégory BLEMAND             <[email protected]>
8
 * Copyright (C) 2024       Frédéric France             <[email protected]>
9
 * Copyright (C) 2024		MDW							<[email protected]>
10
 * Copyright (C) 2024       Rafael San José             <[email protected]>
11
 *
12
 * This program is free software; you can redistribute it and/or modify
13
 * it under the terms of the GNU General Public License as published by
14
 * the Free Software Foundation; either version 3 of the License, or
15
 * (at your option) any later version.
16
 *
17
 * This program is distributed in the hope that it will be useful,
18
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20
 * GNU General Public License for more details.
21
 *
22
 * You should have received a copy of the GNU General Public License
23
 * along with this program. If not, see <https://www.gnu.org/licenses/>.
24
 */
25
26
namespace Dolibarr\Code\Hrm\Classes;
27
28
use Dolibarr\Core\Base\CommonObject;
29
30
/**
31
 *    \file        htdocs/hrm/class/evaluation.class.php
32
 *    \ingroup     hrm
33
 *    \brief       This file is a CRUD class file for Evaluation (Create/Read/Update/Delete)
34
 */
35
36
require_once constant('DOL_DOCUMENT_ROOT') . '/hrm/class/evaluationdet.class.php';
37
38
/**
39
 * Class for Evaluation
40
 */
41
class Evaluation extends CommonObject
42
{
43
    /**
44
     * @var string ID of module.
45
     */
46
    public $module = 'hrm';
47
48
    /**
49
     * @var string ID to identify managed object.
50
     */
51
    public $element = 'evaluation';
52
53
    /**
54
     * @var string Name of table without prefix where object is stored. This is also the key used for extrafields management.
55
     */
56
    public $table_element = 'hrm_evaluation';
57
58
    /**
59
     * @var string String with name of icon for evaluation. Must be the part after the 'object_' into object_evaluation.png
60
     */
61
    public $picto = 'label';
62
63
64
    const STATUS_DRAFT = 0;
65
    const STATUS_VALIDATED = 1;
66
    const STATUS_CANCELED = 9;
67
    const STATUS_CLOSED = 6;
68
69
70
    /**
71
     *  'type' field format ('integer', 'integer:ObjectClass:PathToClass[:AddCreateButtonOrNot[:Filter[:Sortfield]]]', 'sellist:TableName:LabelFieldName[:KeyFieldName[:KeyFieldParent[:Filter]]]', 'varchar(x)', 'double(24,8)', 'real', 'price', 'text', 'text:none', 'html', 'date', 'datetime', 'timestamp', 'duration', 'mail', 'phone', 'url', 'password')
72
     *         Note: Filter can be a string like "(t.ref:like:'SO-%') or (t.date_creation:<:'20160101') or (t.nature:is:NULL)"
73
     *  'label' the translation key.
74
     *  'picto' is code of a picto to show before value in forms
75
     *  'enabled' is a condition when the field must be managed (Example: 1 or 'getDolGlobalString("MY_SETUP_PARAM")')
76
     *  'position' is the sort order of field.
77
     *  'notnull' is set to 1 if not null in database. Set to -1 if we must set data to null if empty ('' or 0).
78
     *  'visible' says if field is visible in list (Examples: 0=Not visible, 1=Visible on list and create/update/view forms, 2=Visible on list only, 3=Visible on create/update/view form only (not list), 4=Visible on list and update/view form only (not create). 5=Visible on list and view only (not create/not update). Using a negative value means field is not shown by default on list but can be selected for viewing)
79
     *  'noteditable' says if field is not editable (1 or 0)
80
     *  'default' is a default value for creation (can still be overwrote by the Setup of Default Values if field is editable in creation form). Note: If default is set to '(PROV)' and field is 'ref', the default value will be set to '(PROVid)' where id is rowid when a new record is created.
81
     *  'index' if we want an index in database.
82
     *  'foreignkey'=>'tablename.field' if the field is a foreign key (it is recommended to name the field fk_...).
83
     *  'searchall' is 1 if we want to search in this field when making a search from the quick search button.
84
     *  'isameasure' must be set to 1 if you want to have a total on list for this field. Field type must be summable like integer or double(24,8).
85
     *  'css' and 'cssview' and 'csslist' is the CSS style to use on field. 'css' is used in creation and update. 'cssview' is used in view mode. 'csslist' is used for columns in lists. For example: 'css'=>'minwidth300 maxwidth500 widthcentpercentminusx', 'cssview'=>'wordbreak', 'csslist'=>'tdoverflowmax200'
86
     *  'help' is a 'TranslationString' to use to show a tooltip on field. You can also use 'TranslationString:keyfortooltiponlick' for a tooltip on click.
87
     *  'showoncombobox' if value of the field must be visible into the label of the combobox that list record
88
     *  'disabled' is 1 if we want to have the field locked by a 'disabled' attribute. In most cases, this is never set into the definition of $fields into class, but is set dynamically by some part of code.
89
     *  'arrayofkeyval' to set a list of values if type is a list of predefined values. For example: array("0"=>"Draft","1"=>"Active","-1"=>"Cancel"). Note that type can be 'integer' or 'varchar'
90
     *  'autofocusoncreate' to have field having the focus on a create form. Only 1 field should have this property set to 1.
91
     *  'comment' is not used. You can store here any text of your choice. It is not used by application.
92
     *
93
     *  Note: To have value dynamic, you can set value to 0 in definition and edit the value on the fly into the constructor.
94
     */
95
96
    // BEGIN MODULEBUILDER PROPERTIES
97
    /**
98
     * @var array<string,array{type:string,label:string,enabled:int<0,2>|string,position:int,notnull?:int,visible:int,noteditable?:int,default?:string,index?:int,foreignkey?:string,searchall?:int,isameasure?:int,css?:string,csslist?:string,help?:string,showoncombobox?:int,disabled?:int,arrayofkeyval?:array<int,string>,comment?:string}>  Array with all fields and their property. Do not use it as a static var. It may be modified by constructor.
0 ignored issues
show
Documentation Bug introduced by
The doc comment array<string,array{type:...ring>,comment?:string}> at position 16 could not be parsed: Expected '}' at position 16, but found 'int'.
Loading history...
99
     */
100
    public $fields = array(
101
        'rowid' => array('type' => 'integer', 'label' => 'TechnicalID', 'enabled' => 1, 'position' => 1, 'notnull' => 1, 'visible' => 0, 'noteditable' => 1, 'index' => 1, 'css' => 'left', 'comment' => "Id"),
102
        'ref' => array('type' => 'varchar(128)', 'label' => 'Ref', 'enabled' => 1, 'position' => 20, 'notnull' => 1, 'visible' => 4, 'noteditable' => 1, 'default' => '(PROV)', 'index' => 1, 'searchall' => 1, 'showoncombobox' => 1, 'comment' => "Reference of object"),
103
        'label' => array('type' => 'varchar(255)', 'label' => 'Label', 'enabled' => 1, 'position' => 30, 'notnull' => 0, 'visible' => 1, 'searchall' => 1, 'css' => 'minwidth300', 'cssview' => 'wordbreak', 'showoncombobox' => '2',),
104
        'description' => array('type' => 'text', 'label' => 'Description', 'enabled' => 1, 'position' => 60, 'notnull' => 0, 'visible' => 3,),
105
        'note_public' => array('type' => 'html', 'label' => 'NotePublic', 'enabled' => 1, 'position' => 61, 'notnull' => 0, 'visible' => 0,),
106
        'note_private' => array('type' => 'html', 'label' => 'NotePrivate', 'enabled' => 1, 'position' => 62, 'notnull' => 0, 'visible' => 0,),
107
        'date_creation' => array('type' => 'datetime', 'label' => 'DateCreation', 'enabled' => 1, 'position' => 500, 'notnull' => 1, 'visible' => -2,),
108
        'tms' => array('type' => 'timestamp', 'label' => 'DateModification', 'enabled' => 1, 'position' => 501, 'notnull' => 0, 'visible' => -2,),
109
        'fk_user_creat' => array('type' => 'integer:User:user/class/user.class.php:0', 'label' => 'UserAuthor', 'enabled' => 1, 'position' => 510, 'notnull' => 1, 'visible' => -2, 'foreignkey' => 'user.rowid',),
110
        'fk_user_modif' => array('type' => 'integer:User:user/class/user.class.php:0', 'label' => 'UserModif', 'enabled' => 1, 'position' => 511, 'notnull' => -1, 'visible' => -2,),
111
        'import_key' => array('type' => 'varchar(14)', 'label' => 'ImportId', 'enabled' => 1, 'position' => 1000, 'notnull' => -1, 'visible' => -2,),
112
        'status' => array('type' => 'smallint', 'label' => 'Status', 'enabled' => 1, 'position' => 1000, 'notnull' => 1, 'default' => '0', 'visible' => 5, 'index' => 1, 'arrayofkeyval' => array('0' => 'Draft', '1' => 'Validated', '6' => 'Closed'),),
113
        'date_eval' => array('type' => 'date', 'label' => 'DateEval', 'enabled' => 1, 'position' => 502, 'notnull' => 1, 'visible' => 1,),
114
        'fk_user' => array('type' => 'integer:User:user/class/user.class.php:0', 'label' => 'Employee', 'enabled' => 1, 'position' => 504, 'notnull' => 1, 'visible' => 1, 'picto' => 'user', 'css' => 'maxwidth300 widthcentpercentminusxx', 'csslist' => 'tdoverflowmax150'),
115
        'fk_job' => array('type' => 'integer:Job:/hrm/class/job.class.php', 'label' => 'JobProfile', 'enabled' => 1, 'position' => 505, 'notnull' => 1, 'visible' => 1, 'picto' => 'jobprofile', 'css' => 'maxwidth300 widthcentpercentminusxx', 'csslist' => 'tdoverflowmax150'),
116
    );
117
    public $rowid;
118
    public $ref;
119
    public $label;
120
    public $description;
121
    public $note_public;
122
    public $note_private;
123
    public $date_creation;
124
    public $fk_user_creat;
125
    public $fk_user_modif;
126
    public $import_key;
127
    public $status;
128
    public $date_eval;
129
    public $fk_user;
130
    public $fk_job;
131
    // END MODULEBUILDER PROPERTIES
132
133
134
    // If this object has a subtable with lines
135
136
    /**
137
     * @var string    Name of subtable line
138
     */
139
    public $table_element_line = 'hrm_evaluationdet';
140
141
    /**
142
     * @var string    Field with ID of parent key if this object has a parent
143
     */
144
    public $fk_element = 'fk_evaluation';
145
146
    /**
147
     * @var string    Name of subtable class that manage subtable lines
148
     */
149
    public $class_element_line = 'EvaluationLine';
150
151
    // /**
152
    //  * @var array    List of child tables. To test if we can delete object.
153
    //  */
154
    // protected $childtables = array();
155
156
    /**
157
     * @var string[] List of child tables. To know object to delete on cascade.
158
     *               If name matches '@ClassNAme:FilePathClass;ParentFkFieldName' it will
159
     *               call method deleteByParentField(parentId, ParentFkFieldName) to fetch and delete child object
160
     */
161
    protected $childtablesoncascade = array('@EvaluationLine:hrm/class/evaluationdet.class.php:fk_evaluation');
162
163
    /**
164
     * @var EvaluationLine[]     Array of subtable lines
165
     */
166
    public $lines = array();
167
168
169
170
    /**
171
     * Constructor
172
     *
173
     * @param DoliDB $db Database handler
174
     */
175
    public function __construct(DoliDB $db)
0 ignored issues
show
Bug introduced by
The type Dolibarr\Code\Hrm\Classes\DoliDB was not found. Did you mean DoliDB? If so, make sure to prefix the type with \.
Loading history...
176
    {
177
        global $conf, $langs, $user;
178
179
        $this->db = $db;
180
181
        $this->ismultientitymanaged = 0;
182
        $this->isextrafieldmanaged = 1;
183
184
        if (!getDolGlobalString('MAIN_SHOW_TECHNICAL_ID') && isset($this->fields['rowid'])) {
185
            $this->fields['rowid']['visible'] = 0;
186
        }
187
        if (!isModEnabled('multicompany') && isset($this->fields['entity'])) {
188
            $this->fields['entity']['enabled'] = 0;
189
        }
190
191
        if (!$user->hasRight('hrm', 'evaluation', 'readall')) {
192
            $this->fields['fk_user']['type'] .= ':rowid IN(' . $this->db->sanitize(implode(", ", $user->getAllChildIds(1))) . ')';
193
        }
194
195
        $this->date_eval = dol_now();
196
197
        // Unset fields that are disabled
198
        foreach ($this->fields as $key => $val) {
199
            if (isset($val['enabled']) && empty($val['enabled'])) {
200
                unset($this->fields[$key]);
201
            }
202
        }
203
204
        // Translate some data of arrayofkeyval
205
        if (is_object($langs)) {
206
            foreach ($this->fields as $key => $val) {
207
                if (!empty($val['arrayofkeyval']) && is_array($val['arrayofkeyval'])) {
208
                    foreach ($val['arrayofkeyval'] as $key2 => $val2) {
209
                        $this->fields[$key]['arrayofkeyval'][$key2] = $langs->trans($val2);
210
                    }
211
                }
212
            }
213
        }
214
    }
215
216
    /**
217
     * Create object into database
218
     *
219
     * @param  User $user      User that creates
220
     * @param  int  $notrigger 0=launch triggers after, 1=disable triggers
221
     * @return int             Return integer <0 if KO, Id of created object if OK
222
     */
223
    public function create(User $user, $notrigger = 0)
0 ignored issues
show
Bug introduced by
The type Dolibarr\Code\Hrm\Classes\User was not found. Did you mean User? If so, make sure to prefix the type with \.
Loading history...
224
    {
225
        $resultcreate = $this->createCommon($user, $notrigger);
226
227
        if ($resultcreate > 0) {
228
            require_once constant('DOL_DOCUMENT_ROOT') . '/hrm/class/skillrank.class.php';
229
            $skillRank = new SkillRank($this->db);
230
            $TRequiredRanks = $skillRank->fetchAll('ASC', 't.rowid', 0, 0, '(fk_object:=:' . ((int) $this->fk_job) . ") AND (objecttype:=:'job')");
231
232
            if (is_array($TRequiredRanks) && !empty($TRequiredRanks)) {
233
                $this->lines = array();
234
                foreach ($TRequiredRanks as $required) {
235
                    $line = new EvaluationLine($this->db);
236
                    $line->fk_evaluation = $resultcreate;
237
                    $line->fk_skill = $required->fk_skill;
238
                    $line->required_rank = $required->rankorder;
239
                    $line->fk_rank = 0;
240
241
                    $res = $line->create($user, $notrigger);
242
                    if ($res > 0) {
243
                        $this->lines[] = $line;
244
                    }
245
                }
246
            }
247
        }
248
249
        return $resultcreate;
250
    }
251
252
    /**
253
     * Clone an object into another one
254
     *
255
     * @param   User    $user       User that creates
256
     * @param   int     $fromid     Id of object to clone
257
     * @return  mixed               New object created, <0 if KO
258
     */
259
    public function createFromClone(User $user, $fromid)
260
    {
261
        global $langs, $extrafields;
262
        $error = 0;
263
264
        dol_syslog(__METHOD__, LOG_DEBUG);
265
266
        $object = new self($this->db);
267
268
        $this->db->begin();
269
270
        // Load source object
271
        $result = $object->fetchCommon($fromid);
272
        if ($result > 0 && !empty($object->table_element_line)) {
273
            $object->fetchLines();
274
        }
275
276
        // get lines so they will be clone
277
        //foreach($this->lines as $line)
278
        //  $line->fetch_optionals();
279
280
        // Reset some properties
281
        unset($object->id);
282
        unset($object->fk_user_creat);
283
        unset($object->import_key);
284
285
        // Clear fields
286
        if (property_exists($object, 'ref')) {
287
            $object->ref = empty($this->fields['ref']['default']) ? "Copy_Of_" . $object->ref : $this->fields['ref']['default'];
288
        }
289
        if (property_exists($object, 'label')) {
290
            $object->label = empty($this->fields['label']['default']) ? $langs->trans("CopyOf") . " " . $object->label : $this->fields['label']['default'];
291
        }
292
        if (property_exists($object, 'status')) {
293
            $object->status = self::STATUS_DRAFT;
294
        }
295
        if (property_exists($object, 'date_creation')) {
296
            $object->date_creation = dol_now();
297
        }
298
        if (property_exists($object, 'date_modification')) {
299
            $object->date_modification = null;
300
        }
301
        // ...
302
        // Clear extrafields that are unique
303
        if (is_array($object->array_options) && count($object->array_options) > 0) {
304
            $extrafields->fetch_name_optionals_label($this->table_element);
305
            foreach ($object->array_options as $key => $option) {
306
                $shortkey = preg_replace('/options_/', '', $key);
307
                if (!empty($extrafields->attributes[$this->table_element]['unique'][$shortkey])) {
308
                    //var_dump($key); var_dump($clonedObj->array_options[$key]); exit;
309
                    unset($object->array_options[$key]);
310
                }
311
            }
312
        }
313
314
        // Create clone
315
        $object->context['createfromclone'] = 'createfromclone';
316
        $result = $object->createCommon($user);
317
        if ($result < 0) {
318
            $error++;
319
            $this->setErrorsFromObject($object);
320
        }
321
322
        if (!$error) {
323
            // copy internal contacts
324
            if ($this->copy_linked_contact($object, 'internal') < 0) {
325
                $error++;
326
            }
327
        }
328
329
        if (!$error) {
330
            // copy external contacts if same company
331
            if (property_exists($this, 'fk_soc') && $this->fk_soc == $object->socid) {
332
                if ($this->copy_linked_contact($object, 'external') < 0) {
333
                    $error++;
334
                }
335
            }
336
        }
337
338
        unset($object->context['createfromclone']);
339
340
        // End
341
        if (!$error) {
342
            $this->db->commit();
343
            return $object;
344
        } else {
345
            $this->db->rollback();
346
            return -1;
347
        }
348
    }
349
350
    /**
351
     * Load object in memory from the database
352
     *
353
     * @param int    $id   Id object
354
     * @param string $ref  Ref
355
     * @return int         Return integer <0 if KO, 0 if not found, >0 if OK
356
     */
357
    public function fetch($id, $ref = null)
358
    {
359
        $result = $this->fetchCommon($id, $ref);
360
        if ($result > 0 && !empty($this->table_element_line)) {
361
            $this->fetchLines();
362
        }
363
        return $result;
364
    }
365
366
    /**
367
     * Load object lines in memory from the database
368
     *
369
     * @return int         Return integer <0 if KO, 0 if not found, >0 if OK
370
     */
371
    public function fetchLines()
372
    {
373
        $this->lines = array();
374
375
        $result = $this->fetchLinesCommon();
376
        return $result;
377
    }
378
379
380
    /**
381
     * Load list of objects in memory from the database.
382
     *
383
     * @param  string       $sortorder      Sort Order
384
     * @param  string       $sortfield      Sort field
385
     * @param  int          $limit          limit
386
     * @param  int          $offset         Offset
387
     * @param  string       $filter         Filter as an Universal Search string.
388
     *                                      Example: '((client:=:1) OR ((client:>=:2) AND (client:<=:3))) AND (client:!=:8) AND (nom:like:'a%')'
389
     * @param  string       $filtermode     No more used
390
     * @return array|int                    int <0 if KO, array of pages if OK
391
     */
392
    public function fetchAll($sortorder = '', $sortfield = '', $limit = 0, $offset = 0, $filter = '', $filtermode = 'AND')
393
    {
394
        dol_syslog(__METHOD__, LOG_DEBUG);
395
396
        $records = array();
397
398
        $sql = 'SELECT ';
399
        $sql .= $this->getFieldList('t');
400
        $sql .= ' FROM ' . MAIN_DB_PREFIX . $this->table_element . ' as t';
401
        if (isset($this->ismultientitymanaged) && $this->ismultientitymanaged == 1) {
402
            $sql .= ' WHERE t.entity IN (' . getEntity($this->element) . ')';
403
        } else {
404
            $sql .= ' WHERE 1 = 1';
405
        }
406
407
        // Manage filter
408
        $errormessage = '';
409
        $sql .= forgeSQLFromUniversalSearchCriteria($filter, $errormessage);
410
        if ($errormessage) {
411
            $this->errors[] = $errormessage;
412
            dol_syslog(__METHOD__ . ' ' . implode(',', $this->errors), LOG_ERR);
413
            return -1;
414
        }
415
416
        if (!empty($sortfield)) {
417
            $sql .= $this->db->order($sortfield, $sortorder);
418
        }
419
        if (!empty($limit)) {
420
            $sql .= ' ' . $this->db->plimit($limit, $offset);
421
        }
422
423
        $resql = $this->db->query($sql);
424
        if ($resql) {
425
            $num = $this->db->num_rows($resql);
426
            $i = 0;
427
            while ($i < ($limit ? min($limit, $num) : $num)) {
428
                $obj = $this->db->fetch_object($resql);
429
430
                $record = new self($this->db);
431
                $record->setVarsFromFetchObj($obj);
432
433
                $records[$record->id] = $record;
434
435
                $i++;
436
            }
437
            $this->db->free($resql);
438
439
            return $records;
440
        } else {
441
            $this->errors[] = 'Error ' . $this->db->lasterror();
442
            dol_syslog(__METHOD__ . ' ' . implode(',', $this->errors), LOG_ERR);
443
444
            return -1;
445
        }
446
    }
447
448
    /**
449
     * Update object into database
450
     *
451
     * @param  User $user      User that modifies
452
     * @param  int  $notrigger 0=launch triggers after, 1=disable triggers
453
     * @return int             Return integer <0 if KO, >0 if OK
454
     */
455
    public function update(User $user, $notrigger = 0)
456
    {
457
        return $this->updateCommon($user, $notrigger);
458
    }
459
460
    /**
461
     * Delete object in database
462
     *
463
     * @param User  $user       User that deletes
464
     * @param int   $notrigger  0=launch triggers after, 1=disable triggers
465
     * @return int              Return integer <0 if KO, >0 if OK
466
     */
467
    public function delete(User $user, $notrigger = 0)
468
    {
469
        return $this->deleteCommon($user, $notrigger);
470
        //return $this->deleteCommon($user, $notrigger, 1);
471
    }
472
473
    /**
474
     *  Delete a line of object in database
475
     *
476
     *  @param  User    $user       User that delete
477
     *  @param  int     $idline     Id of line to delete
478
     *  @param  int     $notrigger  0=launch triggers after, 1=disable triggers
479
     *  @return int                 >0 if OK, <0 if KO
480
     */
481
    public function deleteLine(User $user, $idline, $notrigger = 0)
482
    {
483
        if ($this->status < 0) {
484
            $this->error = 'ErrorDeleteLineNotAllowedByObjectStatus';
485
            return -2;
486
        }
487
488
        return $this->deleteLineCommon($user, $idline, $notrigger);
489
    }
490
491
492
    /**
493
     *  Validate object
494
     *
495
     *  @param      User    $user           User making status change
496
     *  @param      int     $notrigger      1=Does not execute triggers, 0= execute triggers
497
     *  @return     int                     Return integer <=0 if OK, 0=Nothing done, >0 if KO
498
     */
499
    public function validate($user, $notrigger = 0)
500
    {
501
        global $conf, $langs;
502
503
        require_once constant('DOL_DOCUMENT_ROOT') . '/core/lib/files.lib.php';
504
505
        $error = 0;
506
507
        // Protection
508
        if ($this->status == self::STATUS_VALIDATED) {
509
            dol_syslog(get_class($this) . "::validate action abandoned: already validated", LOG_WARNING);
510
            return 0;
511
        }
512
513
514
515
        $now = dol_now();
516
517
        $this->db->begin();
518
519
        // Define new ref
520
        if (!$error && (preg_match('/^[\(]?PROV/i', $this->ref) || empty($this->ref))) { // empty should not happened, but when it occurs, the test save life
521
            $num = $this->getNextNumRef();
522
        } else {
523
            $num = $this->ref;
524
        }
525
        $this->newref = $num;
526
527
        if (!empty($num)) {
528
            // Validate
529
            $sql = "UPDATE " . MAIN_DB_PREFIX . $this->table_element;
530
            $sql .= " SET ref = '" . $this->db->escape($num) . "',";
531
            $sql .= " status = " . self::STATUS_VALIDATED;
532
            if (!empty($this->fields['date_validation'])) {
533
                $sql .= ", date_validation = '" . $this->db->idate($now) . "'";
534
            }
535
            if (!empty($this->fields['fk_user_valid'])) {
536
                $sql .= ", fk_user_valid = " . ((int) $user->id);
537
            }
538
            $sql .= " WHERE rowid = " . ((int) $this->id);
539
540
            dol_syslog(get_class($this) . "::validate()", LOG_DEBUG);
541
            $resql = $this->db->query($sql);
542
            if (!$resql) {
543
                dol_print_error($this->db);
544
                $this->error = $this->db->lasterror();
545
                $error++;
546
            }
547
548
            if (!$error && !$notrigger) {
549
                // Call trigger
550
                $result = $this->call_trigger('HRM_EVALUATION_VALIDATE', $user);
551
                if ($result < 0) {
552
                    $error++;
553
                }
554
                // End call triggers
555
            }
556
        }
557
558
        if (!$error) {
559
            $this->oldref = $this->ref;
560
561
            // Rename directory if dir was a temporary ref
562
            if (preg_match('/^[\(]?PROV/i', $this->ref)) {
563
                // Now we rename also files into index
564
                $sql = 'UPDATE ' . MAIN_DB_PREFIX . "ecm_files set filename = CONCAT('" . $this->db->escape($this->newref) . "', SUBSTR(filename, " . (strlen($this->ref) + 1) . ")), filepath = 'evaluation/" . $this->db->escape($this->newref) . "'";
565
                $sql .= " WHERE filename LIKE '" . $this->db->escape($this->ref) . "%' AND filepath = 'evaluation/" . $this->db->escape($this->ref) . "' and entity = " . $conf->entity;
566
                $resql = $this->db->query($sql);
567
                if (!$resql) {
568
                    $error++;
569
                    $this->error = $this->db->lasterror();
570
                }
571
                $sql = 'UPDATE ' . MAIN_DB_PREFIX . "ecm_files set filepath = 'evaluation/" . $this->db->escape($this->newref) . "'";
572
                $sql .= " WHERE filepath = 'evaluation/" . $this->db->escape($this->ref) . "' and entity = " . $conf->entity;
573
                $resql = $this->db->query($sql);
574
                if (!$resql) {
575
                    $error++;
576
                    $this->error = $this->db->lasterror();
577
                }
578
579
                // We rename directory ($this->ref = old ref, $num = new ref) in order not to lose the attachments
580
                $oldref = dol_sanitizeFileName($this->ref);
581
                $newref = dol_sanitizeFileName($num);
582
                $dirsource = $conf->hrm->dir_output . '/evaluation/' . $oldref;
583
                $dirdest = $conf->hrm->dir_output . '/evaluation/' . $newref;
584
                if (!$error && file_exists($dirsource)) {
585
                    dol_syslog(get_class($this) . "::validate() rename dir " . $dirsource . " into " . $dirdest);
586
587
                    if (@rename($dirsource, $dirdest)) {
588
                        dol_syslog("Rename ok");
589
                        // Rename docs starting with $oldref with $newref
590
                        $listoffiles = dol_dir_list($conf->hrm->dir_output . '/evaluation/' . $newref, 'files', 1, '^' . preg_quote($oldref, '/'));
591
                        foreach ($listoffiles as $fileentry) {
592
                            $dirsource = $fileentry['name'];
593
                            $dirdest = preg_replace('/^' . preg_quote($oldref, '/') . '/', $newref, $dirsource);
594
                            $dirsource = $fileentry['path'] . '/' . $dirsource;
595
                            $dirdest = $fileentry['path'] . '/' . $dirdest;
596
                            @rename($dirsource, $dirdest);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition for rename(). This can introduce security issues, and is generally not recommended. ( Ignorable by Annotation )

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

596
                            /** @scrutinizer ignore-unhandled */ @rename($dirsource, $dirdest);

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
597
                        }
598
                    }
599
                }
600
            }
601
        }
602
603
        // Set new ref and current status
604
        if (!$error) {
605
            $this->ref = $num;
606
            $this->status = self::STATUS_VALIDATED;
607
        }
608
609
        if (!$error) {
610
            $this->db->commit();
611
            return 1;
612
        } else {
613
            $this->db->rollback();
614
            return -1;
615
        }
616
    }
617
618
    /**
619
     *      Get the last evaluation by date for the user assigned
620
     *
621
     *       @param int $fk_user ID of user we need to get last eval
622
     *       @return Evaluation|null
623
     */
624
    public function getLastEvaluationForUser($fk_user)
625
    {
626
        $sql = "SELECT rowid FROM " . MAIN_DB_PREFIX . "hrm_evaluation ";
627
        $sql .= "WHERE fk_user=" . ((int) $fk_user) . " ";
628
        $sql .= "ORDER BY date_eval DESC ";
629
        $sql .= "LIMIT 1 ";
630
631
        $res = $this->db->query($sql);
632
        if (!$res) {
633
            dol_print_error($this->db);
634
        }
635
636
        $Tab = $this->db->fetch_object($res);
637
638
        if (empty($Tab)) {
639
            return null;
640
        } else {
641
            $evaluation = new Evaluation($this->db);
642
            $evaluation->fetch($Tab->rowid);
643
644
            return $evaluation;
645
        }
646
    }
647
648
649
    /**
650
     *  Set draft status
651
     *
652
     *  @param  User    $user           Object user that modify
653
     *  @param  int     $notrigger      1=Does not execute triggers, 0=Execute triggers
654
     *  @return int                     Return integer <0 if KO, >0 if OK
655
     */
656
    public function setDraft($user, $notrigger = 0)
657
    {
658
        // Protection
659
        if ($this->status <= self::STATUS_DRAFT) {
660
            return 0;
661
        }
662
663
        return $this->setStatusCommon($user, self::STATUS_DRAFT, $notrigger, 'HRM_EVALUATION_UNVALIDATE');
664
    }
665
666
    /**
667
     *  Set cancel status
668
     *
669
     *  @param  User    $user           Object user that modify
670
     *  @param  int     $notrigger      1=Does not execute triggers, 0=Execute triggers
671
     *  @return int                     Return integer <0 if KO, 0=Nothing done, >0 if OK
672
     */
673
    public function cancel($user, $notrigger = 0)
674
    {
675
        // Protection
676
        if ($this->status != self::STATUS_VALIDATED) {
677
            return 0;
678
        }
679
680
        return $this->setStatusCommon($user, self::STATUS_CANCELED, $notrigger, 'HRM_EVALUATION_CANCEL');
681
    }
682
683
    /**
684
     *  Set back to validated status
685
     *
686
     *  @param  User    $user           Object user that modify
687
     *  @param  int     $notrigger      1=Does not execute triggers, 0=Execute triggers
688
     *  @return int                     Return integer <0 if KO, 0=Nothing done, >0 if OK
689
     */
690
    public function reopen($user, $notrigger = 0)
691
    {
692
        // Protection
693
        if ($this->status != self::STATUS_CANCELED) {
694
            return 0;
695
        }
696
697
        return $this->setStatusCommon($user, self::STATUS_VALIDATED, $notrigger, 'HRM_EVALUATION_REOPEN');
698
    }
699
700
    /**
701
     *  Return a link to the object card (with optionally the picto)
702
     *
703
     *  @param  int     $withpicto                  Include picto in link (0=No picto, 1=Include picto into link, 2=Only picto)
704
     *  @param  string  $option                     On what the link point to ('nolink', ...)
705
     *  @param  int     $notooltip                  1=Disable tooltip
706
     *  @param  string  $morecss                    Add more css on link
707
     *  @param  int     $save_lastsearch_value      -1=Auto, 0=No save of lastsearch_values when clicking, 1=Save lastsearch_values whenclicking
708
     *  @return string                              String with URL
709
     */
710
    public function getNomUrl($withpicto = 0, $option = '', $notooltip = 0, $morecss = '', $save_lastsearch_value = -1)
711
    {
712
        global $conf, $langs, $hookmanager;
713
714
        if (!empty($conf->dol_no_mouse_hover)) {
715
            $notooltip = 1; // Force disable tooltips
716
        }
717
718
        $result = '';
719
720
        $label = img_picto('', $this->picto) . ' <u>' . $langs->trans("Evaluation") . '</u>';
721
        if (isset($this->status)) {
722
            $label .= ' ' . $this->getLibStatut(5);
723
        }
724
        $label .= '<br>';
725
        $label .= '<b>' . $langs->trans('Ref') . ':</b> ' . $this->ref;
726
727
        $url = dol_buildpath('/hrm/evaluation_card.php', 1) . '?id=' . $this->id;
728
729
        if ($option != 'nolink') {
730
            // Add param to save lastsearch_values or not
731
            $add_save_lastsearch_values = ($save_lastsearch_value == 1 ? 1 : 0);
732
            if ($save_lastsearch_value == -1 && isset($_SERVER["PHP_SELF"]) && preg_match('/list\.php/', $_SERVER["PHP_SELF"])) {
733
                $add_save_lastsearch_values = 1;
734
            }
735
            if ($add_save_lastsearch_values) {
736
                $url .= '&save_lastsearch_values=1';
737
            }
738
        }
739
740
        $linkclose = '';
741
        if (empty($notooltip)) {
742
            if (getDolGlobalString('MAIN_OPTIMIZEFORTEXTBROWSER')) {
743
                $label = $langs->trans("ShowEvaluation");
744
                $linkclose .= ' alt="' . dol_escape_htmltag($label, 1) . '"';
745
            }
746
            $linkclose .= ' title="' . dol_escape_htmltag($label, 1) . '"';
747
            $linkclose .= ' class="classfortooltip' . ($morecss ? ' ' . $morecss : '') . '"';
748
        } else {
749
            $linkclose = ($morecss ? ' class="' . $morecss . '"' : '');
750
        }
751
752
        if ($option == 'nolink') {
753
            $linkstart = '<span';
754
        } else {
755
            $linkstart = '<a href="' . $url . '"';
756
        }
757
        $linkstart .= $linkclose . '>';
758
        if ($option == 'nolink') {
759
            $linkend = '</span>';
760
        } else {
761
            $linkend = '</a>';
762
        }
763
764
        $result .= $linkstart;
765
766
        if (empty($this->showphoto_on_popup)) {
767
            if ($withpicto) {
768
                $result .= img_object(($notooltip ? '' : $label), ($this->picto ? $this->picto : 'generic'), ($notooltip ? (($withpicto != 2) ? 'class="paddingright"' : '') : 'class="' . (($withpicto != 2) ? 'paddingright ' : '') . 'classfortooltip"'), 0, 0, $notooltip ? 0 : 1);
769
            }
770
        } else {
771
            if ($withpicto) {
772
                require_once constant('DOL_DOCUMENT_ROOT') . '/core/lib/files.lib.php';
773
774
                list($class, $module) = explode('@', $this->picto);
775
                $upload_dir = $conf->$module->multidir_output[$conf->entity] . "/$class/" . dol_sanitizeFileName($this->ref);
776
                $filearray = dol_dir_list($upload_dir, "files");
777
                $filename = $filearray[0]['name'];
778
                if (!empty($filename)) {
779
                    $pospoint = strpos($filearray[0]['name'], '.');
780
781
                    $pathtophoto = $class . '/' . $this->ref . '/thumbs/' . substr($filename, 0, $pospoint) . '_mini' . substr($filename, $pospoint);
782
                    if (!getDolGlobalString(strtoupper($module . '_' . $class) . '_FORMATLISTPHOTOSASUSERS')) {
783
                        $result .= '<div class="floatleft inline-block valignmiddle divphotoref"><div class="photoref"><img class="photo' . $module . '" alt="No photo" border="0" src="' . constant('BASE_URL') . '/viewimage.php?modulepart=' . $module . '&entity=' . $conf->entity . '&file=' . urlencode($pathtophoto) . '"></div></div>';
784
                    } else {
785
                        $result .= '<div class="floatleft inline-block valignmiddle divphotoref"><img class="photouserphoto userphoto" alt="No photo" border="0" src="' . constant('BASE_URL') . '/viewimage.php?modulepart=' . $module . '&entity=' . $conf->entity . '&file=' . urlencode($pathtophoto) . '"></div>';
786
                    }
787
788
                    $result .= '</div>';
789
                } else {
790
                    $result .= img_object(($notooltip ? '' : $label), ($this->picto ? $this->picto : 'generic'), ($notooltip ? (($withpicto != 2) ? 'class="paddingright"' : '') : 'class="' . (($withpicto != 2) ? 'paddingright ' : '') . 'classfortooltip"'), 0, 0, $notooltip ? 0 : 1);
791
                }
792
            }
793
        }
794
795
        if ($withpicto != 2) {
796
            $result .= $this->ref;
797
        }
798
799
        $result .= $linkend;
800
        //if ($withpicto != 2) $result.=(($addlabel && $this->label) ? $sep . dol_trunc($this->label, ($addlabel > 1 ? $addlabel : 0)) : '');
801
802
        global $action, $hookmanager;
803
        $hookmanager->initHooks(array('evaluationdao'));
804
        $parameters = array('id' => $this->id, 'getnomurl' => &$result);
805
        $reshook = $hookmanager->executeHooks('getNomUrl', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks
806
        if ($reshook > 0) {
807
            $result = $hookmanager->resPrint;
808
        } else {
809
            $result .= $hookmanager->resPrint;
810
        }
811
812
        return $result;
813
    }
814
815
    /**
816
     *  Return the label of the status
817
     *
818
     *  @param  int     $mode          0=long label, 1=short label, 2=Picto + short label, 3=Picto, 4=Picto + long label, 5=Short label + Picto, 6=Long label + Picto
819
     *  @return string                 Label of status
820
     */
821
    public function getLibStatut($mode = 0)
822
    {
823
        return $this->LibStatut($this->status, $mode);
824
    }
825
826
	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
827
    /**
828
     *  Return the status
829
     *
830
     *  @param  int     $status        Id status
831
     *  @param  int     $mode          0=long label, 1=short label, 2=Picto + short label, 3=Picto, 4=Picto + long label, 5=Short label + Picto, 6=Long label + Picto
832
     *  @return string                 Label of status
833
     */
834
    public function LibStatut($status, $mode = 0)
835
    {
836
		// phpcs:enable
837
        if (empty($this->labelStatus) || empty($this->labelStatusShort)) {
838
            global $langs;
839
            //$langs->load("hrm");
840
            $this->labelStatus[self::STATUS_DRAFT] = $langs->transnoentitiesnoconv('Draft');
841
            $this->labelStatus[self::STATUS_VALIDATED] = $langs->transnoentitiesnoconv('Validated');
842
            $this->labelStatus[self::STATUS_CLOSED] = $langs->transnoentitiesnoconv('Closed');
843
            $this->labelStatusShort[self::STATUS_DRAFT] = $langs->transnoentitiesnoconv('Draft');
844
            $this->labelStatusShort[self::STATUS_VALIDATED] = $langs->transnoentitiesnoconv('Validated');
845
            $this->labelStatusShort[self::STATUS_CLOSED] = $langs->transnoentitiesnoconv('Closed');
846
        }
847
848
        $statusType = 'status' . $status;
849
        //if ($status == self::STATUS_VALIDATED) $statusType = 'status1';
850
        if ($status == self::STATUS_CANCELED) {
851
            $statusType = 'status6';
852
        }
853
854
        return dolGetStatus($this->labelStatus[$status], $this->labelStatusShort[$status], '', $statusType, $mode);
855
    }
856
857
    /**
858
     *  Load the info information in the object
859
     *
860
     *  @param  int     $id       Id of object
861
     *  @return void
862
     */
863
    public function info($id)
864
    {
865
        $sql = 'SELECT rowid, date_creation as datec, tms as datem,';
866
        $sql .= ' fk_user_creat, fk_user_modif';
867
        $sql .= ' FROM ' . MAIN_DB_PREFIX . $this->table_element . ' as t';
868
        $sql .= ' WHERE t.rowid = ' . ((int) $id);
869
        $result = $this->db->query($sql);
870
        if ($result) {
871
            if ($this->db->num_rows($result)) {
872
                $obj = $this->db->fetch_object($result);
873
874
                $this->id = $obj->rowid;
875
876
                $this->user_creation_id = $obj->fk_user_creat;
877
                $this->user_modification_id = $obj->fk_user_modif;
878
                $this->date_creation     = $this->db->jdate($obj->datec);
879
                $this->date_modification = empty($obj->datem) ? '' : $this->db->jdate($obj->datem);
880
            }
881
882
            $this->db->free($result);
883
        } else {
884
            dol_print_error($this->db);
885
        }
886
    }
887
888
    /**
889
     * Initialise object with example values
890
     * Id must be 0 if object instance is a specimen
891
     *
892
     * @return int
893
     */
894
    public function initAsSpecimen()
895
    {
896
        // Set here init that are not commonf fields
897
        // $this->property1 = ...
898
        // $this->property2 = ...
899
900
        return $this->initAsSpecimenCommon();
901
    }
902
903
    /**
904
     *  Create an array of lines
905
     *
906
     *  @return array|int       array of lines if OK, <0 if KO
907
     */
908
    public function getLinesArray()
909
    {
910
        $this->lines = array();
911
912
        $objectline = new EvaluationLine($this->db);
913
        $result = $objectline->fetchAll('ASC', '', 0, 0, '(fk_evaluation:=:' . ((int) $this->id) . ')');
914
915
        if (is_numeric($result)) {
916
            $this->setErrorsFromObject($objectline);
917
            return $result;
918
        } else {
919
            $this->lines = $result;
920
            return $this->lines;
921
        }
922
    }
923
924
    /**
925
     *  Returns the reference to the following non used object depending on the active numbering module.
926
     *
927
     *  @return string              Object free reference
928
     */
929
    public function getNextNumRef()
930
    {
931
        global $langs, $conf;
932
        $langs->load("hrm");
933
934
        if (!getDolGlobalString('HRMTEST_EVALUATION_ADDON')) {
935
            $conf->global->HRMTEST_EVALUATION_ADDON = 'mod_evaluation_standard';
936
        }
937
938
        if (getDolGlobalString('HRMTEST_EVALUATION_ADDON')) {
939
            $mybool = false;
940
941
            $file = getDolGlobalString('HRMTEST_EVALUATION_ADDON') . ".php";
942
            $classname = getDolGlobalString('HRMTEST_EVALUATION_ADDON');
943
944
            // Include file with class
945
            $dirmodels = array_merge(array('/'), (array) $conf->modules_parts['models']);
946
            foreach ($dirmodels as $reldir) {
947
                $dir = dol_buildpath($reldir . "core/modules/hrm/");
948
949
                // Load file with numbering class (if found)
950
                $mybool = ((bool) @include_once $dir . $file) || $mybool;
951
            }
952
953
            if ($mybool === false) {
954
                dol_print_error(null, "Failed to include file " . $file);
955
                return '';
956
            }
957
958
            if (class_exists($classname)) {
959
                $obj = new $classname();
960
                $numref = $obj->getNextValue($this);
961
962
                if ($numref != '' && $numref != '-1') {
963
                    return $numref;
964
                } else {
965
                    $this->error = $obj->error;
966
                    //dol_print_error($this->db,get_class($this)."::getNextNumRef ".$obj->error);
967
                    return "";
968
                }
969
            } else {
970
                print $langs->trans("Error") . " " . $langs->trans("ClassNotFound") . ' ' . $classname;
971
                return "";
972
            }
973
        } else {
974
            print $langs->trans("ErrorNumberingModuleNotSetup", $this->element);
975
            return "";
976
        }
977
    }
978
979
    /**
980
     *  Create a document onto disk according to template module.
981
     *
982
     *  @param      string      $modele         Force template to use ('' to not force)
983
     *  @param      Translate   $outputlangs    object lang a utiliser pour traduction
984
     *  @param      int         $hidedetails    Hide details of lines
985
     *  @param      int         $hidedesc       Hide description
986
     *  @param      int         $hideref        Hide ref
987
     *  @param      null|array  $moreparams     Array to provide more information
988
     *  @return     int                         0 if KO, 1 if OK
989
     */
990
    public function generateDocument($modele, $outputlangs, $hidedetails = 0, $hidedesc = 0, $hideref = 0, $moreparams = null)
991
    {
992
        global $conf, $langs;
993
994
        $result = 0;
995
996
        $langs->load("hrm");
997
998
        if (!dol_strlen($modele)) {
999
            $modele = 'standard';
1000
1001
            if (!empty($this->model_pdf)) {
1002
                $modele = $this->model_pdf;
1003
            } elseif (getDolGlobalString('EVALUATION_ADDON_PDF')) {
1004
                $modele = getDolGlobalString('EVALUATION_ADDON_PDF');
1005
            }
1006
        }
1007
1008
        $modelpath = "core/modules/hrm/doc/";
1009
1010
        if (!empty($modele)) {
1011
            $result = $this->commonGenerateDocument($modelpath, $modele, $outputlangs, $hidedetails, $hidedesc, $hideref, $moreparams);
1012
        }
1013
1014
        return $result;
1015
    }
1016
1017
    /**
1018
     *  Return clicable link of object (with eventually picto)
1019
     *
1020
     *  @param      string      $option                 Where point the link (0=> main card, 1,2 => shipment, 'nolink'=>No link)
1021
     *  @param      array       $arraydata              Array of data
1022
     *  @return     string                              HTML Code for Kanban thumb.
1023
     */
1024
    public function getKanbanView($option = '', $arraydata = null)
1025
    {
1026
        global $selected, $langs;
1027
1028
        $selected = (empty($arraydata['selected']) ? 0 : $arraydata['selected']);
1029
1030
        $return = '<div class="box-flex-item box-flex-grow-zero">';
1031
        $return .= '<div class="info-box info-box-sm">';
1032
        $return .= '<span class="info-box-icon bg-infobox-action">';
1033
        $return .= img_picto('', $this->picto);
1034
        $return .= '</span>';
1035
        $return .= '<div class="info-box-content">';
1036
        $return .= '<span class="info-box-ref inline-block tdoverflowmax150 valignmiddle">' . (method_exists($this, 'getNomUrl') ? $this->getNomUrl(1) : $this->ref) . '</span>';
1037
        $return .= '<input class="fright" id="cb' . $this->id . '" class="flat checkforselect" type="checkbox" name="toselect[]" value="' . $this->id . '"' . ($selected ? ' checked="checked"' : '') . '>';
1038
        if (!empty($arraydata['user'])) {
1039
            $return .= '<br><span class="info-box-label ">' . $arraydata['user'] . '</span>';
1040
        }
1041
        if (!empty($arraydata['job'])) {
1042
            $return .= '<br><span class="info-box-label ">' . $arraydata['job'] . '</span>';
1043
        }
1044
        if (method_exists($this, 'getLibStatut')) {
1045
            $return .= '<br><div class="info-box-status">' . $this->getLibStatut(3) . '</div>';
1046
        }
1047
        $return .= '</div>';
1048
        $return .= '</div>';
1049
        $return .= '</div>';
1050
        return $return;
1051
    }
1052
}
1053