Passed
Push — EXTRACT_CLASSES ( a2ff75...ae6b5c )
by Rafael
34:15
created

ProductAttributeValue::create()   F

Complexity

Conditions 12
Paths 400

Size

Total Lines 67
Code Lines 45

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 12
eloc 45
nc 400
nop 2
dl 0
loc 67
rs 3.6333
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) 2016       Marcos García               <[email protected]>
4
 * Copyright (C) 2022       Open-Dsi		            <[email protected]>
5
 * Copyright (C) 2024		MDW							<[email protected]>
6
 * Copyright (C) 2024       Frédéric France             <[email protected]>
7
 * Copyright (C) 2024       Rafael San José             <[email protected]>
8
 *
9
 * This program is free software; you can redistribute it and/or modify
10
 * it under the terms of the GNU General Public License as published by
11
 * the Free Software Foundation; either version 3 of the License, or
12
 * (at your option) any later version.
13
 *
14
 * This program is distributed in the hope that it will be useful,
15
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17
 * GNU General Public License for more details.
18
 *
19
 * You should have received a copy of the GNU General Public License
20
 * along with this program. If not, see <https://www.gnu.org/licenses/>.
21
 */
22
23
namespace Dolibarr\Code\Variants\Classes;
24
25
use Dolibarr\Core\Base\CommonObjectLine;
26
27
/**
28
 * Class ProductAttributeValue
29
 * Used to represent a product attribute value
30
 */
