Passed
Push — EXTRACT_CLASSES ( ae6b5c...83d77a )
by Rafael
60:14 queued 23:58
created

Target::validate()   F

Complexity

Conditions 22
Paths 2801

Size

Total Lines 114
Code Lines 71

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 22
eloc 71
nc 2801
nop 2
dl 0
loc 114
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) 2024       Frédéric France             <[email protected]>
5
 * Copyright (C) 2024		MDW							<[email protected]>
6
 * Copyright (C) 2024       Rafael San José             <[email protected]>
7
 *
8
 * This program is free software; you can redistribute it and/or modify
9
 * it under the terms of the GNU General Public License as published by
10
 * the Free Software Foundation; either version 3 of the License, or
11
 * (at your option) any later version.
12
 *
13
 * This program is distributed in the hope that it will be useful,
14
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16
 * GNU General Public License for more details.
17
 *
18
 * You should have received a copy of the GNU General Public License
19
 * along with this program. If not, see <https://www.gnu.org/licenses/>.
20
 */
21
22
namespace Dolibarr\Code\WebHook\Classes;
23
24
use Dolibarr\Core\Base\CommonObject;
25
26
/**
27
 * \file        htdocs/webhook/class/target.class.php
28
 * \ingroup     webhook
29
 * \brief       This file is a CRUD class file for Target (Create/Read/Update/Delete)
30
 */
31
32
// Put here all includes required by your class file
33
//use Dolibarr\Code\Societe\Classes\Societe;
34
//require_once constant('DOL_DOCUMENT_ROOT') . '/product/class/product.class.php';
35
36
/**
37
 * Class for Target
38
 */
