dolibarr 21.0.3
categorie.class.php
Go to the documentation of this file.
1<?php
2/* Copyright (C) 2005 Matthieu Valleton <mv@seeschloss.org>
3 * Copyright (C) 2005 Davoleau Brice <brice.davoleau@gmail.com>
4 * Copyright (C) 2005 Rodolphe Quiedeville <rodolphe@quiedeville.org>
5 * Copyright (C) 2006-2012 Regis Houssin <regis.houssin@inodbox.com>
6 * Copyright (C) 2006-2012 Laurent Destailleur <eldy@users.sourceforge.net>
7 * Copyright (C) 2007 Patrick Raguin <patrick.raguin@gmail.com>
8 * Copyright (C) 2013-2016 Juanjo Menent <jmenent@2byte.es>
9 * Copyright (C) 2013-2018 Philippe Grand <philippe.grand@atoo-net.com>
10 * Copyright (C) 2015 Marcos García <marcosgdf@gmail.com>
11 * Copyright (C) 2015 Raphaël Doursenaud <rdoursenaud@gpcsolutions.fr>
12 * Copyright (C) 2016-2024 Charlene Benke <charlene@patas-monkey.com>
13 * Copyright (C) 2018-2024 Frédéric France <frederic.france@free.fr>
14 * Copyright (C) 2023-2024 Benjamin Falière <benjamin.faliere@altairis.fr>
15 * Copyright (C) 2024 MDW <mdeweerd@users.noreply.github.com>
16 *
17 * This program is free software; you can redistribute it and/or modify
18 * it under the terms of the GNU General Public License as published by
19 * the Free Software Foundation; either version 3 of the License, or
20 * (at your option) any later version.
21 *
22 * This program is distributed in the hope that it will be useful,
23 * but WITHOUT ANY WARRANTY; without even the implied warranty of
24 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
25 * GNU General Public License for more details.
26 *
27 * You should have received a copy of the GNU General Public License
28 * along with this program. If not, see <https://www.gnu.org/licenses/>.
29 */
30
37require_once DOL_DOCUMENT_ROOT.'/core/class/commonobject.class.php';
38require_once DOL_DOCUMENT_ROOT.'/product/class/product.class.php';
39require_once DOL_DOCUMENT_ROOT.'/ticket/class/ticket.class.php';
40require_once DOL_DOCUMENT_ROOT.'/fourn/class/fournisseur.class.php';
41require_once DOL_DOCUMENT_ROOT.'/contact/class/contact.class.php';
42require_once DOL_DOCUMENT_ROOT.'/knowledgemanagement/class/knowledgerecord.class.php';
43
44
49{
50 // Categories types (we use string because we want to accept any modules/types in a future)
51 const TYPE_PRODUCT = 'product';
52 const TYPE_SUPPLIER = 'supplier';
53 const TYPE_CUSTOMER = 'customer';
54 const TYPE_MEMBER = 'member';
55 const TYPE_CONTACT = 'contact';
56 const TYPE_USER = 'user';
57 const TYPE_PROJECT = 'project';
58 const TYPE_ACCOUNT = 'bank_account';
59 const TYPE_BANK_LINE = 'bank_line';
60 const TYPE_WAREHOUSE = 'warehouse';
61 const TYPE_ACTIONCOMM = 'actioncomm';
62 const TYPE_WEBSITE_PAGE = 'website_page';
63 const TYPE_TICKET = 'ticket';
64 const TYPE_KNOWLEDGEMANAGEMENT = 'knowledgemanagement';
65 const TYPE_FICHINTER = 'fichinter';
66
70 public $picto = 'category';
71
72
76 public $MAP_ID = array(
77 'product' => 0,
78 'supplier' => 1,
79 'customer' => 2,
80 'member' => 3,
81 'contact' => 4,
82 'bank_account' => 5,
83 'project' => 6,
84 'user' => 7,
85 'bank_line' => 8,
86 'warehouse' => 9,
87 'actioncomm' => 10,
88 'website_page' => 11,
89 'ticket' => 12,
90 'knowledgemanagement' => 13,
91 'fichinter' => 14,
92 );
93
99 public static $MAP_ID_TO_CODE = array(
100 0 => 'product',
101 1 => 'supplier',
102 2 => 'customer',
103 3 => 'member',
104 4 => 'contact',
105 5 => 'bank_account',
106 6 => 'project',
107 7 => 'user',
108 8 => 'bank_line',
109 9 => 'warehouse',
110 10 => 'actioncomm',
111 11 => 'website_page',
112 12 => 'ticket',
113 13 => 'knowledgemanagement',
114 14 => 'fichinter',
115 );
116
122 public $MAP_CAT_FK = array(
123 'customer' => 'soc',
124 'supplier' => 'soc',
125 'contact' => 'socpeople',
126 'bank_account' => 'account',
127 );
128
134 public $MAP_CAT_TABLE = array(
135 'customer' => 'societe',
136 'supplier' => 'fournisseur',
137 'bank_account' => 'account',
138 );
139
145 public $MAP_OBJ_CLASS = array(
146 'product' => 'Product',
147 'customer' => 'Societe',
148 'supplier' => 'Fournisseur',
149 'member' => 'Adherent',
150 'contact' => 'Contact',
151 'user' => 'User',
152 'account' => 'Account', // old for bank account
153 'bank_account' => 'Account',
154 'project' => 'Project',
155 'warehouse' => 'Entrepot',
156 'actioncomm' => 'ActionComm',
157 'website_page' => 'WebsitePage',
158 'ticket' => 'Ticket',
159 'knowledgemanagement' => 'KnowledgeRecord',
160 'fichinter' => 'Fichinter',
161 );
162
168 public static $MAP_TYPE_TITLE_AREA = array(
169 'product' => 'ProductsCategoriesArea',
170 'customer' => 'CustomersCategoriesArea',
171 'supplier' => 'SuppliersCategoriesArea',
172 'member' => 'MembersCategoriesArea',
173 'contact' => 'ContactsCategoriesArea',
174 'user' => 'UsersCategoriesArea',
175 'account' => 'AccountsCategoriesArea', // old for bank account
176 'bank_account' => 'AccountsCategoriesArea',
177 'project' => 'ProjectsCategoriesArea',
178 'warehouse' => 'StocksCategoriesArea',
179 'actioncomm' => 'ActioncommCategoriesArea',
180 'website_page' => 'WebsitePagesCategoriesArea',
181 'ticket' => 'TicketsCategoriesArea',
182 'knowledgemanagement' => 'KnowledgemanagementsCategoriesArea',
183 'fichinter' => 'FichintersCategoriesArea',
184 );
185
190 public $MAP_OBJ_TABLE = array(
191 'customer' => 'societe',
192 'supplier' => 'societe',
193 'member' => 'adherent',
194 'contact' => 'socpeople',
195 'account' => 'bank_account', // old for bank account
196 'project' => 'projet',
197 'warehouse' => 'entrepot',
198 'knowledgemanagement' => 'knowledgemanagement_knowledgerecord',
199 'fichinter' => 'fichinter',
200 );
201
205 public $element = 'category';
206
210 public $table_element = 'categorie';
211
215 public $fk_parent;
216
220 public $label;
221
225 public $description;
226
230 public $color;
231
235 public $position;
236
240 public $visible;
241
245 public $socid;
246
265 public $type;
266
270 public $cats = array();
271
275 public $motherof = array();
276
280 public $childs = array();
281
285 public $multilangs = array();
286
290 public $imgWidth;
291
295 public $imgHeight;
296
321 public $fields = array(
322 'rowid' => array('type' => 'integer', 'label' => 'TechnicalID', 'enabled' => 1, 'position' => 10, 'notnull' => 1, 'visible' => -1,),
323 'entity' => array('type' => 'integer', 'label' => 'Entity', 'enabled' => 1, 'visible' => 0, 'default' => '1', 'notnull' => 1, 'index' => 1, 'position' => 5),
324 'fk_parent' => array('type' => 'integer', 'label' => 'Fkparent', 'enabled' => 1, 'position' => 20, 'notnull' => 1, 'visible' => -1, 'css' => 'maxwidth500 widthcentpercentminusxx',),
325 'label' => array('type' => 'varchar(180)', 'label' => 'Label', 'enabled' => 1, 'position' => 25, 'notnull' => 1, 'visible' => -1, 'alwayseditable' => 1, 'css' => 'minwidth300', 'cssview' => 'wordbreak', 'csslist' => 'tdoverflowmax150', 'showoncombobox' => 1),
326 'ref_ext' => array('type' => 'varchar(255)', 'label' => 'RefExt', 'enabled' => 1, 'position' => 30, 'notnull' => 0, 'visible' => 0, 'alwayseditable' => 1,),
327 'type' => array('type' => 'integer', 'label' => 'Type', 'enabled' => 1, 'position' => 35, 'notnull' => 1, 'visible' => -1, 'alwayseditable' => 1,),
328 'description' => array('type' => 'text', 'label' => 'Description', 'enabled' => 1, 'position' => 40, 'notnull' => 0, 'visible' => -1, 'alwayseditable' => 1,),
329 'color' => array('type' => 'varchar(8)', 'label' => 'Color', 'enabled' => 1, 'position' => 45, 'notnull' => 0, 'visible' => -1, 'alwayseditable' => 1,),
330 'position' => array('type' => 'integer', 'label' => 'Position', 'enabled' => 1, 'position' => 50, 'notnull' => 0, 'visible' => -1, 'alwayseditable' => 1,),
331 'fk_soc' => array('type' => 'integer:Societe:societe/class/societe.class.php', 'label' => 'ThirdParty', 'picto' => 'company', 'enabled' => 1, 'position' => 55, 'notnull' => 0, 'visible' => -1, 'alwayseditable' => 1, 'css' => 'maxwidth500 widthcentpercentminusxx', 'csslist' => 'tdoverflowmax150',),
332 'visible' => array('type' => 'integer', 'label' => 'Visible', 'enabled' => 1, 'position' => 60, 'notnull' => 1, 'visible' => -1, 'alwayseditable' => 1,),
333 'import_key' => array('type' => 'varchar(14)', 'label' => 'ImportId', 'enabled' => 1, 'position' => 900, 'notnull' => 0, 'visible' => -2, 'alwayseditable' => 1,),
334 'date_creation' => array('type' => 'datetime', 'label' => 'DateCreation', 'enabled' => 1, 'position' => 70, 'notnull' => 0, 'visible' => -1, 'alwayseditable' => 1,),
335 'tms' => array('type' => 'timestamp', 'label' => 'DateModification', 'enabled' => 1, 'position' => 75, 'notnull' => 1, 'visible' => -1, 'alwayseditable' => 1,),
336 'fk_user_creat' => array('type' => 'integer:User:user/class/user.class.php', 'label' => 'UserAuthor', 'enabled' => 1, 'position' => 80, 'notnull' => 0, 'visible' => -2, 'alwayseditable' => 1, 'css' => 'maxwidth500 widthcentpercentminusxx', 'csslist' => 'tdoverflowmax150',),
337 'fk_user_modif' => array('type' => 'integer:User:user/class/user.class.php', 'label' => 'UserModif', 'enabled' => 1, 'position' => 85, 'notnull' => -1, 'visible' => -2, 'alwayseditable' => 1, 'css' => 'maxwidth500 widthcentpercentminusxx', 'csslist' => 'tdoverflowmax150',),
338 );
339
345 public function __construct($db)
346 {
347 global $hookmanager;
348
349 $this->db = $db;
350
351 if (is_object($hookmanager)) {
352 $hookmanager->initHooks(array('category'));
353 $parameters = array();
354 $reshook = $hookmanager->executeHooks('constructCategory', $parameters, $this); // Note that $action and $object may have been modified by some hooks
355 if ($reshook >= 0 && !empty($hookmanager->resArray)) {
356 foreach ($hookmanager->resArray as $mapList) {
357 $mapId = $mapList['id'];
358 $mapCode = $mapList['code'];
359 self::$MAP_ID_TO_CODE[$mapId] = $mapCode;
360 $this->MAP_ID[$mapCode] = $mapId;
361 $this->MAP_CAT_FK[$mapCode] = isset($mapList['cat_fk']) ? $mapList['cat_fk'] : null;
362 $this->MAP_CAT_TABLE[$mapCode] = isset($mapList['cat_table']) ? $mapList['cat_table'] : null;
363 $this->MAP_OBJ_CLASS[$mapCode] = $mapList['obj_class'];
364 $this->MAP_OBJ_TABLE[$mapCode] = $mapList['obj_table'];
365 }
366 }
367 }
368 }
369
375 public function getMapList()
376 {
377 $mapList = array();
378
379 foreach ($this->MAP_ID as $mapCode => $mapId) {
380 $mapList[] = array(
381 'id' => $mapId,
382 'code' => $mapCode,
383 'cat_fk' => (empty($this->MAP_CAT_FK[$mapCode]) ? $mapCode : $this->MAP_CAT_FK[$mapCode]),
384 'cat_table' => (empty($this->MAP_CAT_TABLE[$mapCode]) ? $mapCode : $this->MAP_CAT_TABLE[$mapCode]),
385 'obj_class' => (empty($this->MAP_OBJ_CLASS[$mapCode]) ? $mapCode : $this->MAP_OBJ_CLASS[$mapCode]),
386 'obj_table' => (empty($this->MAP_OBJ_TABLE[$mapCode]) ? $mapCode : $this->MAP_OBJ_TABLE[$mapCode])
387 );
388 }
389
390 return $mapList;
391 }
392
398 public function getMapId()
399 {
400 return $this->MAP_ID;
401 }
402
412 public function fetch($id, $label = '', $type = null, $ref_ext = '')
413 {
414 // Check parameters
415 if (empty($id) && empty($label) && empty($ref_ext)) {
416 $this->error = "No category to search for";
417 return -1;
418 }
419 if (!is_null($type) && !is_numeric($type)) {
420 $type = $this->MAP_ID[$type];
421 }
422
423 $sql = "SELECT rowid, fk_parent, entity, label, description, color, position, fk_soc, visible, type, ref_ext";
424 $sql .= ", date_creation, tms, fk_user_creat, fk_user_modif";
425 $sql .= " FROM ".MAIN_DB_PREFIX."categorie";
426 if ($id) {
427 $sql .= " WHERE rowid = ".((int) $id);
428 } elseif (!empty($ref_ext)) {
429 $sql .= " WHERE ref_ext LIKE '".$this->db->escape($ref_ext)."'";
430 } else {
431 $sql .= " WHERE label = '".$this->db->escape($label)."' AND entity IN (".getEntity('category').")";
432 if (!is_null($type)) {
433 $sql .= " AND type = ".((int) $type);
434 }
435 }
436
437 dol_syslog(get_class($this)."::fetch", LOG_DEBUG);
438 $resql = $this->db->query($sql);
439 if ($resql) {
440 if ($this->db->num_rows($resql) > 0 && $res = $this->db->fetch_array($resql)) {
441 $this->id = $res['rowid'];
442 //$this->ref = $res['rowid'];
443 $this->fk_parent = (int) $res['fk_parent'];
444 $this->label = $res['label'];
445 $this->description = $res['description'];
446 $this->color = $res['color'];
447 $this->position = $res['position'];
448 $this->socid = (int) $res['fk_soc'];
449 $this->visible = (int) $res['visible'];
450 $this->type = $res['type'];
451 $this->ref_ext = $res['ref_ext'];
452 $this->entity = (int) $res['entity'];
453 $this->date_creation = $this->db->jdate($res['date_creation']);
454 $this->date_modification = $this->db->jdate($res['tms']);
455 $this->user_creation_id = (int) $res['fk_user_creat'];
456 $this->user_modification_id = (int) $res['fk_user_modif'];
457
458 // Retrieve all extrafield
459 // fetch optionals attributes and labels
460 $this->fetch_optionals();
461
462 $this->db->free($resql);
463
464 // multilangs
465 if (getDolGlobalInt('MAIN_MULTILANGS')) {
466 $this->getMultiLangs();
467 }
468
469 return 1;
470 } else {
471 $this->error = "No category found";
472 return 0;
473 }
474 } else {
475 dol_print_error($this->db);
476 $this->error = $this->db->lasterror;
477 $this->errors[] = $this->db->lasterror;
478 return -1;
479 }
480 }
481
492 public function create($user, $notrigger = 0)
493 {
494 global $conf, $langs;
495 $langs->load('categories');
496
497 $type = $this->type;
498
499 if (!is_numeric($type)) {
500 $type = $this->MAP_ID[$type];
501 }
502
503 $error = 0;
504
505 dol_syslog(get_class($this).'::create', LOG_DEBUG);
506
507 // Clean parameters
508 $this->label = trim($this->label);
509 $this->description = trim($this->description);
510 $this->color = trim($this->color);
511 $this->position = (int) $this->position;
512 if (isset($this->import_key)) {
513 $this->import_key = trim($this->import_key);
514 }
515 $this->ref_ext = trim($this->ref_ext);
516 if (empty($this->visible)) {
517 $this->visible = 0;
518 }
519 $this->fk_parent = ($this->fk_parent != "" ? intval($this->fk_parent) : 0);
520
521 if ($this->already_exists()) {
522 $this->error = $langs->trans("ImpossibleAddCat", $this->label);
523 $this->error .= " : ".$langs->trans("CategoryExistsAtSameLevel");
524 dol_syslog($this->error, LOG_WARNING);
525 return -4;
526 }
527
528 $this->db->begin();
529 $now = dol_now();
530 $sql = "INSERT INTO ".MAIN_DB_PREFIX."categorie (";
531 $sql .= "fk_parent,";
532 $sql .= " label,";
533 $sql .= " description,";
534 $sql .= " color,";
535 $sql .= " position,";
536 if (getDolGlobalString('CATEGORY_ASSIGNED_TO_A_CUSTOMER')) {
537 $sql .= "fk_soc,";
538 }
539 $sql .= " visible,";
540 $sql .= " type,";
541 $sql .= " import_key,";
542 $sql .= " ref_ext,";
543 $sql .= " entity,";
544 $sql .= " date_creation,";
545 $sql .= " fk_user_creat";
546 $sql .= ") VALUES (";
547 $sql .= (int) $this->fk_parent.",";
548 $sql .= "'".$this->db->escape($this->label)."', ";
549 $sql .= "'".$this->db->escape($this->description)."', ";
550 $sql .= "'".$this->db->escape($this->color)."', ";
551 $sql .= (int) $this->position.",";
552 if (getDolGlobalString('CATEGORY_ASSIGNED_TO_A_CUSTOMER')) {
553 $sql .= ($this->socid > 0 ? $this->socid : 'null').", ";
554 }
555 $sql .= "'".$this->db->escape($this->visible)."', ";
556 $sql .= ((int) $type).", ";
557 $sql .= (!empty($this->import_key) ? "'".$this->db->escape($this->import_key)."'" : 'null').", ";
558 $sql .= (!empty($this->ref_ext) ? "'".$this->db->escape($this->ref_ext)."'" : 'null').", ";
559 $sql .= (int) $conf->entity.", ";
560 $sql .= "'".$this->db->idate($now)."', ";
561 $sql .= (int) $user->id;
562 $sql .= ")";
563
564 $res = $this->db->query($sql);
565 if ($res) {
566 $id = $this->db->last_insert_id(MAIN_DB_PREFIX."categorie");
567
568 if ($id > 0) {
569 $this->id = $id;
570
571 $action = 'create';
572
573 // Actions on extra fields
574 if (!$error) {
575 $result = $this->insertExtraFields();
576 if ($result < 0) {
577 $error++;
578 }
579 }
580
581 if (!$error && !$notrigger) {
582 // Call trigger
583 $result = $this->call_trigger('CATEGORY_CREATE', $user);
584 if ($result < 0) {
585 $error++;
586 }
587 // End call triggers
588 }
589
590 if (!$error) {
591 $this->db->commit();
592 return $id;
593 } else {
594 $this->db->rollback();
595 return -3;
596 }
597 } else {
598 $this->db->rollback();
599 return -2;
600 }
601 } else {
602 $this->error = $this->db->error();
603 $this->db->rollback();
604 return -1;
605 }
606 }
607
617 public function update(User $user, $notrigger = 0)
618 {
619 global $langs;
620
621 $error = 0;
622
623 // Clean parameters
624 $this->label = trim($this->label);
625 $this->description = trim($this->description);
626 $this->ref_ext = trim($this->ref_ext);
627 $this->fk_parent = ($this->fk_parent != "" ? intval($this->fk_parent) : 0);
628 $this->visible = ($this->visible != "" ? intval($this->visible) : 0);
629
630 if ($this->already_exists()) {
631 $this->error = $langs->trans("ImpossibleUpdateCat");
632 $this->error .= " : ".$langs->trans("CategoryExistsAtSameLevel");
633 return -1;
634 }
635
636 $this->db->begin();
637
638 $sql = "UPDATE ".MAIN_DB_PREFIX."categorie";
639 $sql .= " SET label = '".$this->db->escape($this->label)."',";
640 $sql .= " description = '".$this->db->escape($this->description)."',";
641 $sql .= " ref_ext = '".$this->db->escape($this->ref_ext)."',";
642 $sql .= " color = '".$this->db->escape($this->color)."'";
643 $sql .= ", position = ".(int) $this->position;
644 if (getDolGlobalString('CATEGORY_ASSIGNED_TO_A_CUSTOMER')) {
645 $sql .= ", fk_soc = ".($this->socid > 0 ? $this->socid : 'null');
646 }
647 $sql .= ", visible = ".(int) $this->visible;
648 $sql .= ", fk_parent = ".(int) $this->fk_parent;
649 $sql .= ", fk_user_modif = ".(int) $user->id;
650 $sql .= " WHERE rowid = ".((int) $this->id);
651
652 dol_syslog(get_class($this)."::update", LOG_DEBUG);
653 if ($this->db->query($sql)) {
654 $action = 'update';
655
656 // Actions on extra fields
657 if (!$error) {
658 $result = $this->insertExtraFields();
659 if ($result < 0) {
660 $error++;
661 }
662 }
663
664 if (!$error && !$notrigger) {
665 // Call trigger
666 $result = $this->call_trigger('CATEGORY_MODIFY', $user);
667 if ($result < 0) {
668 $error++;
669 }
670 // End call triggers
671 }
672
673 if (!$error) {
674 $this->db->commit();
675 return 1;
676 } else {
677 $this->db->rollback();
678 return -1;
679 }
680 } else {
681 $this->db->rollback();
682 dol_print_error($this->db);
683 return -1;
684 }
685 }
686
694 public function delete($user, $notrigger = 0)
695 {
696 $error = 0;
697
698 // Clean parameters
699 $this->fk_parent = ($this->fk_parent != "" ? intval($this->fk_parent) : 0);
700
701 dol_syslog(get_class($this)."::remove");
702
703 $this->db->begin();
704
705 if (!$error && !$notrigger) {
706 // Call trigger
707 $result = $this->call_trigger('CATEGORY_DELETE', $user);
708 if ($result < 0) {
709 $error++;
710 }
711 // End call triggers
712 }
713
714 /* FIX #1317 : Check for child category and move up 1 level*/
715 if (!$error) {
716 $sql = "UPDATE ".MAIN_DB_PREFIX."categorie";
717 $sql .= " SET fk_parent = ".((int) $this->fk_parent);
718 $sql .= " WHERE fk_parent = ".((int) $this->id);
719
720 if (!$this->db->query($sql)) {
721 $this->error = $this->db->lasterror();
722 $error++;
723 }
724 }
725
726 $arraydelete = array(
727 'categorie_account' => 'fk_categorie',
728 'categorie_actioncomm' => 'fk_categorie',
729 'categorie_contact' => 'fk_categorie',
730 'categorie_fournisseur' => 'fk_categorie',
731 'categorie_knowledgemanagement' => array('field' => 'fk_categorie', 'enabled' => isModEnabled('knowledgemanagement')),
732 'categorie_fichinter' => array('field' => 'fk_categorie', 'enabled' => false ), // not yet fully implemented (wait 22) isModEnabled('intervention')),
733 'categorie_member' => 'fk_categorie',
734 'categorie_user' => 'fk_categorie',
735 'categorie_product' => 'fk_categorie',
736 'categorie_project' => 'fk_categorie',
737 'categorie_societe' => 'fk_categorie',
738 'categorie_ticket' => array('field' => 'fk_categorie', 'enabled' => isModEnabled('ticket')),
739 'categorie_warehouse' => 'fk_categorie',
740 'categorie_website_page' => array('field' => 'fk_categorie', 'enabled' => isModEnabled('website')),
741 'category_bankline' => 'fk_categ',
742 'categorie_lang' => 'fk_category',
743 'categorie' => 'rowid',
744 );
745 foreach ($arraydelete as $key => $value) {
746 if (is_array($value)) {
747 if (empty($value['enabled'])) {
748 continue;
749 }
750 $value = $value['field'];
751 }
752 $sql = "DELETE FROM ".MAIN_DB_PREFIX.$key;
753 $sql .= " WHERE ".$value." = ".((int) $this->id);
754 if (!$this->db->query($sql)) {
755 $this->errors[] = $this->db->lasterror();
756 dol_syslog("Error sql=".$sql." ".$this->error, LOG_ERR);
757 $error++;
758 }
759 }
760
761 // Removed extrafields
762 if (!$error) {
763 $result = $this->deleteExtraFields();
764 if ($result < 0) {
765 $error++;
766 dol_syslog(get_class($this)."::delete erreur ".$this->error, LOG_ERR);
767 }
768 }
769
770 if (!$error) {
771 $this->db->commit();
772 return 1;
773 } else {
774 $this->db->rollback();
775 return -1;
776 }
777 }
778
779 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
788 public function add_type($obj, $type = '')
789 {
790 // phpcs:enable
791 global $user;
792
793 $error = 0;
794
795 if ($this->id == -1) {
796 return -2;
797 }
798
799 if (empty($type)) {
800 $type = $obj->element;
801 }
802
803 dol_syslog(get_class($this).'::add_type', LOG_DEBUG);
804
805 $this->db->begin();
806
807 $sql = "INSERT INTO ".MAIN_DB_PREFIX."categorie_".(empty($this->MAP_CAT_TABLE[$type]) ? $type : $this->MAP_CAT_TABLE[$type]);
808 $sql .= " (fk_categorie, fk_".(empty($this->MAP_CAT_FK[$type]) ? $type : $this->MAP_CAT_FK[$type]).")";
809 $sql .= " VALUES (".((int) $this->id).", ".((int) $obj->id).")";
810
811 if ($this->db->query($sql)) {
812 if (getDolGlobalString('CATEGORIE_RECURSIV_ADD')) {
813 $sql = 'SELECT fk_parent FROM '.MAIN_DB_PREFIX.'categorie';
814 $sql .= " WHERE rowid = ".((int) $this->id);
815
816 dol_syslog(get_class($this)."::add_type", LOG_DEBUG);
817 $resql = $this->db->query($sql);
818 if ($resql) {
819 if ($this->db->num_rows($resql) > 0) {
820 $objparent = $this->db->fetch_object($resql);
821
822 if (!empty($objparent->fk_parent)) {
823 $cat = new Categorie($this->db);
824 $cat->id = $objparent->fk_parent;
825 if (!$cat->containsObject($type, $obj->id)) {
826 $result = $cat->add_type($obj, $type);
827 if ($result < 0) {
828 $this->error = $cat->error;
829 $error++;
830 }
831 }
832 }
833 }
834 } else {
835 $error++;
836 $this->error = $this->db->lasterror();
837 }
838
839 if ($error) {
840 $this->db->rollback();
841 return -1;
842 }
843 }
844
845 // Call trigger
846 $this->context = array('linkto' => $obj); // Save object we want to link category to into category instance to provide information to trigger
847 $result = $this->call_trigger('CATEGORY_MODIFY', $user);
848 if ($result < 0) {
849 $error++;
850 }
851 // End call triggers
852
853 if (!$error) {
854 $this->db->commit();
855 return 1;
856 } else {
857 $this->db->rollback();
858 return -2;
859 }
860 } else {
861 $this->db->rollback();
862 if ($this->db->lasterrno() == 'DB_ERROR_RECORD_ALREADY_EXISTS') {
863 $this->error = $this->db->lasterrno();
864 return -3;
865 } else {
866 $this->error = $this->db->lasterror();
867 }
868 return -1;
869 }
870 }
871
872 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
881 public function del_type($obj, $type)
882 {
883 // phpcs:enable
884 global $user;
885
886 $error = 0;
887
888 // For backward compatibility
889 if ($type == 'societe') {
890 $type = 'customer';
891 dol_syslog(get_class($this)."::del_type(): type 'societe' is deprecated, please use 'customer' instead", LOG_WARNING);
892 } elseif ($type == 'fournisseur') {
893 $type = 'supplier';
894 dol_syslog(get_class($this)."::del_type(): type 'fournisseur' is deprecated, please use 'supplier' instead", LOG_WARNING);
895 }
896
897 $this->db->begin();
898
899 $sql = "DELETE FROM ".MAIN_DB_PREFIX."categorie_".(empty($this->MAP_CAT_TABLE[$type]) ? $type : $this->MAP_CAT_TABLE[$type]);
900 $sql .= " WHERE fk_categorie = ".((int) $this->id);
901 $sql .= " AND fk_".(empty($this->MAP_CAT_FK[$type]) ? $type : $this->MAP_CAT_FK[$type])." = ".((int) $obj->id);
902
903 dol_syslog(get_class($this).'::del_type', LOG_DEBUG);
904 if ($this->db->query($sql)) {
905 // Call trigger
906 $this->context = array('unlinkoff' => $obj); // Save object we want to link category to into category instance to provide information to trigger
907 $result = $this->call_trigger('CATEGORY_MODIFY', $user);
908 if ($result < 0) {
909 $error++;
910 }
911 // End call triggers
912
913 if (!$error) {
914 $this->db->commit();
915 return 1;
916 } else {
917 $this->db->rollback();
918 return -2;
919 }
920 } else {
921 $this->db->rollback();
922 $this->error = $this->db->lasterror();
923 return -1;
924 }
925 }
926
944 public function getObjectsInCateg($type, $onlyids = 0, $limit = 0, $offset = 0, $sortfield = '', $sortorder = 'ASC', $filter = '', $filtermode = 'AND', $filterlang = '')
945 {
946 global $user;
947
948 $objs = array();
949
950 $classnameforobj = $this->MAP_OBJ_CLASS[$type];
951 $obj = new $classnameforobj($this->db);
952
953 $sql = "SELECT c.fk_".(empty($this->MAP_CAT_FK[$type]) ? $type : $this->MAP_CAT_FK[$type])." as fk_object";
954 $sql .= " FROM ".MAIN_DB_PREFIX."categorie_".(empty($this->MAP_CAT_TABLE[$type]) ? $type : $this->MAP_CAT_TABLE[$type])." as c";
955 $sql .= ", ".MAIN_DB_PREFIX.(empty($this->MAP_OBJ_TABLE[$type]) ? $type : $this->MAP_OBJ_TABLE[$type])." as o";
956 if (!empty($filterlang)) {
957 $sql .= ", ".MAIN_DB_PREFIX.(empty($this->MAP_OBJ_TABLE[$type]) ? $type : $this->MAP_OBJ_TABLE[$type])."_lang as ol";
958 }
959 $sql .= " WHERE o.entity IN (".getEntity($obj->element).")";
960 $sql .= " AND c.fk_categorie = ".((int) $this->id);
961 // Compatibility with actioncomm table which has id instead of rowid
962 if ((array_key_exists($type, $this->MAP_OBJ_TABLE) && $this->MAP_OBJ_TABLE[$type] == "actioncomm") || $type == "actioncomm") {
963 $sql .= " AND c.fk_".(empty($this->MAP_CAT_FK[$type]) ? $type : $this->MAP_CAT_FK[$type])." = o.id";
964 } else {
965 $sql .= " AND c.fk_".(empty($this->MAP_CAT_FK[$type]) ? $type : $this->MAP_CAT_FK[$type])." = o.rowid";
966 }
967 if (!empty($filterlang)) {
968 $sql .= " AND ol.fk_".(empty($this->MAP_OBJ_TABLE[$type]) ? $type : $this->MAP_OBJ_TABLE[$type])." = o.rowid";
969 $sql .= " AND ol.lang = '".$this->db->escape($filterlang)."'";
970 }
971 // Protection for external users
972 if (($type == 'customer' || $type == 'supplier') && $user->socid > 0) {
973 $sql .= " AND o.rowid = ".((int) $user->socid);
974 }
975
976 $errormessage = '';
977 $sql .= forgeSQLFromUniversalSearchCriteria($filter, $errormessage);
978 if ($errormessage) {
979 $this->errors[] = $errormessage;
980 dol_syslog(__METHOD__.' '.implode(',', $this->errors), LOG_ERR);
981 return -1;
982 }
983
984 $sql .= $this->db->order($sortfield, $sortorder);
985 if ($limit > 0 || $offset > 0) {
986 $sql .= $this->db->plimit($limit + 1, $offset);
987 }
988
989 dol_syslog(get_class($this)."::getObjectsInCateg", LOG_DEBUG);
990
991 $resql = $this->db->query($sql);
992 if ($resql) {
993 while ($rec = $this->db->fetch_array($resql)) {
994 if ($onlyids) {
995 $objs[] = $rec['fk_object'];
996 } else {
997 $classnameforobj = $this->MAP_OBJ_CLASS[$type];
998
999 $obj = new $classnameforobj($this->db);
1000 $obj->fetch($rec['fk_object']);
1001 if ($obj->id > 0) { // Failing fetch may happen for example when a category supplier was set and third party was moved as customer only. The object supplier can't be loaded.
1002 $objs[] = $obj;
1003 }
1004 }
1005 }
1006 return $objs;
1007 } else {
1008 $this->error = $this->db->error().' sql='.$sql;
1009 return -1;
1010 }
1011 }
1012
1021 public function containsObject($type, $object_id)
1022 {
1023 $sql = "SELECT COUNT(*) as nb FROM ".MAIN_DB_PREFIX."categorie_".(empty($this->MAP_CAT_TABLE[$type]) ? $type : $this->MAP_CAT_TABLE[$type]);
1024 $sql .= " WHERE fk_categorie = ".((int) $this->id)." AND fk_".(empty($this->MAP_CAT_FK[$type]) ? $type : $this->MAP_CAT_FK[$type])." = ".((int) $object_id);
1025
1026 dol_syslog(get_class($this)."::containsObject", LOG_DEBUG);
1027
1028 $resql = $this->db->query($sql);
1029 if ($resql) {
1030 return $this->db->fetch_object($resql)->nb;
1031 } else {
1032 $this->error = $this->db->error();
1033 return -1;
1034 }
1035 }
1036
1049 public function getListForItem($id, $type = 'customer', $sortfield = "s.rowid", $sortorder = 'ASC', $limit = 0, $page = 0)
1050 {
1051 $categories = array();
1052
1053 $type = sanitizeVal($type, 'aZ09');
1054
1055 $sub_type = $type;
1056 $subcol_name = "fk_".$type;
1057 if ($type == "customer") {
1058 $sub_type = "societe";
1059 $subcol_name = "fk_soc";
1060 }
1061 if ($type == "supplier") {
1062 $sub_type = "fournisseur";
1063 $subcol_name = "fk_soc";
1064 }
1065 if ($type == "contact") {
1066 $subcol_name = "fk_socpeople";
1067 }
1068
1069 $idoftype = array_search($type, self::$MAP_ID_TO_CODE);
1070
1071 $sql = "SELECT s.rowid";
1072 $sqlfields = $sql; // $sql fields to remove for count total
1073 $sql .= " FROM ".MAIN_DB_PREFIX."categorie as s, ".MAIN_DB_PREFIX."categorie_".$sub_type." as sub";
1074 $sql .= ' WHERE s.entity IN ('.getEntity('category').')';
1075 $sql .= ' AND s.type = '.((int) $idoftype);
1076 $sql .= ' AND s.rowid = sub.fk_categorie';
1077 $sql .= " AND sub.".$subcol_name." = ".((int) $id);
1078
1079 $offset = 0;
1080 $nbtotalofrecords = '';
1081 if (!getDolGlobalInt('MAIN_DISABLE_FULL_SCANLIST')) {
1082 $sqlforcount = preg_replace('/^'.preg_quote($sqlfields, '/').'/', 'SELECT COUNT(*) as nbtotalofrecords', $sql);
1083 $sqlforcount = preg_replace('/GROUP BY .*$/', '', $sqlforcount);
1084
1085 $resql = $this->db->query($sqlforcount);
1086 if ($resql) {
1087 $objforcount = $this->db->fetch_object($resql);
1088 $nbtotalofrecords = $objforcount->nbtotalofrecords;
1089 } else {
1090 dol_print_error($this->db);
1091 }
1092
1093 if (($page * $limit) > $nbtotalofrecords) { // if total resultset is smaller then paging size (filtering), goto and load page 0
1094 $page = 0;
1095 $offset = 0;
1096 }
1097 $this->db->free($resql);
1098 }
1099
1100 $sql .= $this->db->order($sortfield, $sortorder);
1101 if ($limit) {
1102 if ($page < 0) {
1103 $page = 0;
1104 }
1105 $offset = $limit * $page;
1106
1107 $sql .= $this->db->plimit($limit + 1, $offset);
1108 }
1109
1110 $result = $this->db->query($sql);
1111 if ($result) {
1112 $i = 0;
1113 $num = $this->db->num_rows($result);
1114 $min = min($num, ($limit <= 0 ? $num : $limit));
1115 while ($i < $min) {
1116 $obj = $this->db->fetch_object($result);
1117 $category_static = new Categorie($this->db);
1118 if ($category_static->fetch($obj->rowid)) {
1119 $categories[$i]['id'] = $category_static->id;
1120 $categories[$i]['fk_parent'] = $category_static->fk_parent;
1121 $categories[$i]['label'] = $category_static->label;
1122 $categories[$i]['description'] = $category_static->description;
1123 $categories[$i]['color'] = $category_static->color;
1124 $categories[$i]['position'] = $category_static->position;
1125 $categories[$i]['socid'] = $category_static->socid;
1126 $categories[$i]['ref_ext'] = $category_static->ref_ext;
1127 $categories[$i]['visible'] = $category_static->visible;
1128 $categories[$i]['type'] = $category_static->type;
1129 $categories[$i]['entity'] = $category_static->entity;
1130 $categories[$i]['array_options'] = $category_static->array_options;
1131
1132 // multilangs
1133 if (getDolGlobalInt('MAIN_MULTILANGS') && isset($category_static->multilangs)) {
1134 $categories[$i]['multilangs'] = $category_static->multilangs;
1135 }
1136 }
1137 $i++;
1138 }
1139 } else {
1140 $this->error = $this->db->lasterror();
1141 return -1;
1142 }
1143 if (!count($categories)) {
1144 return [];
1145 }
1146
1147 return $categories;
1148 }
1149
1150 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1156 public function get_filles()
1157 {
1158 // phpcs:enable
1159 $sql = "SELECT rowid FROM ".MAIN_DB_PREFIX."categorie";
1160 $sql .= " WHERE fk_parent = ".((int) $this->id);
1161 $sql .= " AND entity IN (".getEntity('category').")";
1162
1163 $res = $this->db->query($sql);
1164 if ($res) {
1165 $cats = array();
1166 while ($rec = $this->db->fetch_array($res)) {
1167 $cat = new Categorie($this->db);
1168 $cat->fetch($rec['rowid']);
1169 $cats[] = $cat;
1170 }
1171 return $cats;
1172 } else {
1173 dol_print_error($this->db);
1174 return -1;
1175 }
1176 }
1177
1178 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1184 protected function load_motherof()
1185 {
1186 // phpcs:enable
1187 $this->motherof = array();
1188
1189 // Load array[child]=parent
1190 $sql = "SELECT fk_parent as id_parent, rowid as id_son";
1191 $sql .= " FROM ".MAIN_DB_PREFIX."categorie";
1192 $sql .= " WHERE fk_parent != 0";
1193 $sql .= " AND entity IN (".getEntity('category').")";
1194
1195 dol_syslog(get_class($this)."::load_motherof", LOG_DEBUG);
1196 $resql = $this->db->query($sql);
1197 if ($resql) {
1198 while ($obj = $this->db->fetch_object($resql)) {
1199 $this->motherof[$obj->id_son] = $obj->id_parent;
1200 }
1201 return 1;
1202 } else {
1203 dol_print_error($this->db);
1204 return -1;
1205 }
1206 }
1207
1208 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1229 public function get_full_arbo($type, $fromid = 0, $include = 0, $forcelangcode = '')
1230 {
1231 // phpcs:enable
1232 global $langs;
1233
1234 if (!is_numeric($type)) {
1235 $type = $this->MAP_ID[$type];
1236 }
1237 if (is_null($type)) {
1238 $this->error = 'BadValueForParameterType';
1239 return -1;
1240 }
1241
1242 if (is_string($fromid)) {
1243 $fromid = explode(',', $fromid);
1244 } elseif (is_numeric($fromid)) {
1245 if ($fromid > 0) {
1246 $fromid = array($fromid);
1247 } else {
1248 $fromid = array();
1249 }
1250 } elseif (!is_array($fromid)) {
1251 $fromid = array();
1252 }
1253
1254 $this->cats = array();
1255 $nbcateg = 0;
1256
1257 // Init this->motherof that is array(id_son=>id_parent, ...)
1258 $this->load_motherof();
1259
1260 if ($forcelangcode) {
1261 $current_lang = $forcelangcode;
1262 } else {
1263 $current_lang = $langs->getDefaultLang();
1264 }
1265
1266 // Init $this->cats array
1267 $sql = "SELECT DISTINCT c.rowid, c.label, c.ref_ext, c.description, c.color, c.position, c.fk_parent, c.visible"; // Distinct reduce pb with old tables with duplicates
1268 if (getDolGlobalInt('MAIN_MULTILANGS') && $current_lang !== 'none') {
1269 $sql .= ", t.label as label_trans, t.description as description_trans";
1270 }
1271 $sql .= " FROM ".MAIN_DB_PREFIX."categorie as c";
1272 if (getDolGlobalInt('MAIN_MULTILANGS') && $current_lang !== 'none') {
1273 $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."categorie_lang as t ON t.fk_category = c.rowid AND t.lang = '".$this->db->escape($current_lang)."'";
1274 }
1275 $sql .= " WHERE c.entity IN (".getEntity('category').")";
1276 $sql .= " AND c.type = ".(int) $type;
1277
1278 dol_syslog(get_class($this)."::get_full_arbo get category list", LOG_DEBUG);
1279 $resql = $this->db->query($sql);
1280 if ($resql) {
1281 $i = 0;
1282 $nbcateg = $this->db->num_rows($resql);
1283
1284 while ($obj = $this->db->fetch_object($resql)) {
1285 $this->cats[$obj->rowid]['rowid'] = $obj->rowid;
1286 $this->cats[$obj->rowid]['id'] = $obj->rowid;
1287 $this->cats[$obj->rowid]['fk_parent'] = $obj->fk_parent;
1288 $this->cats[$obj->rowid]['label'] = !empty($obj->label_trans) ? $obj->label_trans : $obj->label;
1289 $this->cats[$obj->rowid]['description'] = !empty($obj->description_trans) ? $obj->description_trans : $obj->description;
1290 $this->cats[$obj->rowid]['color'] = $obj->color;
1291 $this->cats[$obj->rowid]['position'] = $obj->position;
1292 $this->cats[$obj->rowid]['visible'] = $obj->visible;
1293 $this->cats[$obj->rowid]['ref_ext'] = $obj->ref_ext;
1294 $this->cats[$obj->rowid]['picto'] = 'category';
1295 // fields are filled with buildPathFromId
1296 $this->cats[$obj->rowid]['fullpath'] = '';
1297 $this->cats[$obj->rowid]['fulllabel'] = '';
1298 $i++;
1299 }
1300 } else {
1301 dol_print_error($this->db);
1302 return -1;
1303 }
1304
1305 // We add the fullpath property to each elements of first level (no parent exists)
1306 dol_syslog(get_class($this)."::get_full_arbo call to buildPathFromId", LOG_DEBUG);
1307
1308 foreach ($this->cats as $key => $val) {
1309 //print 'key='.$key.'<br>'."\n";
1310 $this->buildPathFromId($key, $nbcateg); // Process a branch from the root category key (this category has no parent) and adds level to $this->cats items
1311 }
1312
1313 // Include or exclude leaf (including $fromid) from tree
1314 if (count($fromid) > 0) {
1315 $keyfiltercatid = '('.implode('|', $fromid).')';
1316
1317 //print "Look to discard category ".$fromid."\n";
1318 $keyfilter1 = '^'.$keyfiltercatid.'$';
1319 $keyfilter2 = '_'.$keyfiltercatid.'$';
1320 $keyfilter3 = '^'.$keyfiltercatid.'_';
1321 $keyfilter4 = '_'.$keyfiltercatid.'_';
1322 foreach (array_keys($this->cats) as $key) {
1323 $fullpath = (string) $this->cats[$key]['fullpath'];
1324 $test = (preg_match('/'.$keyfilter1.'/', $fullpath) || preg_match('/'.$keyfilter2.'/', $fullpath)
1325 || preg_match('/'.$keyfilter3.'/', $fullpath) || preg_match('/'.$keyfilter4.'/', $fullpath));
1326
1327 if (($test && !$include) || (!$test && $include)) {
1328 unset($this->cats[$key]); // @phpstan-ignore-line
1329 }
1330 }
1331 }
1332
1333 dol_syslog(get_class($this)."::get_full_arbo dol_sort_array", LOG_DEBUG);
1334
1335 $this->cats = dol_sort_array($this->cats, 'fulllabel', 'asc', 1, 0, 1); // Sort on full label like "Label 1 >> Sublabel a >> Subsublabel"
1336
1337 return $this->cats;
1338 }
1339
1350 private function buildPathFromId($id_categ, $protection = 1000)
1351 {
1352 //dol_syslog(get_class($this)."::buildPathFromId id_categ=".$id_categ." protection=".$protection, LOG_DEBUG);
1353
1354 if (!empty($this->cats[$id_categ]['fullpath'])) {
1355 // Already defined
1356 dol_syslog(get_class($this)."::buildPathFromId fullpath and fulllabel already defined", LOG_WARNING);
1357 return -1;
1358 }
1359
1360 // $this->cats[$id_categ] is supposed to be already an array. We just want to complete it with property fullpath and fulllabel
1361
1362 // Define fullpath and fulllabel
1363 $this->cats[$id_categ]['fullpath'] = '_'.$id_categ;
1364 $this->cats[$id_categ]['fulllabel'] = $this->cats[$id_categ]['label'];
1365 $i = 0;
1366 $cursor_categ = $id_categ;
1367 //print 'Work for id_categ='.$id_categ.'<br>'."\n";
1368 while ((empty($protection) || $i < $protection) && !empty($this->motherof[$cursor_categ])) {
1369 //print '&nbsp; cursor_categ='.$cursor_categ.' i='.$i.' '.$this->motherof[$cursor_categ].'<br>'."\n";
1370 $this->cats[$id_categ]['fullpath'] = '_'.$this->motherof[$cursor_categ].$this->cats[$id_categ]['fullpath'];
1371 $this->cats[$id_categ]['fulllabel'] = (empty($this->cats[$this->motherof[$cursor_categ]]) ? 'NotFound' : $this->cats[$this->motherof[$cursor_categ]]['label']).' >> '.$this->cats[$id_categ]['fulllabel'];
1372 //print '&nbsp; Result for id_categ='.$id_categ.' : '.$this->cats[$id_categ]['fullpath'].' '.$this->cats[$id_categ]['fulllabel'].'<br>'."\n";
1373 $i++;
1374 $cursor_categ = $this->motherof[$cursor_categ];
1375 }
1376 //print 'Result for id_categ='.$id_categ.' : '.$this->cats[$id_categ]['fullpath'].'<br>'."\n";
1377
1378 // We count number of _ to have level
1379 $nbunderscore = substr_count($this->cats[$id_categ]['fullpath'], '_');
1380 $this->cats[$id_categ]['level'] = ($nbunderscore ? $nbunderscore : null);
1381
1382 return 1;
1383 }
1384
1385
1386 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1394 public function get_all_categories($type = null, $parent = false)
1395 {
1396 // phpcs:enable
1397 if (!is_numeric($type) && !is_null($type)) {
1398 $type = $this->MAP_ID[$type];
1399 }
1400
1401 $sql = "SELECT rowid FROM ".MAIN_DB_PREFIX."categorie";
1402 $sql .= " WHERE entity IN (".getEntity('category').")";
1403 if (!is_null($type)) {
1404 $sql .= " AND type = ".(int) $type;
1405 }
1406 if ($parent) {
1407 $sql .= " AND fk_parent = 0";
1408 }
1409
1410 $res = $this->db->query($sql);
1411 if ($res) {
1412 $cats = array();
1413 while ($rec = $this->db->fetch_array($res)) {
1414 $cat = new Categorie($this->db);
1415 $cat->fetch($rec['rowid']);
1416 $cats[$rec['rowid']] = $cat;
1417 }
1418 return $cats;
1419 } else {
1420 dol_print_error($this->db);
1421 return -1;
1422 }
1423 }
1424
1425 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1432 public function get_main_categories($type = null)
1433 {
1434 // phpcs:enable
1435 return $this->get_all_categories($type, true);
1436 }
1437
1438 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1444 public function already_exists()
1445 {
1446 // phpcs:enable
1447 $type = $this->type;
1448
1449 if (!is_numeric($type)) {
1450 $type = $this->MAP_ID[$type];
1451 }
1452
1453 /* We have to select any rowid from llx_categorie which category's mother and label
1454 * are equals to those of the calling category
1455 */
1456 $sql = "SELECT c.rowid";
1457 $sql .= " FROM ".MAIN_DB_PREFIX."categorie as c ";
1458 $sql .= " WHERE c.entity IN (".getEntity('category').")";
1459 $sql .= " AND c.type = ".((int) $type);
1460 $sql .= " AND c.fk_parent = ".((int) $this->fk_parent);
1461 $sql .= " AND c.label = '".$this->db->escape($this->label)."'";
1462
1463 dol_syslog(get_class($this)."::already_exists", LOG_DEBUG);
1464
1465 $resql = $this->db->query($sql);
1466 if ($resql) {
1467 if ($this->db->num_rows($resql) > 0) { // Checking for empty resql
1468 $obj = $this->db->fetch_object($resql);
1469 /* If object called create, obj cannot have is id.
1470 * If object called update, he mustn't have the same label as an other category for this mother.
1471 * So if the result has the same id, update is not for label, and if result has an other one, update may be for label.
1472 */
1473 if (!empty($obj) && $obj->rowid > 0 && $obj->rowid != $this->id) {
1474 dol_syslog(get_class($this)."::already_exists category with name=".$this->label." and parent ".$this->fk_parent." exists: rowid=".$obj->rowid." current_id=".$this->id, LOG_DEBUG);
1475 return 1;
1476 }
1477 }
1478 dol_syslog(get_class($this)."::already_exists no category with same name=".$this->label." and same parent ".$this->fk_parent." than category id=".$this->id, LOG_DEBUG);
1479 return 0;
1480 } else {
1481 $this->error = $this->db->error();
1482 return -1;
1483 }
1484 }
1485
1486
1487 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1498 public function print_all_ways($sep = '&gt;&gt;', $url = '', $nocolor = 0, $addpicto = 0)
1499 {
1500 // phpcs:enable
1501 $ways = array();
1502
1503 $all_ways = $this->get_all_ways(); // Load array of categories to reach this->id
1504
1505 foreach ($all_ways as $way) { // It seems we always have 1 entry in this array.
1506 $w = array();
1507 $i = 0;
1508 $forced_color = '';
1509 foreach ($way as $cat) { // Loop on each successive categories to reach the target of current category
1510 $i++;
1511
1512 if (empty($nocolor)) {
1513 $forced_color = 'colortoreplace';
1514 if ($i == count($way)) { // Last category in hierarchy
1515 // Check contrast with background and correct text color
1516 $forced_color = 'categtextwhite'; // We want color white because the getNomUrl of a tag is always called inside a dark background like '<span color="bbb"></span>' to show it as a tag. TODO Add this in param to force when called outside of span.
1517 if ($cat->color) {
1518 if (colorIsLight($cat->color)) {
1519 $forced_color = 'categtextblack';
1520 }
1521 }
1522 }
1523 }
1524
1525 if ($url == '') {
1526 $link = '<a href="'.DOL_URL_ROOT.'/categories/viewcat.php?id='.((int) $cat->id).'&type='.urlencode($cat->type).'" class="'.($i < count($way) ? 'small ': '').$forced_color.'">';
1527 $linkend = '</a>';
1528 $w[] = $link.(($addpicto && $i == 1) ? img_object('', 'category', 'class="paddingright"') : '').$cat->label.$linkend;
1529 } elseif ($url == 'none') {
1530 $link = '<span class="'.($i < count($way) ? 'small ': '').$forced_color.'">';
1531 $linkend = '</span>';
1532 $w[] = $link.(($addpicto && $i == 1) ? img_object('', 'category', 'class="paddingright"') : '').$cat->label.$linkend;
1533 } else {
1534 $w[] = '<a class="'.($i < count($way) ? 'small ': '').$forced_color.'" href="'.DOL_URL_ROOT.'/'.$url.'?catid='.((int) $cat->id).'">'.($addpicto ? img_object('', 'category') : '').$cat->label.'</a>';
1535 }
1536 }
1537 $newcategwithpath = preg_replace('/colortoreplace/', $forced_color, implode('<span class="inline-block valignmiddle paddingleft paddingright '.$forced_color.'">'.$sep.'</span>', $w));
1538
1539 $ways[] = $newcategwithpath;
1540 }
1541
1542 return $ways;
1543 }
1544
1545
1546 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1553 public function get_meres()
1554 {
1555 // phpcs:enable
1556 $parents = array();
1557
1558 $sql = "SELECT fk_parent FROM ".MAIN_DB_PREFIX."categorie";
1559 $sql .= " WHERE rowid = ".((int) $this->id);
1560
1561 $res = $this->db->query($sql);
1562
1563 if ($res) {
1564 while ($rec = $this->db->fetch_array($res)) {
1565 if ($rec['fk_parent'] > 0) {
1566 $cat = new Categorie($this->db);
1567 $cat->fetch($rec['fk_parent']);
1568 $parents[] = $cat;
1569 }
1570 }
1571 return $parents;
1572 } else {
1573 dol_print_error($this->db);
1574 return -1;
1575 }
1576 }
1577
1578 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1585 public function get_all_ways()
1586 {
1587 // phpcs:enable
1588 $ways = array();
1589
1590 $parents = $this->get_meres();
1591 if (is_array($parents)) {
1592 foreach ($parents as $parent) {
1593 $all_ways = $parent->get_all_ways(); // recursivity. TODO Add a protection for infinite loop
1594 foreach ($all_ways as $way) {
1595 $w = $way;
1596 $w[] = $this;
1597 $ways[] = $w;
1598 }
1599 }
1600 }
1601
1602 if (count($ways) == 0) {
1603 $ways[0][0] = $this;
1604 }
1605
1606 return $ways;
1607 }
1608
1619 public function containing($id, $type, $mode = 'object')
1620 {
1621 $cats = array();
1622
1623 if (is_numeric($type)) {
1624 $type = Categorie::$MAP_ID_TO_CODE[$type];
1625 }
1626
1627 if ($type === Categorie::TYPE_BANK_LINE) { // TODO Remove this after migration of llx_category_bankline into llx_categorie_bankline
1628 // Load bank categories
1629 $sql = "SELECT c.label, c.rowid";
1630 $sql .= " FROM ".MAIN_DB_PREFIX."category_bankline as a, ".MAIN_DB_PREFIX."categorie as c";
1631 $sql .= " WHERE a.lineid=".((int) $id)." AND a.fk_categ = c.rowid";
1632 $sql .= " AND c.entity IN (".getEntity('category').")";
1633 $sql .= " ORDER BY c.label";
1634
1635 $res = $this->db->query($sql);
1636 if ($res) {
1637 while ($obj = $this->db->fetch_object($res)) {
1638 if ($mode == 'id') {
1639 $cats[] = $obj->rowid;
1640 } elseif ($mode == 'label') {
1641 $cats[] = $obj->label;
1642 } else {
1643 $cat = new Categorie($this->db);
1644 $cat->id = $obj->rowid;
1645 $cat->label = $obj->label;
1646 $cats[] = $cat;
1647 }
1648 }
1649 } else {
1650 dol_print_error($this->db);
1651 return -1;
1652 }
1653 } else {
1654 $sql = "SELECT ct.fk_categorie, c.label, c.rowid";
1655 $sql .= " FROM ".MAIN_DB_PREFIX."categorie_".(empty($this->MAP_CAT_TABLE[$type]) ? $type : $this->MAP_CAT_TABLE[$type])." as ct, ".MAIN_DB_PREFIX."categorie as c";
1656 $sql .= " WHERE ct.fk_categorie = c.rowid AND ct.fk_".(empty($this->MAP_CAT_FK[$type]) ? $type : $this->MAP_CAT_FK[$type])." = ".(int) $id;
1657 // This seems useless because the table already contains id of category of 1 unique type. So commented.
1658 // So now it works also with external added categories.
1659 //$sql .= " AND c.type = ".((int) $this->MAP_ID[$type]);
1660 $sql .= " AND c.entity IN (".getEntity('category').")";
1661
1662 $res = $this->db->query($sql);
1663 if ($res) {
1664 while ($obj = $this->db->fetch_object($res)) {
1665 if ($mode == 'id') {
1666 $cats[] = $obj->rowid;
1667 } elseif ($mode == 'label') {
1668 $cats[] = $obj->label;
1669 } else {
1670 $cat = new Categorie($this->db);
1671 $cat->fetch($obj->fk_categorie);
1672 $cats[] = $cat;
1673 }
1674 }
1675 } else {
1676 dol_print_error($this->db);
1677 return -1;
1678 }
1679 }
1680
1681 return $cats;
1682 }
1683
1695 public function rechercher($id, $nom, $type, $exact = false, $case = false)
1696 {
1697 // Deprecation warning
1698 if (is_numeric($type)) {
1699 dol_syslog(__METHOD__.': using numeric types is deprecated.', LOG_WARNING);
1700 }
1701
1702 $cats = array();
1703
1704 // For backward compatibility
1705 if (is_numeric($type)) {
1706 // We want to reverse lookup
1707 $map_type = array_flip($this->MAP_ID);
1708 $type = $map_type[$type];
1709 dol_syslog(get_class($this)."::rechercher(): numeric types are deprecated, please use string instead", LOG_WARNING);
1710 }
1711
1712 // Generation requete recherche
1713 $sql = "SELECT rowid FROM ".MAIN_DB_PREFIX."categorie";
1714 $sql .= " WHERE type = ".((int) $this->MAP_ID[$type]);
1715 $sql .= " AND entity IN (".getEntity('category').")";
1716 if ($nom) {
1717 if (!$exact) {
1718 $nom = '%'.$this->db->escape(str_replace('*', '%', $nom)).'%';
1719 }
1720 if (!$case) {
1721 $sql .= " AND label LIKE '".$this->db->escape($nom)."'";
1722 } else {
1723 $sql .= " AND label LIKE BINARY '".$this->db->escape($nom)."'";
1724 }
1725 }
1726 if ($id) {
1727 $sql .= " AND rowid = ".((int) $id);
1728 }
1729
1730 $res = $this->db->query($sql);
1731 if ($res) {
1732 while ($rec = $this->db->fetch_array($res)) {
1733 $cat = new Categorie($this->db);
1734 $cat->fetch($rec['rowid']);
1735 $cats[] = $cat;
1736 }
1737
1738 return $cats;
1739 } else {
1740 $this->error = $this->db->error().' sql='.$sql;
1741 return -1;
1742 }
1743 }
1744
1751 public function isAnyPhotoAvailable($sdir)
1752 {
1753 include_once DOL_DOCUMENT_ROOT . '/core/lib/files.lib.php';
1754 include_once DOL_DOCUMENT_ROOT . '/core/lib/images.lib.php';
1755
1756 $sdir .= '/' . get_exdir($this->id, 2, 0, 0, $this, 'category') . $this->id . "/photos/";
1757
1758 $dir_osencoded = dol_osencode($sdir);
1759 if (file_exists($dir_osencoded)) {
1760 $handle = opendir($dir_osencoded);
1761 if (is_resource($handle)) {
1762 while (($file = readdir($handle)) !== false) {
1763 if (!utf8_check($file)) {
1764 $file = mb_convert_encoding($file, 'UTF-8', 'ISO-8859-1'); // To be sure data is stored in UTF8 in memory
1765 }
1766 if (dol_is_file($sdir . $file) && image_format_supported($file) >= 0) {
1767 return true;
1768 }
1769 }
1770 }
1771 }
1772 return false;
1773 }
1774
1781 public function getTooltipContentArray($params)
1782 {
1783 global $langs;
1784
1785 $langs->load('categories');
1786
1787 $datas = [];
1788
1789 $datas['label'] = $langs->trans("ShowCategory").': '.($this->ref ? $this->ref : $this->label);
1790
1791 return $datas;
1792 }
1793
1807 public function getNomUrl($withpicto = 0, $option = '', $maxlength = 0, $moreparam = '', $notooltip = 0, $morecss = '', $save_lastsearch_value = 0)
1808 {
1809 global $conf, $langs, $hookmanager;
1810
1811 if (!empty($conf->dol_no_mouse_hover)) {
1812 $notooltip = 1; // Force disable tooltips
1813 }
1814
1815 $result = '';
1816 $params = [
1817 'id' => $this->id,
1818 'objecttype' => $this->element,
1819 'option' => $option,
1820 ];
1821 $classfortooltip = 'classfortooltip';
1822 $dataparams = '';
1823 if (getDolGlobalInt('MAIN_ENABLE_AJAX_TOOLTIP')) {
1824 $classfortooltip = 'classforajaxtooltip';
1825 $dataparams = ' data-params="'.dol_escape_htmltag(json_encode($params)).'"';
1826 $label = '';
1827 } else {
1828 $label = implode($this->getTooltipContentArray($params));
1829 }
1830
1831 $url = DOL_URL_ROOT.'/categories/viewcat.php?id='.$this->id.'&type='.$this->type.$moreparam.'&backtopage='.urlencode($_SERVER['PHP_SELF'].($moreparam ? '?'.$moreparam : ''));
1832
1833 if ($option !== 'nolink') {
1834 // Add param to save lastsearch_values or not
1835 $add_save_lastsearch_values = ($save_lastsearch_value == 1 ? 1 : 0);
1836 if ($save_lastsearch_value == -1 && isset($_SERVER["PHP_SELF"]) && preg_match('/list\.php/', $_SERVER["PHP_SELF"])) {
1837 $add_save_lastsearch_values = 1;
1838 }
1839 if ($url && $add_save_lastsearch_values) {
1840 $url .= '&save_lastsearch_values=1';
1841 }
1842 }
1843
1844 // Check contrast with background and correct text color
1845 $forced_color = 'categtextwhite'; // We want color white because the getNomUrl of a tag is always called inside a dark background like '<span color="bbb"></span>' to show it as a tag. TODO Add this in param to force when called outside of span.
1846 if ($this->color) {
1847 if (colorIsLight($this->color)) { // If color is light, we force color to dark
1848 $forced_color = 'categtextblack';
1849 }
1850 }
1851
1852 $linkclose = '';
1853 if (empty($notooltip)) {
1854 if (getDolGlobalInt('MAIN_OPTIMIZEFORTEXTBROWSER')) {
1855 $label = $langs->trans("ShowMyObject");
1856 $linkclose .= ' alt="'.dolPrintHTMLForAttribute($label).'"';
1857 }
1858 $linkclose .= ($label ? ' title="'.dolPrintHTMLForAttribute($label).'"' : ' title="tocomplete"');
1859 $linkclose .= $dataparams.' class="'.$classfortooltip.' '.$forced_color.($morecss ? ' '.$morecss : '').'"';
1860 } else {
1861 $linkclose = ' class="'.$forced_color.($morecss ? ' '.$morecss : '').'"';
1862 }
1863
1864 if ($option == 'nolink' || empty($url)) {
1865 $linkstart = '<span';
1866 } else {
1867 $linkstart = '<a href="'.$url.'"';
1868 }
1869 $linkstart .= $linkclose.'>';
1870 if ($option == 'nolink' || empty($url)) {
1871 $linkend = '</span>';
1872 } else {
1873 $linkend = '</a>';
1874 }
1875
1876 $result .= $linkstart;
1877
1878 if ($withpicto) {
1879 $result .= img_object(($notooltip ? '' : $label), ($this->picto ? $this->picto : 'generic'), ($notooltip ? (($withpicto != 2) ? 'class="paddingright"' : '') : 'class="'.(($withpicto != 2) ? 'paddingright ' : '').'"'), 0, 0, $notooltip ? 0 : 1);
1880 }
1881
1882 if ($withpicto != 2) {
1883 $result .= dol_trunc(($this->ref ? $this->ref : $this->label), $maxlength);
1884 }
1885
1886 $result .= $linkend;
1887
1888 global $action;
1889 $hookmanager->initHooks(array($this->element . 'dao'));
1890 $parameters = array('id' => $this->id, 'getnomurl' => &$result);
1891 $reshook = $hookmanager->executeHooks('getNomUrl', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks
1892 if ($reshook > 0) {
1893 $result = $hookmanager->resPrint;
1894 } else {
1895 $result .= $hookmanager->resPrint;
1896 }
1897 return $result;
1898 }
1899
1900
1901 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1909 public function add_photo($sdir, $file)
1910 {
1911 // phpcs:enable
1912 require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
1913
1914 $dir = $sdir.'/'.get_exdir($this->id, 2, 0, 0, $this, 'category').$this->id."/";
1915 $dir .= "photos/";
1916
1917 if (!file_exists($dir)) {
1918 dol_mkdir($dir);
1919 }
1920
1921 if (file_exists($dir)) {
1922 if (is_array($file['name'])) {
1923 $nbfile = count($file['name']);
1924 for ($i = 0; $i < $nbfile; $i++) {
1925 $originImage = $dir.$file['name'][$i];
1926
1927 // Cree fichier en taille origine
1928 dol_move_uploaded_file($file['tmp_name'][$i], $originImage, 1, 0, 0);
1929
1930 if (file_exists($originImage)) {
1931 // Create thumbs
1932 $this->addThumbs($originImage);
1933 }
1934 }
1935 } else {
1936 $originImage = $dir.$file['name'];
1937
1938 // Cree fichier en taille origine
1939 dol_move_uploaded_file($file['tmp_name'], $originImage, 1, 0, 0);
1940
1941 if (file_exists($originImage)) {
1942 // Create thumbs
1943 $this->addThumbs($originImage);
1944 }
1945 }
1946 }
1947 }
1948
1949 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1957 public function liste_photos($dir, $nbmax = 0)
1958 {
1959 // phpcs:enable
1960 include_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
1961
1962 $nbphoto = 0;
1963 $tabobj = array();
1964
1965 $dirthumb = $dir.'thumbs/';
1966
1967 if (file_exists($dir)) {
1968 $handle = opendir($dir);
1969 if (is_resource($handle)) {
1970 while (($file = readdir($handle)) !== false) {
1971 if (dol_is_file($dir.$file) && preg_match('/(\.jpeg|\.jpg|\.bmp|\.gif|\.png|\.tiff)$/i', $dir.$file)) {
1972 $nbphoto++;
1973 $photo = $file;
1974
1975 // On determine nom du fichier vignette
1976 $photo_vignette = '';
1977 $regs = array();
1978 if (preg_match('/(\.jpeg|\.jpg|\.bmp|\.gif|\.png|\.tiff)$/i', $photo, $regs)) {
1979 $photo_vignette = preg_replace('/'.$regs[0].'/i', '', $photo).'_small'.$regs[0];
1980 }
1981
1982 // Object
1983 $obj = array();
1984 $obj['photo'] = $photo;
1985 if ($photo_vignette && is_file($dirthumb.$photo_vignette)) {
1986 $obj['photo_vignette'] = 'thumbs/'.$photo_vignette;
1987 } else {
1988 $obj['photo_vignette'] = "";
1989 }
1990
1991 $tabobj[$nbphoto - 1] = $obj;
1992
1993 // On continue ou on arrete de boucler
1994 if ($nbmax && $nbphoto >= $nbmax) {
1995 break;
1996 }
1997 }
1998 }
1999
2000 closedir($handle);
2001 }
2002 }
2003
2004 return $tabobj;
2005 }
2006
2007 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2014 public function delete_photo($file)
2015 {
2016 // phpcs:enable
2017 require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
2018
2019 $dir = dirname($file).'/'; // Chemin du dossier contenant l'image d'origine
2020 $dirthumb = $dir.'/thumbs/'; // Chemin du dossier contenant la vignette
2021 $filename = preg_replace('/'.preg_quote($dir, '/').'/i', '', $file); // Nom du fichier
2022
2023 // On efface l'image d'origine
2024 dol_delete_file($file, 1);
2025
2026 // Si elle existe, on efface la vignette
2027 $regs = array();
2028 if (preg_match('/(\.jpeg|\.jpg|\.bmp|\.gif|\.png|\.tiff)$/i', $filename, $regs)) {
2029 $photo_vignette = preg_replace('/'.$regs[0].'/i', '', $filename).'_small'.$regs[0];
2030 if (file_exists($dirthumb.$photo_vignette)) {
2031 dol_delete_file($dirthumb.$photo_vignette, 1);
2032 }
2033 }
2034 }
2035
2036 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2043 public function get_image_size($file)
2044 {
2045 // phpcs:enable
2046 $infoImg = getimagesize($file); // Recuperation des infos de l'image
2047 $this->imgWidth = $infoImg[0]; // Largeur de l'image
2048 $this->imgHeight = $infoImg[1]; // Hauteur de l'image
2049 }
2050
2059 public function setMultiLangs(User $user, $notrigger = 0)
2060 {
2061 global $langs;
2062
2063 $langs_available = $langs->get_available_languages();
2064 $current_lang = $langs->getDefaultLang();
2065
2066 foreach ($langs_available as $key => $value) {
2067 $sql = "SELECT rowid";
2068 $sql .= " FROM ".MAIN_DB_PREFIX."categorie_lang";
2069 $sql .= " WHERE fk_category=".((int) $this->id);
2070 $sql .= " AND lang = '".$this->db->escape($key)."'";
2071
2072 $result = $this->db->query($sql);
2073
2074 if ($key == $current_lang) {
2075 $sql2 = '';
2076 if ($this->db->num_rows($result)) { // if no line in database
2077 $sql2 = "UPDATE ".MAIN_DB_PREFIX."categorie_lang";
2078 $sql2 .= " SET label = '".$this->db->escape($this->label)."',";
2079 $sql2 .= " description = '".$this->db->escape($this->description)."'";
2080 $sql2 .= " WHERE fk_category = ".((int) $this->id)." AND lang = '".$this->db->escape($key)."'";
2081 } elseif (isset($this->multilangs[$key])) {
2082 $sql2 = "INSERT INTO ".MAIN_DB_PREFIX."categorie_lang (fk_category, lang, label, description)";
2083 $sql2 .= " VALUES(".((int) $this->id).", '".$this->db->escape($key)."', '".$this->db->escape($this->label)."'";
2084 $sql2 .= ", '".$this->db->escape($this->multilangs[$key]["description"])."')";
2085 }
2086 dol_syslog(get_class($this).'::setMultiLangs', LOG_DEBUG);
2087 if ($sql2 && !$this->db->query($sql2)) {
2088 $this->error = $this->db->lasterror();
2089 return -1;
2090 }
2091 } elseif (isset($this->multilangs[$key])) {
2092 if ($this->db->num_rows($result)) { // if no line in database
2093 $sql2 = "UPDATE ".MAIN_DB_PREFIX."categorie_lang";
2094 $sql2 .= " SET label='".$this->db->escape($this->multilangs[$key]["label"])."',";
2095 $sql2 .= " description='".$this->db->escape($this->multilangs[$key]["description"])."'";
2096 $sql2 .= " WHERE fk_category=".((int) $this->id)." AND lang='".$this->db->escape($key)."'";
2097 } else {
2098 $sql2 = "INSERT INTO ".MAIN_DB_PREFIX."categorie_lang (fk_category, lang, label, description)";
2099 $sql2 .= " VALUES(".((int) $this->id).", '".$this->db->escape($key)."', '".$this->db->escape($this->multilangs[$key]["label"])."'";
2100 $sql2 .= ",'".$this->db->escape($this->multilangs[$key]["description"])."')";
2101 }
2102
2103 // on ne sauvegarde pas des champs vides
2104 if ($this->multilangs[$key]["label"] || $this->multilangs[$key]["description"] || $this->multilangs[$key]["note"]) {
2105 dol_syslog(get_class($this).'::setMultiLangs', LOG_DEBUG);
2106 }
2107 if (!$this->db->query($sql2)) {
2108 $this->error = $this->db->lasterror();
2109 return -1;
2110 }
2111 }
2112 }
2113
2114 // Call trigger
2115 if (!$notrigger) {
2116 $result = $this->call_trigger('CATEGORY_SET_MULTILANGS', $user);
2117 if ($result < 0) {
2118 $this->error = $this->db->lasterror();
2119 return -1;
2120 }
2121 }
2122 // End call triggers
2123
2124 return 1;
2125 }
2126
2135 public function delMultiLangs($langtodelete, $user)
2136 {
2137 $sql = "DELETE FROM ".$this->db->prefix()."categorie_lang";
2138 $sql .= " WHERE fk_category = ".((int) $this->id)." AND lang = '".$this->db->escape($langtodelete)."'";
2139
2140 dol_syslog(get_class($this).'::delMultiLangs', LOG_DEBUG);
2141 $result = $this->db->query($sql);
2142 if ($result) {
2143 // Call trigger
2144 $result = $this->call_trigger('CATEGORY_DEL_MULTILANGS', $user);
2145 if ($result < 0) {
2146 $this->error = $this->db->lasterror();
2147 dol_syslog(get_class($this).'::delMultiLangs error='.$this->error, LOG_ERR);
2148 return -1;
2149 }
2150 // End call triggers
2151 return 1;
2152 } else {
2153 $this->error = $this->db->lasterror();
2154 dol_syslog(get_class($this).'::delMultiLangs error='.$this->error, LOG_ERR);
2155 return -1;
2156 }
2157 }
2158
2164 public function getMultiLangs()
2165 {
2166 global $langs;
2167
2168 $current_lang = $langs->getDefaultLang();
2169
2170 $sql = "SELECT lang, label, description";
2171 $sql .= " FROM ".MAIN_DB_PREFIX."categorie_lang";
2172 $sql .= " WHERE fk_category=".((int) $this->id);
2173
2174 $result = $this->db->query($sql);
2175 if ($result) {
2176 while ($obj = $this->db->fetch_object($result)) {
2177 //print 'lang='.$obj->lang.' current='.$current_lang.'<br>';
2178 if ($obj->lang == $current_lang) { // si on a les traduct. dans la langue courante on les charge en infos principales.
2179 $this->label = $obj->label;
2180 $this->description = $obj->description;
2181 }
2182 $this->multilangs[$obj->lang]["label"] = $obj->label;
2183 $this->multilangs[$obj->lang]["description"] = $obj->description;
2184 }
2185 return 1;
2186 } else {
2187 $this->error = $langs->trans("Error")." : ".$this->db->error()." - ".$sql;
2188 return -1;
2189 }
2190 }
2191
2198 public function getLibStatut($mode)
2199 {
2200 return '';
2201 }
2202
2203
2211 public function initAsSpecimen()
2212 {
2213 dol_syslog(get_class($this)."::initAsSpecimen");
2214
2215 // Initialise parameters
2216 $this->id = 0;
2217 $this->fk_parent = 0;
2218 $this->label = 'SPECIMEN';
2219 $this->specimen = 1;
2220 $this->description = 'This is a description';
2221 $this->socid = 1;
2222 $this->type = self::TYPE_PRODUCT;
2223
2224 return 1;
2225 }
2226
2235 public static function replaceThirdparty(DoliDB $dbs, $origin_id, $dest_id)
2236 {
2237 $tables = array(
2238 'categorie_societe'
2239 );
2240
2241 return CommonObject::commonReplaceThirdparty($dbs, $origin_id, $dest_id, $tables, 1);
2242 }
2243
2252 public static function getFilterJoinQuery($type, $rowIdName)
2253 {
2254 if ($type == 'bank_account') {
2255 $type = 'account';
2256 }
2257
2258 return " LEFT JOIN ".MAIN_DB_PREFIX."categorie_".$type." as cp ON ".$rowIdName." = cp.fk_".$type;
2259 }
2260
2270 public static function getFilterSelectQuery($type, $rowIdName, $searchList)
2271 {
2272 if ($type == 'bank_account') {
2273 $type = 'account';
2274 }
2275 if ($type == 'customer') {
2276 $type = 'societe';
2277 }
2278 if ($type == 'supplier') {
2279 $type = 'fournisseur';
2280 }
2281
2282 if (empty($searchList) && !is_array($searchList)) {
2283 return "";
2284 }
2285
2286 $searchCategorySqlList = array();
2287 foreach ($searchList as $searchCategory) {
2288 if (intval($searchCategory) == -2) {
2289 $searchCategorySqlList[] = " cp.fk_categorie IS NULL";
2290 } elseif (intval($searchCategory) > 0) {
2291 $searchCategorySqlList[] = " ".$rowIdName." IN (SELECT fk_".$type." FROM ".MAIN_DB_PREFIX."categorie_".$type." WHERE fk_categorie = ".((int) $searchCategory).")";
2292 }
2293 }
2294
2295 if (!empty($searchCategorySqlList)) {
2296 return " AND (".implode(' AND ', $searchCategorySqlList).")";
2297 } else {
2298 return "";
2299 }
2300 }
2301
2307 public function countNbOfCategories()
2308 {
2309 dol_syslog(get_class($this)."::count_all_categories", LOG_DEBUG);
2310 $sql = "SELECT COUNT(rowid) FROM ".MAIN_DB_PREFIX."categorie";
2311 $sql .= " WHERE entity IN (".getEntity('category').")";
2312
2313 $res = $this->db->query($sql);
2314 if ($res) {
2315 $obj = $this->db->fetch_object($res);
2316 return $obj->count;
2317 } else {
2318 dol_print_error($this->db);
2319 return -1;
2320 }
2321 }
2322}
print $object position
Definition edit.php:204
$object ref
Definition info.php:89
Class to manage categories.
getListForItem($id, $type='customer', $sortfield="s.rowid", $sortorder='ASC', $limit=0, $page=0)
Return the list of categories of an element id.
get_image_size($file)
Load size of image file.
load_motherof()
Load the array this->motherof that is array(id_son=>id_parent, ...)
getLibStatut($mode)
Return label of contact status.
delete_photo($file)
Efface la photo de la categorie et sa vignette.
containing($id, $type, $mode='object')
Return list of categories (object instances or labels) linked to element of id $id and type $type Sho...
getTooltipContentArray($params)
getTooltipContentArray
countNbOfCategories()
Count all categories.
del_type($obj, $type)
Delete object from category.
buildPathFromId($id_categ, $protection=1000)
For category id_categ and its children available in this->cats, define property fullpath and fulllabe...
static getFilterSelectQuery($type, $rowIdName, $searchList)
Return the additional SQL SELECT query for filtering a list by a category.
delMultiLangs($langtodelete, $user)
Delete a language for this category.
create($user, $notrigger=0)
Add category into database.
rechercher($id, $nom, $type, $exact=false, $case=false)
Returns categories whose id or name matches.
getMultiLangs()
Load array this->multilangs.
getObjectsInCateg($type, $onlyids=0, $limit=0, $offset=0, $sortfield='', $sortorder='ASC', $filter='', $filtermode='AND', $filterlang='')
Return list of fetched instance of elements having this category.
isAnyPhotoAvailable($sdir)
Return if at least one photo is available.
already_exists()
Check if a category with same label already exists for this cat's parent or root and for this cat's t...
get_filles()
Return direct children ids of a category into an array.
initAsSpecimen()
Initialise an instance with random values.
get_all_categories($type=null, $parent=false)
Returns all categories.
static getFilterJoinQuery($type, $rowIdName)
Return the additional SQL JOIN query for filtering a list by a category.
containsObject($type, $object_id)
Check for the presence of an object in a category.
get_main_categories($type=null)
Returns the top level categories (which are not child)
__construct($db)
Constructor.
getMapId()
Get MAP_ID.
static replaceThirdparty(DoliDB $dbs, $origin_id, $dest_id)
Function used to replace a thirdparty id with another one.
setMultiLangs(User $user, $notrigger=0)
Create or Update translations of categories labels.
getMapList()
Get map list.
$fields
'type' if the field format ('integer', 'integer:ObjectClass:PathToClass[:AddCreateButtonOrNot[:Filter...
get_meres()
Returns an array containing the list of parent categories Note: A category can only have one parent b...
get_full_arbo($type, $fromid=0, $include=0, $forcelangcode='')
Rebuilding the category tree as an array Return an array of table('id','id_mere',....
add_type($obj, $type='')
Link an object to the category.
update(User $user, $notrigger=0)
Update category.
liste_photos($dir, $nbmax=0)
Return an array with all photos inside the directory.
get_all_ways()
Returns in a array all possible paths to go to the category starting with the major categories repres...
getNomUrl($withpicto=0, $option='', $maxlength=0, $moreparam='', $notooltip=0, $morecss='', $save_lastsearch_value=0)
Return name and link of category (with picto) Use ->id, ->ref, ->label, ->color.
print_all_ways($sep='&gt;&gt;', $url='', $nocolor=0, $addpicto=0)
Returns the path of the category, with the names of the categories separated by $sep (" >> " by defau...
add_photo($sdir, $file)
Add the image uploaded as $file to the directory $sdir/<category>-<id>/photos/.
fetch($id, $label='', $type=null, $ref_ext='')
Load category into memory from database.
Parent class of all other business classes (invoices, contracts, proposals, orders,...
fetch_optionals($rowid=null, $optionsArray=null)
Function to get extra fields of an object into $this->array_options This method is in most cases call...
deleteExtraFields()
Delete all extra fields values for the current object.
static commonReplaceThirdparty(DoliDB $dbs, $origin_id, $dest_id, array $tables, $ignoreerrors=0)
Function used to replace a thirdparty id with another one.
insertExtraFields($trigger='', $userused=null)
Add/Update all extra fields values for the current object.
call_trigger($triggerName, $user)
Call trigger based on this instance.
addThumbs($file, $quality=50)
Build thumb.
Class to manage Dolibarr database access.
Class to manage Dolibarr users.
print $script_file $mode $langs defaultlang(is_numeric($duration_value) ? " delay=". $duration_value :"").(is_numeric($duration_value2) ? " after cd cd cd description as description
Only used if Module[ID]Desc translation string is not found.
dol_delete_file($file, $disableglob=0, $nophperrors=0, $nohook=0, $object=null, $allowdotdot=false, $indexdatabase=1, $nolog=0)
Remove a file or several files with a mask.
dol_move_uploaded_file($src_file, $dest_file, $allowoverwrite, $disablevirusscan=0, $uploaderrorcode=0, $nohook=0, $varfiles='addedfile', $upload_dir='')
Check validity of a file upload from an GUI page, and move it to its final destination.
dol_is_file($pathoffile)
Return if path is a file.
dol_osencode($str)
Return a string encoded into OS filesystem encoding.
img_object($titlealt, $picto, $moreatt='', $pictoisfullpath=0, $srconly=0, $notitle=0, $allowothertags=array())
Show a picto called object_picto (generic function)
forgeSQLFromUniversalSearchCriteria($filter, &$errorstr='', $noand=0, $nopar=0, $noerror=0)
forgeSQLFromUniversalSearchCriteria
dol_now($mode='auto')
Return date for now.
getDolGlobalInt($key, $default=0)
Return a Dolibarr global constant int value.
dol_sort_array(&$array, $index, $order='asc', $natsort=0, $case_sensitive=0, $keepindex=0)
Advanced sort array by the value of a given key, which produces ascending (default) or descending out...
colorIsLight($stringcolor)
Return true if the color is light.
dol_print_error($db=null, $error='', $errors=null)
Displays error message system with all the information to facilitate the diagnosis and the escalation...
dol_trunc($string, $size=40, $trunc='right', $stringencoding='UTF-8', $nodot=0, $display=0)
Truncate a string to a particular length adding '…' if string larger than length.
getDolGlobalString($key, $default='')
Return a Dolibarr global constant string value.
sanitizeVal($out='', $check='alphanohtml', $filter=null, $options=null)
Return a sanitized or empty value after checking value against a rule.
utf8_check($str)
Check if a string is in UTF8.
get_exdir($num, $level, $alpha, $withoutslash, $object, $modulepart='')
Return a path to have a the directory according to object where files are stored.
dol_syslog($message, $level=LOG_INFO, $ident=0, $suffixinfilename='', $restricttologhandler='', $logcontext=null)
Write log message into outputs.
getEntity($element, $shared=1, $currentobject=null)
Get list of entity id to use.
dol_mkdir($dir, $dataroot='', $newmask='')
Creation of a directory (this can create recursive subdir)
image_format_supported($file, $acceptsvg=0)
Return if a filename is file name of a supported image format.
global $conf
The following vars must be defined: $type2label $form $conf, $lang, The following vars may also be de...
Definition member.php:79
if(preg_match('/crypted:/i', $dolibarr_main_db_pass)||!empty($dolibarr_main_db_encrypted_pass)) $conf db type
Definition repair.php:150