31
class ProductAttributeValue extends CommonObjectLine
32
{
33
    /**
34
     * @var string ID of module.
35
     */
36
    public $module = 'variants';
37
38
    /**
39
     * @var string ID to identify managed object.
40
     */
41
    public $element = 'productattributevalue';
42
43
    /**
44
     * @var string Name of table without prefix where object is stored. This is also the key used for extrafields management.
45
     */
46
    public $table_element = 'product_attribute_value';
47
48
    /**
49
     *  'type' field format ('integer', 'integer:ObjectClass:PathToClass[:AddCreateButtonOrNot[:Filter]]', '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')
50
     *         Note: Filter can be a string like "(t.ref:like:'SO-%') or (t.date_creation:<:'20160101') or (t.nature:is:NULL)"
51
     *  'label' the translation key.
52
     *  'picto' is code of a picto to show before value in forms
53
     *  'enabled' is a condition when the field must be managed (Example: 1 or 'getDolGlobalString("MY_SETUP_PARAM")'
54
     *  'position' is the sort order of field.
55
     *  'notnull' is set to 1 if not null in database. Set to -1 if we must set data to null if empty ('' or 0).
56
     *  '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)
57
     *  'noteditable' says if field is not editable (1 or 0)
58
     *  '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.
59
     *  'index' if we want an index in database.
60
     *  'foreignkey'=>'tablename.field' if the field is a foreign key (it is recommended to name the field fk_...).
61
     *  'searchall' is 1 if we want to search in this field when making a search from the quick search button.
62
     *  '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).
63
     *  '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: 'maxwidth200', 'wordbreak', 'tdoverflowmax200'
64
     *  'help' is a 'TranslationString' to use to show a tooltip on field. You can also use 'TranslationString:keyfortooltiponlick' for a tooltip on click.
65
     *  'showoncombobox' if value of the field must be visible into the label of the combobox that list record
66
     *  '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.
67
     *  'arrayofkeyval' to set list of value if type is a list of predefined values. For example: array("0"=>"Draft","1"=>"Active","-1"=>"Cancel")
68
     *  'autofocusoncreate' to have field having the focus on a create form. Only 1 field should have this property set to 1.
69
     *  'comment' is not used. You can store here any text of your choice. It is not used by application.
70
     *
71
     *  Note: To have value dynamic, you can set value to 0 in definition and edit the value on the fly into the constructor.
72
     */
73
    /**
74
     * @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...
75
     */
76
    public $fields = array(
77
        'rowid' => array('type' => 'integer', 'label' => 'TechnicalID', 'enabled' => 1, 'position' => 1, 'notnull' => 1, 'visible' => 0, 'noteditable' => 1, 'index' => 1, 'css' => 'left', 'comment' => "Id"),
78
        'fk_product_attribute' => array('type' => 'integer:ProductAttribute:variants/class/ProductAttribute.class.php', 'label' => 'ProductAttribute', 'enabled' => 1, 'visible' => 0, 'position' => 10, 'notnull' => 1, 'index' => 1,),
79
        'ref' => array('type' => 'varchar(255)', 'label' => 'Ref', 'visible' => 1, 'enabled' => 1, 'position' => 20, 'notnull' => 1, 'index' => 1, 'searchall' => 1, 'comment' => "Reference of object", 'css' => ''),
80
        'value' => array('type' => 'varchar(255)', 'label' => 'Value', 'enabled' => 1, 'position' => 30, 'notnull' => 1, 'visible' => 1, 'searchall' => 1, 'css' => 'minwidth300', 'help' => "", 'showoncombobox' => 1,),
81
        'position' => array('type' => 'integer', 'label' => 'Rank', 'enabled' => 1, 'visible' => 0, 'default' => '0', 'position' => 200, 'notnull' => 1,),
82
    );
83
84
    /**
85
     * ID of the ProductAttributeValue
86
     * @var int
87
     */
88
    public $id;
89
90
    /**
91
     * ID of the parent attribute (ex: ID of the attribute "COLOR")
92
     * @var int
93
     */
94
    public $fk_product_attribute;
95
96
    /**
97
     * Reference of the ProductAttributeValue (ex: "BLUE_1" or "RED_3")
98
     * @var string
99
     */
100
    public $ref;
101
102
    /**
103
     * Label of the ProductAttributeValue (ex: "Dark blue" or "Chili Red")
104
     * @var string
105
     */
106
    public $value;
107
108
    /**
109
     * Sorting position of the ProductAttributeValue
110
     * @var int
111
     */
112
    public $position;
113
114
    /**
115
     * Constructor
116
     *
117
     * @param   DoliDB $db     Database handler
118
     */
119
    public function __construct(DoliDB $db)
0 ignored issues
show
Bug introduced by
The type Dolibarr\Code\Variants\Classes\DoliDB was not found. Did you mean DoliDB? If so, make sure to prefix the type with \.
Loading history...
120
    {
121
        global $conf, $langs;
122
123
        $this->db = $db;
124
125
        $this->ismultientitymanaged = 1;
126
        $this->isextrafieldmanaged = 0;
127
        $this->entity = $conf->entity;
128
129
        if (!getDolGlobalString('MAIN_SHOW_TECHNICAL_ID') && isset($this->fields['rowid'])) {
130
            $this->fields['rowid']['visible'] = 0;
131
        }
132
        if (!isModEnabled('multicompany') && isset($this->fields['entity'])) {
133
            $this->fields['entity']['enabled'] = 0;
134
        }
135
136
        // Unset fields that are disabled
137
        foreach ($this->fields as $key => $val) {
138
            if (isset($val['enabled']) && empty($val['enabled'])) {
139
                unset($this->fields[$key]);
140
            }
141
        }
142
143
        // Translate some data of arrayofkeyval
144
        if (is_object($langs)) {
145
            foreach ($this->fields as $key => $val) {
146
                if (!empty($val['arrayofkeyval']) && is_array($val['arrayofkeyval'])) {
147
                    foreach ($val['arrayofkeyval'] as $key2 => $val2) {
148
                        $this->fields[$key]['arrayofkeyval'][$key2] = $langs->trans($val2);
149
                    }
150
                }
151
            }
152
        }
153
    }
154
155
    /**
156
     * Creates a value for a product attribute
157
     *
158
     * @param  User $user      Object user
159
     * @param  int  $notrigger Do not execute trigger
160
     * @return int Return integer <0 KO >0 OK
161
     */
162
    public function create(User $user, $notrigger = 0)
163
    {
164
        global $langs;
165
        $error = 0;
166
167
        // Clean parameters
168
        $this->fk_product_attribute = $this->fk_product_attribute > 0 ? $this->fk_product_attribute : 0;
169
        $this->ref = strtoupper(dol_sanitizeFileName(dol_string_nospecial(trim($this->ref)))); // Ref must be uppercase
170
        $this->value = trim($this->value);
171
172
        // Check parameters
173
        if (empty($this->fk_product_attribute)) {
174
            $this->errors[] = $langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("ProductAttribute"));
175
            $error++;
176
        }
177
        if (empty($this->ref)) {
178
            $this->errors[] = $langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("Ref"));
179
            $error++;
180
        }