39
class Target extends CommonObject
40
{
41
    /**
42
     * @var string ID of module.
43
     */
44
    public $module = 'webhook';
45
46
    /**
47
     * @var string ID to identify managed object.
48
     */
49
    public $element = 'target';
50
51
    /**
52
     * @var string Name of table without prefix where object is stored. This is also the key used for extrafields management.
53
     */
54
    public $table_element = 'webhook_target';
55
56
    /**
57
     * @var string String with name of icon for target. Must be the part after the 'object_' into object_target.png
58
     */
59
    public $picto = 'webhook';
60
61
62
    const STATUS_DRAFT = 0;
63
    const STATUS_VALIDATED = 1;
64
    const STATUS_CANCELED = 9;
65
66
67
    /**
68
     *  'type' field format ('integer', 'integer:ObjectClass:PathToClass[:AddCreateButtonOrNot[:Filter[:Sortfield]]]', 'sellist:TableName:LabelFieldName[:KeyFieldName[:KeyFieldParent[:Filter[:Sortfield]]]]', 'varchar(x)', 'double(24,8)', 'real', 'price', 'text', 'text:none', 'html', 'date', 'datetime', 'timestamp', 'duration', 'mail', 'phone', 'url', 'password')
69
     *         Note: Filter can be a string like "(t.ref:like:'SO-%') or (t.date_creation:<:'20160101') or (t.nature:is:NULL)"
70
     *  'label' the translation key.
71
     *  'picto' is code of a picto to show before value in forms
72
     *  'enabled' is a condition when the field must be managed (Example: 1 or '$conf->global->MY_SETUP_PARAM' or 'isModEnabled("multicurrency")' ...)
73
     *  'position' is the sort order of field.
74
     *  'notnull' is set to 1 if not null in database. Set to -1 if we must set data to null if empty ('' or 0).
75
     *  '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)
76
     *  'noteditable' says if field is not editable (1 or 0)
77
     *  '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.
78
     *  'index' if we want an index in database.
79
     *  'foreignkey'=>'tablename.field' if the field is a foreign key (it is recommended to name the field fk_...).
80
     *  'searchall' is 1 if we want to search in this field when making a search from the quick search button.
81
     *  'isameasure' must be set to 1 or 2 if field can be used for measure. Field type must be summable like integer or double(24,8). Use 1 in most cases, or 2 if you don't want to see the column total into list (for example for percentage)
82
     *  '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'
83
     *  'help' is a 'TranslationString' to use to show a tooltip on field. You can also use 'TranslationString:keyfortooltiponlick' for a tooltip on click.
84
     *  'showoncombobox' if value of the field must be visible into the label of the combobox that list record
85
     *  '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.
86
     *  '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'
87
     *  'autofocusoncreate' to have field having the focus on a create form. Only 1 field should have this property set to 1.
88
     *  'comment' is not used. You can store here any text of your choice. It is not used by application.
89
     *  'validate' is 1 if need to validate with $this->validateField()
90
     *  'copytoclipboard' is 1 or 2 to allow to add a picto to copy value into clipboard (1=picto after label, 2=picto after value)
91
     *
92
     *  Note: To have value dynamic, you can set value to 0 in definition and edit the value on the fly into the constructor.
93
     */
94
95
    // BEGIN MODULEBUILDER PROPERTIES
96
    /**
97
     * @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...
98
     */
99
    public $fields = array(
100
        'rowid' => array('type' => 'integer', 'label' => 'TechnicalID', 'enabled' => 1, 'position' => 1, 'notnull' => 1, 'visible' => 0, 'noteditable' => 1, 'index' => 1, 'css' => 'left', 'comment' => "Id"),
101
        'ref' => array('type' => 'varchar(128)', 'label' => 'Ref', 'enabled' => 1, 'position' => 20, 'notnull' => 1, 'visible' => 4, 'noteditable' => 1, 'index' => 1, 'searchall' => 1, 'validate' => 1, 'comment' => "Reference of object"),
102
        'label' => array('type' => 'varchar(255)', 'label' => 'Label', 'enabled' => 1, 'position' => 30, 'notnull' => 0, 'visible' => 1, 'searchall' => 1, 'css' => 'minwidth300', 'cssview' => 'wordbreak', 'csslist' => 'tdoverflowmax150', 'showoncombobox' => 2, 'validate' => 1,),
103
        'trigger_codes' => array('type' => 'text', 'label' => 'TriggerCodes', 'enabled' => 1, 'position' => 50, 'notnull' => 1, 'visible' => 1, 'help' => "TriggerCodeInfo", 'tdcss' => 'titlefieldmiddle', 'csslist' => 'tdoverflowmax200', 'css' => 'minwidth400', 'arrayofkeyval' => array('defined_in_constructor' => 'defined_from_c_action_trigger'), 'multiinput' => 1,),
104
        'url' => array('type' => 'url', 'label' => 'Url', 'enabled' => 1, 'position' => 55, 'notnull' => 1, 'visible' => 1,),
105
        'description' => array('type' => 'text', 'label' => 'Description', 'enabled' => 1, 'position' => 60, 'notnull' => 0, 'visible' => 3, 'validate' => 1,),
106
        'note_public' => array('type' => 'html', 'label' => 'NotePublic', 'enabled' => 1, 'position' => 61, 'notnull' => 0, 'visible' => 0, 'cssview' => 'wordbreak', 'validate' => 1,),
107
        'note_private' => array('type' => 'html', 'label' => 'NotePrivate', 'enabled' => 1, 'position' => 62, 'notnull' => 0, 'visible' => 0, 'cssview' => 'wordbreak', 'validate' => 1,),
108
        'date_creation' => array('type' => 'datetime', 'label' => 'DateCreation', 'enabled' => 1, 'position' => 500, 'notnull' => 1, 'visible' => -2,),
109
        'tms' => array('type' => 'timestamp', 'label' => 'DateModification', 'enabled' => 1, 'position' => 501, 'notnull' => 0, 'visible' => -2,),
110
        'fk_user_creat' => array('type' => 'integer:User:user/class/user.class.php', 'label' => 'UserAuthor', 'enabled' => 1, 'position' => 510, 'notnull' => 1, 'visible' => -2, 'foreignkey' => 'user.rowid',),
111
        'fk_user_modif' => array('type' => 'integer:User:user/class/user.class.php', 'label' => 'UserModif', 'enabled' => 1, 'position' => 511, 'notnull' => -1, 'visible' => -2,),
112
        'import_key' => array('type' => 'varchar(14)', 'label' => 'ImportId', 'enabled' => 1, 'position' => 1000, 'notnull' => -1, 'visible' => -2,),
113
        'status' => array('type' => 'integer', 'label' => 'Status', 'enabled' => 1, 'position' => 2000, 'notnull' => 1, 'default' => '1', 'visible' => 1, 'index' => 1, 'arrayofkeyval' => array('0' => 'Disabled', '1' => 'Enabled'), 'validate' => 1,),
114
    );
115
    public $rowid;
116
    public $ref;
117
    public $label;
118
    public $description;
119
    public $note_public;
120
    public $note_private;
121
    public $date_creation;
122
    public $fk_user_creat;
123
    public $fk_user_modif;
124
    public $import_key;
125
    public $status;
126
    public $url;
127
    /**
128
     * @var string  List of trigger codes separated by a comma. Example: 'BILL_VALIDATE,PROPAL_DELETE,...'
129
     */
130
    public $trigger_codes;
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 = 'webhook_targetline';
140
141
    // /**
142
    //  * @var string    Field with ID of parent key if this object has a parent
143
    //  */
144
    // public $fk_element = 'fk_target';
145
146
    // /**
147
    //  * @var string    Name of subtable class that manage subtable lines
148
    //  */
149
    // public $class_element_line = 'Targetline';
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 array    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('webhook_targetdet');
162
163
    // /**
164
    //  * @var TargetLine[]     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\WebHook\Classes\DoliDB was not found. Did you mean DoliDB? If so, make sure to prefix the type with \.
Loading history...
176
    {
177
        global $langs;
178
179
        $this->db = $db;
180
181
        $this->ismultientitymanaged = 0;
182
        $this->isextrafieldmanaged = 0;
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
        // Unset fields that are disabled
192
        foreach ($this->fields as $key => $val) {
193
            if (isset($val['enabled']) && empty($val['enabled'])) {
194
                unset($this->fields[$key]);
195
            }
196
        }
197
198
        // Translate some data of arrayofkeyval
199
        if (is_object($langs)) {
200
            foreach ($this->fields as $key => $val) {
201
                if (!empty($val['arrayofkeyval']) && is_array($val['arrayofkeyval'])) {
202
                    foreach ($val['arrayofkeyval'] as $key2 => $val2) {
203
                        $this->fields[$key]['arrayofkeyval'][$key2] = $langs->trans($val2);
204
                    }
205
                }
206
            }
207
        }
208
    }
209
210
    /**
211
     * Init the list of available triggers;
212
     *
213
     * @return int             Return integer <0 if KO, >0 if OK
214
     */
215
    public function initListOfTriggers()
216
    {
217
        $entitytoicon = array(
218
            'societe'           => 'company',
219
            'facture'           => 'bill',
220
            'commande'          => 'order',
221
            'order_supplier'    => 'supplier_order',
222
            'proposal_supplier' => 'supplier_proposal',
223
            'invoice_supplier'  => 'supplier_invoice',
224
            'facturerec'        => 'bill',
225
            'ficheinter'        => 'intervention',
226
            'shipping'          => 'shipment',
227
            'contrat'           => 'contract',
228
            'recruitment'       => 'recruitmentjobposition',
229
        );
230
        // Define the array $arrayofkeyval for $this->fields["trigger_codes"]
231
        if (!empty($this->fields["trigger_codes"]['arrayofkeyval']) && is_array($this->fields["trigger_codes"]['arrayofkeyval']) && !empty($this->fields["trigger_codes"]["multiinput"])) {
232
            $sql = "SELECT c.code, c.label, c.elementtype FROM " . MAIN_DB_PREFIX . "c_action_trigger as c ORDER BY c.rang ASC";
233
            $resql = $this->db->query($sql);
234
            if ($resql) {
235
                $num = $this->db->num_rows($resql);
236
                $i = 0;
237
                $arraytrigger = array();
238
                while ($i < $num) {
239
                    $obj = $this->db->fetch_object($resql);
240
                    $elementtype = (!empty($entitytoicon[$obj->elementtype]) ? $entitytoicon[$obj->elementtype] : $obj->elementtype);
241
                    $arraytrigger[$obj->code] = img_object("", $elementtype) . ' ' . $obj->label . ' (' . $obj->code . ')';
242
                    $i++;
243
                }
244
                $this->fields["trigger_codes"]['arrayofkeyval'] = $arraytrigger;
245
            } else {
246
                $this->errors[] = 'Error ' . $this->db->lasterror();
247
                dol_syslog(__METHOD__ . ' ' . implode(',', $this->errors), LOG_ERR);
248
            }
249
        }
250
251
        return 1;
252
    }
253
254
    /**
255
     * Create object into database
256
     *
257
     * @param  User $user      User that creates
258
     * @param  int  $notrigger 0=launch triggers after, 1=disable triggers
259
     * @return int             Return integer <0 if KO, ID of created object if OK
260
     */
261
    public function create(User $user, $notrigger = 0)
262
    {
263
        $resultcreate = $this->createCommon($user, $notrigger);
264
        $this->ref = (string) $this->id;
265
266
        if ($resultcreate <= 0) {
267
            return $resultcreate;
268
        }
269
270
        return $this->id;
271
    }
272
273
    /**
274
     * Clone an object into another one
275
     *
276
     * @param   User    $user       User that creates
277
     * @param   int     $fromid     Id of object to clone
278
     * @return  mixed               New object created, <0 if KO
279
     */
280
    public function createFromClone(User $user, $fromid)
281
    {
282
        global $langs, $extrafields;
283
        $error = 0;
284
285
        dol_syslog(__METHOD__, LOG_DEBUG);
286
287
        $object = new self($this->db);
288
289
        $this->db->begin();
290
291
        // Load source object
292
        $result = $object->fetchCommon($fromid);
293
        if ($result > 0 && !empty($object->table_element_line)) {
294
            $object->fetchLines();
295
        }
296
297
        // get lines so they will be clone
298
        //foreach($this->lines as $line)
299
        //  $line->fetch_optionals();
300
301
        // Reset some properties
302
        unset($object->id);
303
        unset($object->fk_user_creat);
304
        unset($object->import_key);
305
306
        // Clear fields
307
        if (property_exists($object, 'ref')) {
308
            $object->ref = empty($this->fields['ref']['default']) ? "Copy_Of_" . $object->ref : $this->fields['ref']['default'];
309
        }
310
        if (property_exists($object, 'label')) {
311
            $object->label = empty($this->fields['label']['default']) ? $langs->trans("CopyOf") . " " . $object->label : $this->fields['label']['default'];
312
        }
313
        if (property_exists($object, 'status')) {
314
            $object->status = self::STATUS_DRAFT;
315
        }
316
        if (property_exists($object, 'date_creation')) {
317
            $object->date_creation = dol_now();
318
        }
319
        if (property_exists($object, 'date_modification')) {
320
            $object->date_modification = null;
321
        }
322
        // ...
323
        // Clear extrafields that are unique
324
        if (is_array($object->array_options) && count($object->array_options) > 0) {
325
            $extrafields->fetch_name_optionals_label($this->table_element);
326
            foreach ($object->array_options as $key => $option) {
327
                $shortkey = preg_replace('/options_/', '', $key);
328
                if (!empty($extrafields->attributes[$this->table_element]['unique'][$shortkey])) {
329
                    //var_dump($key); var_dump($clonedObj->array_options[$key]); exit;
330
                    unset($object->array_options[$key]);
331
                }
332
            }
333
        }
334
335
        // Create clone
336
        $object->context['createfromclone'] = 'createfromclone';
337
        $result = $object->createCommon($user);
338
        if ($result < 0) {
339
            $error++;
340
            $this->setErrorsFromObject($object);
341
        }
342
343
        // if (!$error) {
344
        //  // copy internal contacts
345
        //  if ($this->copy_linked_contact($object, 'internal') < 0) {
346
        //      $error++;
347
        //  }
348
        // }
349
350
        // if (!$error) {
351
        //  // copy external contacts if same company
352
        //  if (!empty($object->socid) && property_exists($this, 'fk_soc') && $this->fk_soc == $object->socid) {
353
        //      if ($this->copy_linked_contact($object, 'external') < 0) {
354
        //          $error++;
355
        //      }
356
        //  }
357
        // }
358
359
        unset($object->context['createfromclone']);
360
361
        // End
362
        if (!$error) {
363
            $this->db->commit();
364
            return $object;
365
        } else {
366
            $this->db->rollback();
367
            return -1;
368
        }
369
    }
370
371
    /**
372
     * Load object in memory from the database
373
     *
374
     * @param int    $id   Id object
375
     * @param string $ref  Ref
376
     * @return int         Return integer <0 if KO, 0 if not found, >0 if OK
377
     */
378
    public function fetch($id, $ref = null)
379
    {
380
        $result = $this->fetchCommon($id, $ref);
381
        if (empty($this->ref)) {
382
            $this->ref = (string) $this->id;
383
        }
384
385
        return $result;
386
    }
387
388
    /**
389
     * Load object lines in memory from the database
390
     *
391
     * @return int         Return integer <0 if KO, 0 if not found, >0 if OK
392
     */
393
    public function fetchLines()
394
    {
395
        $this->lines = array();
396
397
        $result = $this->fetchLinesCommon();
398
        return $result;
399
    }
400
401
402
    /**
403
     * Load list of objects in memory from the database.
404
     *
405
     * @param  string       $sortorder      Sort Order
406
     * @param  string       $sortfield      Sort field
407
     * @param  int          $limit          limit
408
     * @param  int          $offset         Offset
409
     * @param  string       $filter         Filter as an Universal Search string.
410
     *                                      Example: '((client:=:1) OR ((client:>=:2) AND (client:<=:3))) AND (client:!=:8) AND (nom:like:'a%')'
411
     * @param  string       $filtermode     No more used
412
     * @return array|int                    int <0 if KO, array of pages if OK
413
     */
414
    public function fetchAll($sortorder = '', $sortfield = '', $limit = 0, $offset = 0, $filter = '', $filtermode = 'AND')
415
    {
416
        dol_syslog(__METHOD__, LOG_DEBUG);
417
418
        $records = array();
419
420
        $sql = "SELECT ";
421
        $sql .= $this->getFieldList('t');
422
        $sql .= " FROM " . MAIN_DB_PREFIX . $this->table_element . " as t";
423
        if (isset($this->ismultientitymanaged) && $this->ismultientitymanaged == 1) {
424
            $sql .= " WHERE t.entity IN (" . getEntity($this->element) . ")";
425
        } else {
426
            $sql .= " WHERE 1 = 1";
427
        }
428
429
        $errormessage = '';
430
        $sql .= forgeSQLFromUniversalSearchCriteria($filter, $errormessage);
431
        if ($errormessage) {
432
            $this->errors[] = $errormessage;
433
            dol_syslog(__METHOD__ . ' ' . implode(',', $this->errors), LOG_ERR);
434
            return -1;
435
        }
436
437
        if (!empty($sortfield)) {
438
            $sql .= $this->db->order($sortfield, $sortorder);
439
        }
440
        if (!empty($limit)) {
441
            $sql .= $this->db->plimit($limit, $offset);
442
        }
443
444
        $resql = $this->db->query($sql);
445
        if ($resql) {
446
            $num = $this->db->num_rows($resql);
447
            $i = 0;
448
            while ($i < ($limit ? min($limit, $num) : $num)) {
449
                $obj = $this->db->fetch_object($resql);
450
451
                $record = new self($this->db);
452
                $record->setVarsFromFetchObj($obj);
453
454
                $records[$record->id] = $record;
455
456
                $i++;
457
            }
458
            $this->db->free($resql);
459
460
            return $records;
461
        } else {
462
            $this->errors[] = 'Error ' . $this->db->lasterror();
463
            dol_syslog(__METHOD__ . ' ' . implode(',', $this->errors), LOG_ERR);
464
465
            return -1;
466
        }
467
    }
468
469
    /**
470
     * Update object into database
471
     *
472
     * @param  User $user      User that modifies
473
     * @param  int  $notrigger 0=launch triggers after, 1=disable triggers
474
     * @return int             Return integer <0 if KO, >0 if OK
475
     */
476
    public function update(User $user, $notrigger = 0)
477
    {
478
        return $this->updateCommon($user, $notrigger);
479
    }
480
481
    /**
482
     * Delete object in database
483
     *
484
     * @param User  $user       User that deletes
485
     * @param int   $notrigger  0=launch triggers after, 1=disable triggers
486
     * @return int              Return integer <0 if KO, >0 if OK
487
     */
488
    public function delete(User $user, $notrigger = 0)
489
    {
490
        return $this->deleteCommon($user, $notrigger);
491
        //return $this->deleteCommon($user, $notrigger, 1);
492
    }
493
494
    /**
495
     *  Delete a line of object in database
496
     *
497
     *  @param  User    $user       User that delete
498
     *  @param  int     $idline     Id of line to delete
499
     *  @param  int     $notrigger  0=launch triggers after, 1=disable triggers
500
     *  @return int                 >0 if OK, <0 if KO
501
     */
502
    public function deleteLine(User $user, $idline, $notrigger = 0)
503
    {
504
        if ($this->status < 0) {
505
            $this->error = 'ErrorDeleteLineNotAllowedByObjectStatus';
506
            return -2;
507
        }
508
509
        return $this->deleteLineCommon($user, $idline, $notrigger);
510
    }
511
512
513
    /**
514
     *  Validate object
515
     *
516
     *  @param      User    $user           User making status change
517
     *  @param      int     $notrigger      1=Does not execute triggers, 0= execute triggers
518
     *  @return     int                     Return integer <=0 if OK, 0=Nothing done, >0 if KO
519
     */
520
    public function validate($user, $notrigger = 0)
521
    {
522
        global $conf;
523
524
        require_once constant('DOL_DOCUMENT_ROOT') . '/core/lib/files.lib.php';
525
526
        $error = 0;
527
528
        // Protection
529
        if ($this->status == self::STATUS_VALIDATED) {
530
            dol_syslog(get_class($this) . "::validate action abandoned: already validated", LOG_WARNING);
531
            return 0;
532
        }
533
534
        $now = dol_now();
535
536
        $this->db->begin();
537
538
        // Define new ref
539
        if (!$error && (preg_match('/^[\(]?PROV/i', $this->ref) || empty($this->ref))) { // empty should not happened, but when it occurs, the test save life
540
            $num = $this->getNextNumRef();
541
        } else {
542
            $num = $this->ref;
543
        }
544
        $this->newref = $num;
545
546
        if (!empty($num)) {
547
            // Validate
548
            $sql = "UPDATE " . MAIN_DB_PREFIX . $this->table_element;
549
            $sql .= " SET ref = '" . $this->db->escape($num) . "',";
550
            $sql .= " status = " . self::STATUS_VALIDATED;
551
            if (!empty($this->fields['date_validation'])) {
552
                $sql .= ", date_validation = '" . $this->db->idate($now) . "'";
553
            }
554
            if (!empty($this->fields['fk_user_valid'])) {
555
                $sql .= ", fk_user_valid = " . ((int) $user->id);
556
            }
557
            $sql .= " WHERE rowid = " . ((int) $this->id);
558
559
            dol_syslog(get_class($this) . "::validate()", LOG_DEBUG);
560
            $resql = $this->db->query($sql);
561
            if (!$resql) {
562
                dol_print_error($this->db);
563
                $this->error = $this->db->lasterror();
564
                $error++;
565
            }
566
567
            if (!$error && !$notrigger) {
568
                // Call trigger
569
                $result = $this->call_trigger('TARGET_VALIDATE', $user);
570
                if ($result < 0) {
571
                    $error++;
572
                }
573
                // End call triggers
574
            }
575
        }
576
577
        if (!$error) {
578
            $this->oldref = $this->ref;
579
580
            // Rename directory if dir was a temporary ref
581
            if (preg_match('/^[\(]?PROV/i', $this->ref)) {
582
                // Now we rename also files into index
583
                $sql = 'UPDATE ' . MAIN_DB_PREFIX . "ecm_files set filename = CONCAT('" . $this->db->escape($this->newref) . "', SUBSTR(filename, " . (strlen($this->ref) + 1) . ")), filepath = 'target/" . $this->db->escape($this->newref) . "'";
584
                $sql .= " WHERE filename LIKE '" . $this->db->escape($this->ref) . "%' AND filepath = 'target/" . $this->db->escape($this->ref) . "' and entity = " . $conf->entity;
585
                $resql = $this->db->query($sql);
586
                if (!$resql) {
587
                    $error++;
588
                    $this->error = $this->db->lasterror();
589
                }
590
                $sql = 'UPDATE ' . MAIN_DB_PREFIX . "ecm_files set filepath = 'target/" . $this->db->escape($this->newref) . "'";
591
                $sql .= " WHERE filepath = 'target/" . $this->db->escape($this->ref) . "' and entity = " . ((int) $conf->entity);
592
                $resql = $this->db->query($sql);
593
                if (!$resql) {
594
                    $error++;
595
                    $this->error = $this->db->lasterror();
596
                }
597
598
                // We rename directory ($this->ref = old ref, $num = new ref) in order not to lose the attachments
599
                $oldref = dol_sanitizeFileName($this->ref);
600
                $newref = dol_sanitizeFileName($num);
601
                $dirsource = $conf->webhook->dir_output . '/target/' . $oldref;
602
                $dirdest = $conf->webhook->dir_output . '/target/' . $newref;
603
                if (!$error && file_exists($dirsource)) {
604
                    dol_syslog(get_class($this) . "::validate() rename dir " . $dirsource . " into " . $dirdest);
605
606
                    if (@rename($dirsource, $dirdest)) {
607
                        dol_syslog("Rename ok");
608
                        // Rename docs starting with $oldref with $newref
609
                        $listoffiles = dol_dir_list($conf->webhook->dir_output . '/target/' . $newref, 'files', 1, '^' . preg_quote($oldref, '/'));
610
                        foreach ($listoffiles as $fileentry) {
611
                            $dirsource = $fileentry['name'];
612
                            $dirdest = preg_replace('/^' . preg_quote($oldref, '/') . '/', $newref, $dirsource);
613
                            $dirsource = $fileentry['path'] . '/' . $dirsource;
614
                            $dirdest = $fileentry['path'] . '/' . $dirdest;
615
                            @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

615
                            /** @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...
616
                        }
617
                    }
618
                }
619
            }
620
        }
621
622
        // Set new ref and current status
623
        if (!$error) {
624
            $this->ref = $num;
625
            $this->status = self::STATUS_VALIDATED;
626
        }
627
628
        if (!$error) {
629
            $this->db->commit();
630
            return 1;
631
        } else {
632
            $this->db->rollback();
633
            return -1;
634
        }
635
    }
636
637
638
    /**
639
     *  Set draft status
640
     *
641
     *  @param  User    $user           Object user that modify
642
     *  @param  int     $notrigger      1=Does not execute triggers, 0=Execute triggers
643
     *  @return int                     Return integer <0 if KO, >0 if OK
644
     */
645
    public function setDraft($user, $notrigger = 0)
646
    {
647
        // Protection
648
        if ($this->status <= self::STATUS_DRAFT) {
649
            return 0;
650
        }
651
652
        return $this->setStatusCommon($user, self::STATUS_DRAFT, $notrigger, 'TARGET_UNVALIDATE');
653
    }
654
655
    /**
656
     *  Set cancel status
657
     *
658
     *  @param  User    $user           Object user that modify
659
     *  @param  int     $notrigger      1=Does not execute triggers, 0=Execute triggers
660
     *  @return int                     Return integer <0 if KO, 0=Nothing done, >0 if OK
661
     */
662
    public function cancel($user, $notrigger = 0)
663
    {
664
        // Protection
665
        if ($this->status != self::STATUS_VALIDATED) {
666
            return 0;
667
        }
668
669
        return $this->setStatusCommon($user, self::STATUS_CANCELED, $notrigger, 'TARGET_CANCEL');
670
    }
671
672
    /**
673
     *  Set back to validated status
674
     *
675
     *  @param  User    $user           Object user that modify
676
     *  @param  int     $notrigger      1=Does not execute triggers, 0=Execute triggers
677
     *  @return int                     Return integer <0 if KO, 0=Nothing done, >0 if OK
678
     */
679
    public function reopen($user, $notrigger = 0)
680
    {
681
        // Protection
682
        if ($this->status != self::STATUS_CANCELED) {
683
            return 0;
684
        }
685
686
        return $this->setStatusCommon($user, self::STATUS_VALIDATED, $notrigger, 'TARGET_REOPEN');
687
    }
688
689
    /**
690
     *  Return a link to the object card (with optionally the picto)
691
     *
692
     *  @param  int     $withpicto                  Include picto in link (0=No picto, 1=Include picto into link, 2=Only picto)
693
     *  @param  string  $option                     On what the link point to ('nolink', ...)
694
     *  @param  int     $notooltip                  1=Disable tooltip
695
     *  @param  string  $morecss                    Add more css on link
696
     *  @param  int     $save_lastsearch_value      -1=Auto, 0=No save of lastsearch_values when clicking, 1=Save lastsearch_values whenclicking
697
     *  @return string                              String with URL
698
     */
699
    public function getNomUrl($withpicto = 0, $option = '', $notooltip = 0, $morecss = '', $save_lastsearch_value = -1)
700
    {
701
        global $conf, $langs, $hookmanager;
702
703
        if (!empty($conf->dol_no_mouse_hover)) {
704
            $notooltip = 1; // Force disable tooltips
705
        }
706
707
        $result = '';
708
709
        $label = img_picto('', $this->picto) . ' <u>' . $langs->trans("Target") . '</u>';
710
        if (isset($this->status)) {
711
            $label .= ' ' . $this->getLibStatut(5);
712
        }
713
        $label .= '<br>';
714
        $label .= '<b>' . $langs->trans('Ref') . ':</b> ' . $this->ref;
715
716
        $url = dol_buildpath('/webhook/target_card.php', 1) . '?id=' . $this->id;
717
718
        if ($option != 'nolink') {
719
            // Add param to save lastsearch_values or not
720
            $add_save_lastsearch_values = ($save_lastsearch_value == 1 ? 1 : 0);
721
            if ($save_lastsearch_value == -1 && isset($_SERVER["PHP_SELF"]) && preg_match('/list\.php/', $_SERVER["PHP_SELF"])) {
722
                $add_save_lastsearch_values = 1;
723
            }
724
            if ($url && $add_save_lastsearch_values) {
725
                $url .= '&save_lastsearch_values=1';
726
            }
727
        }
728
729
        $linkclose = '';
730
        if (empty($notooltip)) {
731
            if (getDolGlobalString('MAIN_OPTIMIZEFORTEXTBROWSER')) {
732
                $label = $langs->trans("ShowTarget");
733
                $linkclose .= ' alt="' . dol_escape_htmltag($label, 1) . '"';
734
            }
735
            $linkclose .= ' title="' . dol_escape_htmltag($label, 1) . '"';
736
            $linkclose .= ' class="classfortooltip' . ($morecss ? ' ' . $morecss : '') . '"';
737
        } else {
738
            $linkclose = ($morecss ? ' class="' . $morecss . '"' : '');
739
        }
740
741
        if ($option == 'nolink' || empty($url)) {
742
            $linkstart = '<span';
743
        } else {
744
            $linkstart = '<a href="' . $url . '"';
745
        }
746
        $linkstart .= $linkclose . '>';
747
        if ($option == 'nolink' || empty($url)) {
748
            $linkend = '</span>';
749
        } else {
750
            $linkend = '</a>';
751
        }
752
753
        $result .= $linkstart;
754
755
        if (empty($this->showphoto_on_popup)) {
756
            if ($withpicto) {
757
                $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);
758
            }
759
        } else {
760
            if ($withpicto) {
761
                require_once constant('DOL_DOCUMENT_ROOT') . '/core/lib/files.lib.php';
762
763
                list($class, $module) = explode('@', $this->picto);
764
                $upload_dir = $conf->$module->multidir_output[$conf->entity] . "/$class/" . dol_sanitizeFileName($this->ref);
765
                $filearray = dol_dir_list($upload_dir, "files");
766
                $filename = $filearray[0]['name'];
767
                if (!empty($filename)) {
768
                    $pospoint = strpos($filearray[0]['name'], '.');
769
770
                    $pathtophoto = $class . '/' . $this->ref . '/thumbs/' . substr($filename, 0, $pospoint) . '_mini' . substr($filename, $pospoint);
771
                    if (!getDolGlobalString(strtoupper($module . '_' . $class) . '_FORMATLISTPHOTOSASUSERS')) {
772
                        $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>';
773
                    } else {
774
                        $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>';
775
                    }
776
777
                    $result .= '</div>';
778
                } else {
779
                    $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);
780
                }
781
            }
782
        }
783
784
        if ($withpicto != 2) {
785
            $result .= $this->ref;
786
        }
787
788
        $result .= $linkend;
789
        //if ($withpicto != 2) $result.=(($addlabel && $this->label) ? $sep . dol_trunc($this->label, ($addlabel > 1 ? $addlabel : 0)) : '');
790
791
        global $action, $hookmanager;
792
        $hookmanager->initHooks(array('targetdao'));
793
        $parameters = array('id' => $this->id, 'getnomurl' => &$result);
794
        $reshook = $hookmanager->executeHooks('getNomUrl', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks
795
        if ($reshook > 0) {
796
            $result = $hookmanager->resPrint;
797
        } else {
798
            $result .= $hookmanager->resPrint;
799
        }
800
801
        return $result;
802
    }
803
804
    /**
805
     *  Return the label of the status
806
     *
807
     *  @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
808
     *  @return string                 Label of status
809
     */
810
    public function getLabelStatus($mode = 0)
811
    {
812
        return $this->LibStatut($this->status, $mode);
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
840
            $this->labelStatus[self::STATUS_DRAFT] = $langs->transnoentitiesnoconv('Draft');
841
            $this->labelStatus[self::STATUS_VALIDATED] = $langs->transnoentitiesnoconv('Enabled');
842
            $this->labelStatus[self::STATUS_CANCELED] = $langs->transnoentitiesnoconv('Disabled');
843
            $this->labelStatusShort[self::STATUS_DRAFT] = $langs->transnoentitiesnoconv('Draft');
844
            $this->labelStatusShort[self::STATUS_VALIDATED] = $langs->transnoentitiesnoconv('Enabled');
845
            $this->labelStatusShort[self::STATUS_CANCELED] = $langs->transnoentitiesnoconv('Disabled');
846
        }
847
848
        $statusType = 'status' . $status;
849
        if ($status == self::STATUS_VALIDATED) {
850
            $statusType = 'status4';
851
        }
852
        if ($status == self::STATUS_CANCELED) {
853
            $statusType = 'status6';
854
        }
855
856
        return dolGetStatus($this->labelStatus[$status], $this->labelStatusShort[$status], '', $statusType, $mode);
857
    }
858
859
    /**
860
     *  Load the info information in the object
861
     *
862
     *  @param  int     $id       Id of object
863
     *  @return void
864
     */
865
    public function info($id)
866
    {
867
        $sql = "SELECT rowid, date_creation as datec, tms as datem,";
868
        $sql .= " fk_user_creat, fk_user_modif";
869
        $sql .= " FROM " . MAIN_DB_PREFIX . $this->table_element . " as t";
870
        $sql .= " WHERE t.rowid = " . ((int) $id);
871
872
        $result = $this->db->query($sql);
873
        if ($result) {
874
            if ($this->db->num_rows($result)) {
875
                $obj = $this->db->fetch_object($result);
876
877
                $this->id = $obj->rowid;
878
879
                $this->user_creation_id = $obj->fk_user_creat;
880
                $this->user_modification_id = $obj->fk_user_modif;
881
                $this->date_creation     = $this->db->jdate($obj->datec);
882
                $this->date_modification = empty($obj->datem) ? '' : $this->db->jdate($obj->datem);
883
            }
884
885
            $this->db->free($result);
886
        } else {
887
            dol_print_error($this->db);
888
        }
889
    }
890
891
    /**
892
     * Initialise object with example values
893
     * Id must be 0 if object instance is a specimen
894
     *
895
     * @return int
896
     */
897
    public function initAsSpecimen()
898
    {
899
        $this->url = "https://thisisunurl";
900
        $this->trigger_codes = "ThisIsATestCode";
901
902
        return $this->initAsSpecimenCommon();
903
    }
904
905
    /**
906
     *  Returns the reference to the following non used object depending on the active numbering module.
907
     *
908
     *  @return string              Object free reference
909
     */
910
    public function getNextNumRef()
911
    {
912
        global $langs, $conf;
913
914
        $mybool = false;
915
916
        $classname = getDolGlobalString('WEBHOOK_TARGET_ADDON', 'mod_target_standard');
917
        $file = $classname . ".php";
918
919
        // Include file with class
920
        $dirmodels = array_merge(array('/'), (array) $conf->modules_parts['models']);
921
        foreach ($dirmodels as $reldir) {
922
            $dir = dol_buildpath($reldir . "core/modules/webhook/");
923
924
            // Load file with numbering class (if found)
925
            $mybool = ((bool) @include_once $dir . $file) || $mybool;
926
        }
927
928
        if ($mybool === false) {
929
            dol_print_error(null, "Failed to include file " . $file);
930
            return '';
931
        }
932
933
        if (class_exists($classname)) {
934
            $obj = new $classname();
935
            $numref = $obj->getNextValue($this);
936
937
            if ($numref != '' && $numref != '-1') {
938
                return $numref;
939
            } else {
940
                $this->error = $obj->error;
941
                //dol_print_error($this->db,get_class($this)."::getNextNumRef ".$obj->error);
942
                return "";
943
            }
944
        } else {
945
            print $langs->trans("Error") . " " . $langs->trans("ClassNotFound") . ' ' . $classname;
946
            return "";
947
        }
948
    }
949
950
    /**
951
     *  Create a document onto disk according to template module.
952
     *
953
     *  @param      string      $modele         Force template to use ('' to not force)
954
     *  @param      Translate   $outputlangs    object lang a utiliser pour traduction
955
     *  @param      int         $hidedetails    Hide details of lines
956
     *  @param      int         $hidedesc       Hide description
957
     *  @param      int         $hideref        Hide ref
958
     *  @param      null|array  $moreparams     Array to provide more information
959
     *  @return     int                         0 if KO, 1 if OK
960
     */
961
    public function generateDocument($modele, $outputlangs, $hidedetails = 0, $hidedesc = 0, $hideref = 0, $moreparams = null)
962
    {
963
        $result = 0;
964
        $includedocgeneration = 0;
965
966
        if (!dol_strlen($modele)) {
967
            $modele = 'standard_target';
968
969
            if (!empty($this->model_pdf)) {
970
                $modele = $this->model_pdf;
971
            } elseif (getDolGlobalString('TARGET_ADDON_PDF')) {
972
                $modele = getDolGlobalString('TARGET_ADDON_PDF');
973
            }
974
        }
975
976
        $modelpath = "core/modules/webhook/doc/";
977
978
        if ($includedocgeneration && !empty($modele)) {
979
            $result = $this->commonGenerateDocument($modelpath, $modele, $outputlangs, $hidedetails, $hidedesc, $hideref, $moreparams);
980
        }
981
982
        return $result;
983
    }
984
985
    /**
986
     * Action executed by scheduler
987
     * CAN BE A CRON TASK. In such a case, parameters come from the schedule job setup field 'Parameters'
988
     * Use public function doScheduledJob($param1, $param2, ...) to get parameters
989
     *
990
     * @return  int         0 if OK, <>0 if KO (this function is used also by cron so only 0 is OK)
991
     */
992
    public function doScheduledJob()
993
    {
994
        //global $conf, $langs;
995
996
        //$conf->global->SYSLOG_FILE = 'DOL_DATA_ROOT/dolibarr_mydedicatedlofile.log';
997
998
        $error = 0;
999
        $this->output = '';
1000
        $this->error = '';
1001
1002
        dol_syslog(__METHOD__, LOG_DEBUG);
1003
1004
        //$now = dol_now();
1005
1006
        $this->db->begin();
1007
1008
        // ...
1009
1010
        $this->db->commit();
1011
1012
        return $error;
1013
    }
1014
}
1015