181
        if (empty($this->value)) {
182
            $this->errors[] = $langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("Value"));
183
            $error++;
184
        }
185
        if ($error) {
186
            dol_syslog(__METHOD__ . ' ' . $this->errorsToString(), LOG_ERR);
187
            return -1;
188
        }
189
190
        $this->db->begin();
191
192
        $sql = "INSERT INTO " . MAIN_DB_PREFIX . $this->table_element . " (";
193
        $sql .= " fk_product_attribute, ref, value, entity, position";
194
        $sql .= ")";
195
        $sql .= " VALUES (";
196
        $sql .= "  " . ((int) $this->fk_product_attribute);
197
        $sql .= ", '" . $this->db->escape($this->ref) . "'";
198
        $sql .= ", '" . $this->db->escape($this->value) . "'";
199
        $sql .= ", " . ((int) $this->entity);
200
        $sql .= ", " . ((int) $this->position);
201
        $sql .= ")";
202
203
        dol_syslog(__METHOD__, LOG_DEBUG);
204
        $resql = $this->db->query($sql);
205
        if (!$resql) {
206
            $this->errors[] = "Error " . $this->db->lasterror();
207
            $error++;
208
        }
209
210
        if (!$error) {
211
            $this->id = $this->db->last_insert_id(MAIN_DB_PREFIX . $this->table_element);
212
        }
213
214
        if (!$error && !$notrigger) {
215
            // Call trigger
216
            $result = $this->call_trigger('PRODUCT_ATTRIBUTE_VALUE_CREATE', $user);
217
            if ($result < 0) {
218
                $error++;
219
            }
220
            // End call triggers
221
        }
222
223
        if ($error) {
224
            $this->db->rollback();
225
            return -1 * $error;
226
        } else {
227
            $this->db->commit();
228
            return $this->id;
229
        }
230
    }
231
232
    /**
233
     * Gets a product attribute value
234
     *
235
     * @param int $id Product attribute value id
236
     * @return int Return integer <0 KO, >0 OK
237
     */
238
    public function fetch($id)
239
    {
240
        global $langs;
241
        $error = 0;
242
243
        // Clean parameters
244
        $id = $id > 0 ? $id : 0;
245
246
        // Check parameters
247
        if (empty($id)) {
248
            $this->errors[] = $langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("TechnicalID"));
249
            $error++;
250
        }
251
        if ($error) {
252
            dol_syslog(__METHOD__ . ' ' . $this->errorsToString(), LOG_ERR);
253
            return -1;
254
        }
255
256
        $sql = "SELECT rowid, fk_product_attribute, ref, value";
257
        $sql .= " FROM " . MAIN_DB_PREFIX . $this->table_element;
258
        $sql .= " WHERE rowid = " . ((int) $id);
259
        $sql .= " AND entity IN (" . getEntity('product') . ")";
260
261
        dol_syslog(__METHOD__, LOG_DEBUG);
262
        $resql = $this->db->query($sql);
263
        if (!$resql) {
264
            $this->errors[] = "Error " . $this->db->lasterror();
265
            dol_syslog(__METHOD__ . ' ' . $this->errorsToString(), LOG_ERR);
266
            return -1;
267
        }
268
269
        $numrows = $this->db->num_rows($resql);
270
        if ($numrows) {
271
            $obj = $this->db->fetch_object($resql);
272
273
            $this->id = $obj->rowid;
274
            $this->fk_product_attribute = $obj->fk_product_attribute;
275
            $this->ref = $obj->ref;
276
            $this->value = $obj->value;
277
        }
278
        $this->db->free($resql);
279
280
        return $numrows;
281
    }
282
283
    /**
284
     * Returns all product attribute values of a product attribute
285
     *
286
     * @param   int     $prodattr_id        Product attribute id
287
     * @param   bool    $only_used          Fetch only used attribute values
288
     * @param   int<0,1>    $returnonlydata     0: return object, 1: return only data
289
     * @return  ProductAttributeValue[]|stdClass[]  Array of object
290
     */
291
    public function fetchAllByProductAttribute($prodattr_id, $only_used = false, $returnonlydata = 0)
292
    {
293
        $return = array();
294
295
        $sql = "SELECT ";
296
297
        if ($only_used) {
298
            $sql .= "DISTINCT ";
299
        }
300
301
        $sql .= "v.fk_product_attribute, v.rowid, v.ref, v.value FROM " . MAIN_DB_PREFIX . "product_attribute_value v ";
302
303
        if ($only_used) {
304
            $sql .= "LEFT JOIN " . MAIN_DB_PREFIX . "product_attribute_combination2val c2v ON c2v.fk_prod_attr_val = v.rowid ";
305
            $sql .= "LEFT JOIN " . MAIN_DB_PREFIX . "product_attribute_combination c ON c.rowid = c2v.fk_prod_combination ";
306
            $sql .= "LEFT JOIN " . MAIN_DB_PREFIX . "product p ON p.rowid = c.fk_product_child ";
307
        }
308
309
        $sql .= "WHERE v.fk_product_attribute = " . ((int) $prodattr_id);
310
311
        if ($only_used) {
312
            $sql .= " AND c2v.rowid IS NOT NULL AND p.tosell = 1";
313
        }
314
315
        $sql .= " ORDER BY v.position ASC";
316
317
        $query = $this->db->query($sql);
318
319
        while ($result = $this->db->fetch_object($query)) {
320
            if (empty($returnonlydata)) {
321
                $tmp = new ProductAttributeValue($this->db);
322
            } else {
323
                $tmp = new stdClass();
0 ignored issues
show
Bug introduced by
The type Dolibarr\Code\Variants\Classes\stdClass was not found. Did you mean stdClass? If so, make sure to prefix the type with \.
Loading history...
324
            }
325
326
            $tmp->fk_product_attribute = $result->fk_product_attribute;
327
            $tmp->id = $result->rowid;
328
            $tmp->ref = $result->ref;
329
            $tmp->value = $result->value;
330
331
            $return[] = $tmp;
332
        }
333
334
        return $return;
335
    }
336
337
    /**
338
     * Updates a product attribute value
339
     *
340
     * @param  User $user      Object user
341
     * @param  int  $notrigger Do not execute trigger
342
     * @return int Return integer <0 if KO, >0 if OK
343
     */
344
    public function update(User $user, $notrigger = 0)
345
    {
346
        global $langs;
347
        $error = 0;
348
349
        // Clean parameters
350
        $this->fk_product_attribute = $this->fk_product_attribute > 0 ? $this->fk_product_attribute : 0;
351
        $this->ref = strtoupper(dol_sanitizeFileName(dol_string_nospecial(trim($this->ref)))); // Ref must be uppercase
352
        $this->value = trim($this->value);
353
354
        // Check parameters
355
        if (empty($this->fk_product_attribute)) {
356
            $this->errors[] = $langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("ProductAttribute"));
357
            $error++;
358
        }
359
        if (empty($this->ref)) {
360
            $this->errors[] = $langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("Ref"));
361
            $error++;
362
        }
363
        if (empty($this->value)) {
364
            $this->errors[] = $langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("Value"));
365
            $error++;
366
        }
367
        if ($error) {
368
            dol_syslog(__METHOD__ . ' ' . $this->errorsToString(), LOG_ERR);
369
            return -1;
370
        }
371
372
        $this->db->begin();
373
374
        $sql = "UPDATE " . MAIN_DB_PREFIX . $this->table_element . " SET";
375
376
        $sql .= "  fk_product_attribute = " . ((int) $this->fk_product_attribute);
377
        $sql .= ", ref = '" . $this->db->escape($this->ref) . "'";
378
        $sql .= ", value = '" . $this->db->escape($this->value) . "'";
379
        $sql .= ", position = " . ((int) $this->position);
380
381
        $sql .= " WHERE rowid = " . ((int) $this->id);
382
383
        dol_syslog(__METHOD__, LOG_DEBUG);
384
        $resql = $this->db->query($sql);
385
        if (!$resql) {
386
            $this->errors[] = "Error " . $this->db->lasterror();
387
            $error++;
388
        }
389
390
        if (!$error && !$notrigger) {
391
            // Call trigger
392
            $result = $this->call_trigger('PRODUCT_ATTRIBUTE_VALUE_MODIFY', $user);
393
            if ($result < 0) {
394
                $error++;
395
            }
396
            // End call triggers
397
        }
398
399
        if (!$error) {
400
            $this->db->commit();
401
            return 1;
402
        } else {
403
            $this->db->rollback();
404
            return -1 * $error;
405
        }
406
    }
407
408
    /**
409
     * Deletes a product attribute value
410
     *
411
     * @param  User $user      Object user
412
     * @param  int  $notrigger Do not execute trigger
413
     * @return int Return integer <0 KO, >0 OK
414
     */
415
    public function delete(User $user, $notrigger = 0)
416
    {
417
        global $langs;
418
        $error = 0;
419
420
        // Clean parameters
421
        $this->id = $this->id > 0 ? $this->id : 0;
422
423
        // Check parameters
424
        if (empty($this->id)) {
425
            $this->errors[] = $langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("TechnicalID"));
426
            $error++;
427
        }
428
        if ($error) {
429
            dol_syslog(__METHOD__ . ' ' . $this->errorsToString(), LOG_ERR);
430
            return -1;
431
        }
432
433
        $result = $this->isUsed();
434
        if ($result < 0) {
435
            return -1;
436
        } elseif ($result > 0) {
437
            $this->errors[] = $langs->trans('ErrorAttributeValueIsUsedIntoProduct');
438
            return -1;
439
        }
440
441
        $this->db->begin();
442
443
        if (!$error && !$notrigger) {
444
            // Call trigger
445
            $result = $this->call_trigger('PRODUCT_ATTRIBUTE_VALUE_DELETE', $user);
446
            if ($result < 0) {
447
                $error++;
448
            }
449
            // End call triggers
450
        }
451
452
        if (!$error) {
453
            $sql = "DELETE FROM " . MAIN_DB_PREFIX . $this->table_element . " WHERE rowid = " . ((int) $this->id);
454
455
            dol_syslog(__METHOD__, LOG_DEBUG);
456
            $resql = $this->db->query($sql);
457
            if (!$resql) {
458
                $this->errors[] = "Error " . $this->db->lasterror();
459
                $error++;
460
            }
461
        }
462
463
        if (!$error) {
464
            $this->db->commit();
465
            return 1;
466
        } else {
467
            $this->db->rollback();
468
            return -1 * $error;
469
        }
470
    }
471
472
    /**
473
     * Test if used by a product
474
     *
475
     * @return int Return integer <0 KO, =0 if No, =1 if Yes
476
     */
477
    public function isUsed()
478
    {
479
        global $langs;
480
        $error = 0;
481
482
        // Clean parameters
483
        $this->id = $this->id > 0 ? $this->id : 0;
484
485
        // Check parameters
486
        if (empty($this->id)) {
487
            $this->errors[] = $langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("TechnicalID"));
488
            $error++;
489
        }
490
        if ($error) {
491
            dol_syslog(__METHOD__ . ' ' . $this->errorsToString(), LOG_ERR);
492
            return -1;
493
        }
494
495
        $sql = "SELECT COUNT(*) AS nb FROM " . MAIN_DB_PREFIX . "product_attribute_combination2val WHERE fk_prod_attr_val = " . ((int) $this->id);
496
497
        dol_syslog(__METHOD__, LOG_DEBUG);
498
        $resql = $this->db->query($sql);
499
        if (!$resql) {
500
            $this->errors[] = "Error " . $this->db->lasterror();
501
            return -1;
502
        }
503
504
        $used = 0;
505
        if ($obj = $this->db->fetch_object($resql)) {
506
            $used = $obj->nb;
507
        }
508
509
        return $used ? 1 : 0;
510
    }
511
}
512