dolibarr  13.0.2
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 Charlie Benke <charlie@patas-monkey.com>
13  * Copyright (C) 2018-2019 Frédéric France <frederic.france@netlogic.fr>
14  *
15  * This program is free software; you can redistribute it and/or modify
16  * it under the terms of the GNU General Public License as published by
17  * the Free Software Foundation; either version 3 of the License, or
18  * (at your option) any later version.
19  *
20  * This program is distributed in the hope that it will be useful,
21  * but WITHOUT ANY WARRANTY; without even the implied warranty of
22  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23  * GNU General Public License for more details.
24  *
25  * You should have received a copy of the GNU General Public License
26  * along with this program. If not, see <https://www.gnu.org/licenses/>.
27  */
28 
35 require_once DOL_DOCUMENT_ROOT.'/core/class/commonobject.class.php';
36 require_once DOL_DOCUMENT_ROOT.'/product/class/product.class.php';
37 require_once DOL_DOCUMENT_ROOT.'/fourn/class/fournisseur.class.php';
38 require_once DOL_DOCUMENT_ROOT.'/contact/class/contact.class.php';
39 
40 
44 class Categorie extends CommonObject
45 {
46  // Categories types (we use string because we want to accept any modules/types in a future)
47  const TYPE_PRODUCT = 'product';
48  const TYPE_SUPPLIER = 'supplier';
49  const TYPE_CUSTOMER = 'customer';
50  const TYPE_MEMBER = 'member';
51  const TYPE_CONTACT = 'contact';
52  const TYPE_USER = 'user';
53  const TYPE_PROJECT = 'project';
54  const TYPE_ACCOUNT = 'bank_account';
55  const TYPE_BANK_LINE = 'bank_line';
56  const TYPE_WAREHOUSE = 'warehouse';
57  const TYPE_ACTIONCOMM = 'actioncomm';
58  const TYPE_WEBSITE_PAGE = 'website_page';
59 
63  public $picto = 'category';
64 
65 
69  protected $MAP_ID = array(
70  'product' => 0,
71  'supplier' => 1,
72  'customer' => 2,
73  'member' => 3,
74  'contact' => 4,
75  'bank_account' => 5,
76  'project' => 6,
77  'user' => 7,
78  'bank_line' => 8,
79  'warehouse' => 9,
80  'actioncomm' => 10,
81  'website_page' => 11
82  );
83 
89  public static $MAP_ID_TO_CODE = array(
90  0 => 'product',
91  1 => 'supplier',
92  2 => 'customer',
93  3 => 'member',
94  4 => 'contact',
95  5 => 'bank_account',
96  6 => 'project',
97  7 => 'user',
98  8 => 'bank_line',
99  9 => 'warehouse',
100  10 => 'actioncomm',
101  11 => 'website_page'
102  );
103 
109  protected $MAP_CAT_FK = array(
110  'customer' => 'soc',
111  'supplier' => 'soc',
112  'contact' => 'socpeople',
113  'bank_account' => 'account',
114  );
115 
121  protected $MAP_CAT_TABLE = array(
122  'customer' => 'societe',
123  'supplier' => 'fournisseur',
124  'bank_account'=> 'account',
125  );
126 
132  protected $MAP_OBJ_CLASS = array(
133  'product' => 'Product',
134  'customer' => 'Societe',
135  'supplier' => 'Fournisseur',
136  'member' => 'Adherent',
137  'contact' => 'Contact',
138  'user' => 'User',
139  'account' => 'Account', // old for bank account
140  'bank_account' => 'Account',
141  'project' => 'Project',
142  'warehouse'=> 'Entrepot',
143  'actioncomm' => 'ActionComm',
144  'website_page' => 'WebsitePage'
145  );
146 
152  public static $MAP_TYPE_TITLE_AREA = array(
153  'product' => 'ProductsCategoriesArea',
154  'customer' => 'CustomersCategoriesArea',
155  'supplier' => 'SuppliersCategoriesArea',
156  'member' => 'MembersCategoriesArea',
157  'contact' => 'ContactsCategoriesArea',
158  'user' => 'UsersCategoriesArea',
159  'account' => 'AccountsCategoriesArea', // old for bank account
160  'bank_account' => 'AccountsCategoriesArea',
161  'project' => 'ProjectsCategoriesArea',
162  'warehouse'=> 'StocksCategoriesArea',
163  'actioncomm' => 'ActioncommCategoriesArea',
164  'website_page' => 'WebsitePageCategoriesArea'
165  );
166 
172  protected $MAP_OBJ_TABLE = array(
173  'customer' => 'societe',
174  'supplier' => 'societe',
175  'member' => 'adherent',
176  'contact' => 'socpeople',
177  'account' => 'bank_account', // old for bank account
178  'project' => 'projet',
179  'warehouse'=> 'entrepot'
180  );
181 
185  public $element = 'category';
186 
190  public $table_element = 'categorie';
191 
195  public $fk_parent;
196 
200  public $label;
201 
205  public $description;
206 
210  public $color;
211 
215  public $visible;
216 
220  public $socid;
221 
238  public $type;
239 
243  public $cats = array();
244 
248  public $motherof = array();
249 
255  public function __construct($db)
256  {
257  global $hookmanager;
258 
259  $this->db = $db;
260 
261  if (is_object($hookmanager)) {
262  $hookmanager->initHooks(array('category'));
263  $parameters = array();
264  $reshook = $hookmanager->executeHooks('constructCategory', $parameters, $this); // Note that $action and $object may have been modified by some hooks
265  if ($reshook >= 0 && !empty($hookmanager->resArray)) {
266  $mapList = $hookmanager->resArray;
267  $mapId = $mapList['id'];
268  $mapCode = $mapList['code'];
269  self::$MAP_ID_TO_CODE[$mapId] = $mapCode;
270  $this->MAP_ID[$mapCode] = $mapId;
271  $this->MAP_CAT_FK[$mapCode] = $mapList['cat_fk'];
272  $this->MAP_CAT_TABLE[$mapCode] = $mapList['cat_table'];
273  $this->MAP_OBJ_CLASS[$mapCode] = $mapList['obj_class'];
274  $this->MAP_OBJ_TABLE[$mapCode] = $mapList['obj_table'];
275  }
276  }
277  }
278 
284  public function getMapList()
285  {
286  $mapList = array();
287 
288  foreach ($this->MAP_ID as $mapCode => $mapId) {
289  $mapList[] = array(
290  'id' => $mapId,
291  'code' => $mapCode,
292  'cat_fk' => (empty($this->MAP_CAT_FK[$mapCode]) ? $mapCode : $this->MAP_CAT_FK[$mapCode]),
293  'cat_table' => (empty($this->MAP_CAT_TABLE[$mapCode]) ? $mapCode : $this->MAP_CAT_TABLE[$mapCode]),
294  'obj_class' => (empty($this->MAP_OBJ_CLASS[$mapCode]) ? $mapCode : $this->MAP_OBJ_CLASS[$mapCode]),
295  'obj_table' => (empty($this->MAP_OBJ_TABLE[$mapCode]) ? $mapCode : $this->MAP_OBJ_TABLE[$mapCode])
296  );
297  }
298 
299  return $mapList;
300  }
301 
311  public function fetch($id, $label = '', $type = null, $ref_ext = '')
312  {
313  global $conf;
314 
315  // Check parameters
316  if (empty($id) && empty($label) && empty($ref_ext)) return -1;
317  if (!is_null($type) && !is_numeric($type)) $type = $this->MAP_ID[$type];
318 
319  $sql = "SELECT rowid, fk_parent, entity, label, description, color, fk_soc, visible, type, ref_ext";
320  $sql .= ", date_creation, tms, fk_user_creat, fk_user_modif";
321  $sql .= " FROM ".MAIN_DB_PREFIX."categorie";
322  if ($id > 0) {
323  $sql .= " WHERE rowid = ".$id;
324  } elseif (!empty($ref_ext)) {
325  $sql .= " WHERE ref_ext LIKE '".$this->db->escape($ref_ext)."'";
326  } else {
327  $sql .= " WHERE label = '".$this->db->escape($label)."' AND entity IN (".getEntity('category').")";
328  if (!is_null($type)) $sql .= " AND type = ".((int) $type);
329  }
330 
331  dol_syslog(get_class($this)."::fetch", LOG_DEBUG);
332  $resql = $this->db->query($sql);
333  if ($resql) {
334  if ($this->db->num_rows($resql) > 0) {
335  $res = $this->db->fetch_array($resql);
336 
337  $this->id = $res['rowid'];
338  //$this->ref = $res['rowid'];
339  $this->fk_parent = (int) $res['fk_parent'];
340  $this->label = $res['label'];
341  $this->description = $res['description'];
342  $this->color = $res['color'];
343  $this->socid = (int) $res['fk_soc'];
344  $this->visible = (int) $res['visible'];
345  $this->type = (int) $res['type'];
346  $this->ref_ext = $res['ref_ext'];
347  $this->entity = (int) $res['entity'];
348  $this->date_creation = $this->db->jdate($res['date_creation']);
349  $this->date_modification = $this->db->jdate($res['tms']);
350  $this->user_creation = (int) $res['fk_user_creat'];
351  $this->user_modification = (int) $res['fk_user_modif'];
352 
353  // Retrieve all extrafield
354  // fetch optionals attributes and labels
355  $this->fetch_optionals();
356 
357  $this->db->free($resql);
358 
359  // multilangs
360  if (!empty($conf->global->MAIN_MULTILANGS)) $this->getMultiLangs();
361 
362  return 1;
363  } else {
364  return 0;
365  }
366  } else {
367  dol_print_error($this->db);
368  return -1;
369  }
370  }
371 
381  public function create($user)
382  {
383  global $conf, $langs, $hookmanager;
384  $langs->load('categories');
385 
386  $type = $this->type;
387 
388  if (!is_numeric($type)) $type = $this->MAP_ID[$type];
389 
390  $error = 0;
391 
392  dol_syslog(get_class($this).'::create', LOG_DEBUG);
393 
394  // Clean parameters
395  $this->label = trim($this->label);
396  $this->description = trim($this->description);
397  $this->color = trim($this->color);
398  $this->import_key = trim($this->import_key);
399  $this->ref_ext = trim($this->ref_ext);
400  if (empty($this->visible)) $this->visible = 0;
401  $this->fk_parent = ($this->fk_parent != "" ? intval($this->fk_parent) : 0);
402 
403  if ($this->already_exists()) {
404  $this->error = $langs->trans("ImpossibleAddCat", $this->label);
405  $this->error .= " : ".$langs->trans("CategoryExistsAtSameLevel");
406  dol_syslog($this->error, LOG_WARNING);
407  return -4;
408  }
409 
410  $this->db->begin();
411  $now = dol_now();
412  $sql = "INSERT INTO ".MAIN_DB_PREFIX."categorie (";
413  $sql .= "fk_parent,";
414  $sql .= " label,";
415  $sql .= " description,";
416  $sql .= " color,";
417  if (!empty($conf->global->CATEGORY_ASSIGNED_TO_A_CUSTOMER)) {
418  $sql .= "fk_soc,";
419  }
420  $sql .= " visible,";
421  $sql .= " type,";
422  $sql .= " import_key,";
423  $sql .= " ref_ext,";
424  $sql .= " entity,";
425  $sql .= " date_creation,";
426  $sql .= " fk_user_creat";
427  $sql .= ") VALUES (";
428  $sql .= (int) $this->fk_parent.",";
429  $sql .= "'".$this->db->escape($this->label)."', ";
430  $sql .= "'".$this->db->escape($this->description)."', ";
431  $sql .= "'".$this->db->escape($this->color)."', ";
432  if (!empty($conf->global->CATEGORY_ASSIGNED_TO_A_CUSTOMER)) {
433  $sql .= ($this->socid > 0 ? $this->socid : 'null').", ";
434  }
435  $sql .= "'".$this->db->escape($this->visible)."', ";
436  $sql .= $this->db->escape($type).", ";
437  $sql .= (!empty($this->import_key) ? "'".$this->db->escape($this->import_key)."'" : 'null').", ";
438  $sql .= (!empty($this->ref_ext) ? "'".$this->db->escape($this->ref_ext)."'" : 'null').", ";
439  $sql .= (int) $conf->entity.", ";
440  $sql .= "'".$this->db->idate($now)."', ";
441  $sql .= (int) $user->id;
442  $sql .= ")";
443 
444  $res = $this->db->query($sql);
445  if ($res) {
446  $id = $this->db->last_insert_id(MAIN_DB_PREFIX."categorie");
447 
448  if ($id > 0) {
449  $this->id = $id;
450 
451  $action = 'create';
452 
453  // Actions on extra fields
454  if (!$error) {
455  $result = $this->insertExtraFields();
456  if ($result < 0) {
457  $error++;
458  }
459  }
460 
461  if (!$error) {
462  // Call trigger
463  $result = $this->call_trigger('CATEGORY_CREATE', $user);
464  if ($result < 0) { $error++; }
465  // End call triggers
466  }
467 
468  if (!$error) {
469  $this->db->commit();
470  return $id;
471  } else {
472  $this->db->rollback();
473  return -3;
474  }
475  } else {
476  $this->db->rollback();
477  return -2;
478  }
479  } else {
480  $this->error = $this->db->error();
481  $this->db->rollback();
482  return -1;
483  }
484  }
485 
494  public function update(User $user)
495  {
496  global $conf, $langs, $hookmanager;
497 
498  $error = 0;
499 
500  // Clean parameters
501  $this->label = trim($this->label);
502  $this->description = trim($this->description);
503  $this->ref_ext = trim($this->ref_ext);
504  $this->fk_parent = ($this->fk_parent != "" ? intval($this->fk_parent) : 0);
505  $this->visible = ($this->visible != "" ? intval($this->visible) : 0);
506 
507  if ($this->already_exists()) {
508  $this->error = $langs->trans("ImpossibleUpdateCat");
509  $this->error .= " : ".$langs->trans("CategoryExistsAtSameLevel");
510  return -1;
511  }
512 
513  $this->db->begin();
514 
515  $sql = "UPDATE ".MAIN_DB_PREFIX."categorie";
516  $sql .= " SET label = '".$this->db->escape($this->label)."',";
517  $sql .= " description = '".$this->db->escape($this->description)."',";
518  $sql .= " ref_ext = '".$this->db->escape($this->ref_ext)."',";
519  $sql .= " color = '".$this->db->escape($this->color)."'";
520  if (!empty($conf->global->CATEGORY_ASSIGNED_TO_A_CUSTOMER)) {
521  $sql .= ", fk_soc = ".($this->socid > 0 ? $this->socid : 'null');
522  }
523  $sql .= ", visible = ".(int) $this->visible;
524  $sql .= ", fk_parent = ".(int) $this->fk_parent;
525  $sql .= ", fk_user_modif = ".(int) $user->id;
526  $sql .= " WHERE rowid = ".$this->id;
527 
528  dol_syslog(get_class($this)."::update", LOG_DEBUG);
529  if ($this->db->query($sql)) {
530  $action = 'update';
531 
532  // Actions on extra fields
533  if (!$error) {
534  $result = $this->insertExtraFields();
535  if ($result < 0) {
536  $error++;
537  }
538  }
539 
540  if (!$error) {
541  // Call trigger
542  $result = $this->call_trigger('CATEGORY_MODIFY', $user);
543  if ($result < 0) { $error++; $this->db->rollback(); return -1; }
544  // End call triggers
545  }
546 
547  $this->db->commit();
548 
549  return 1;
550  } else {
551  $this->db->rollback();
552  dol_print_error($this->db);
553  return -1;
554  }
555  }
556 
564  public function delete($user, $notrigger = 0)
565  {
566  global $conf, $langs;
567 
568  $error = 0;
569 
570  // Clean parameters
571  $this->fk_parent = ($this->fk_parent != "" ? intval($this->fk_parent) : 0);
572 
573  dol_syslog(get_class($this)."::remove");
574 
575  $this->db->begin();
576 
577  if (!$error && !$notrigger) {
578  // Call trigger
579  $result = $this->call_trigger('CATEGORY_DELETE', $user);
580  if ($result < 0) $error++;
581  // End call triggers
582  }
583 
584  /* FIX #1317 : Check for child category and move up 1 level*/
585  if (!$error) {
586  $sql = "UPDATE ".MAIN_DB_PREFIX."categorie";
587  $sql .= " SET fk_parent = ".$this->fk_parent;
588  $sql .= " WHERE fk_parent = ".$this->id;
589 
590  if (!$this->db->query($sql)) {
591  $this->error = $this->db->lasterror();
592  $error++;
593  }
594  }
595 
596  $arraydelete = array(
597  'categorie_societe' => 'fk_categorie',
598  'categorie_fournisseur' => 'fk_categorie',
599  'categorie_product' => 'fk_categorie',
600  'categorie_member' => 'fk_categorie',
601  'categorie_contact' => 'fk_categorie',
602  'categorie_account' => 'fk_categorie',
603  'bank_class' => 'fk_categ',
604  'categorie_lang' => 'fk_category',
605  'categorie' => 'rowid',
606  );
607  foreach ($arraydelete as $key => $value) {
608  $sql = "DELETE FROM ".MAIN_DB_PREFIX.$key;
609  $sql .= " WHERE ".$value." = ".$this->id;
610  if (!$this->db->query($sql)) {
611  $this->errors[] = $this->db->lasterror();
612  dol_syslog("Error sql=".$sql." ".$this->error, LOG_ERR);
613  $error++;
614  }
615  }
616 
617  // Removed extrafields
618  if (!$error) {
619  $result = $this->deleteExtraFields();
620  if ($result < 0) {
621  $error++;
622  dol_syslog(get_class($this)."::delete erreur ".$this->error, LOG_ERR);
623  }
624  }
625 
626  if (!$error) {
627  $this->db->commit();
628  return 1;
629  } else {
630  $this->db->rollback();
631  return -1;
632  }
633  }
634 
635  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
643  public function add_type($obj, $type = '')
644  {
645  // phpcs:enable
646  global $user, $langs, $conf;
647 
648  $error = 0;
649 
650  if ($this->id == -1) return -2;
651 
652  if (empty($type)) $type = $obj->element;
653 
654  $this->db->begin();
655 
656  $sql = "INSERT INTO ".MAIN_DB_PREFIX."categorie_".(empty($this->MAP_CAT_TABLE[$type]) ? $type : $this->MAP_CAT_TABLE[$type]);
657  $sql .= " (fk_categorie, fk_".(empty($this->MAP_CAT_FK[$type]) ? $type : $this->MAP_CAT_FK[$type]).")";
658  $sql .= " VALUES (".$this->id.", ".$obj->id.")";
659 
660  dol_syslog(get_class($this).'::add_type', LOG_DEBUG);
661  if ($this->db->query($sql)) {
662  if (!empty($conf->global->CATEGORIE_RECURSIV_ADD)) {
663  $sql = 'SELECT fk_parent FROM '.MAIN_DB_PREFIX.'categorie';
664  $sql .= " WHERE rowid = ".$this->id;
665 
666  dol_syslog(get_class($this)."::add_type", LOG_DEBUG);
667  $resql = $this->db->query($sql);
668  if ($resql) {
669  if ($this->db->num_rows($resql) > 0) {
670  $objparent = $this->db->fetch_object($resql);
671 
672  if (!empty($objparent->fk_parent)) {
673  $cat = new Categorie($this->db);
674  $cat->id = $objparent->fk_parent;
675  if (!$cat->containsObject($type, $obj->id)) {
676  $result = $cat->add_type($obj, $type);
677  if ($result < 0) {
678  $this->error = $cat->error;
679  $error++;
680  }
681  }
682  }
683  }
684  } else {
685  $error++;
686  $this->error = $this->db->lasterror();
687  }
688 
689  if ($error) {
690  $this->db->rollback();
691  return -1;
692  }
693  }
694 
695 
696 
697  // Call trigger
698  $this->context = array('linkto'=>$obj); // Save object we want to link category to into category instance to provide information to trigger
699  $result = $this->call_trigger('CATEGORY_LINK', $user);
700  if ($result < 0) { $error++; }
701  // End call triggers
702 
703  if (!$error) {
704  $this->db->commit();
705  return 1;
706  } else {
707  $this->db->rollback();
708  return -2;
709  }
710  } else {
711  $this->db->rollback();
712  if ($this->db->lasterrno() == 'DB_ERROR_RECORD_ALREADY_EXISTS') {
713  $this->error = $this->db->lasterrno();
714  return -3;
715  } else {
716  $this->error = $this->db->lasterror();
717  }
718  return -1;
719  }
720  }
721 
722  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
731  public function del_type($obj, $type)
732  {
733  // phpcs:enable
734  global $user, $langs, $conf;
735 
736  $error = 0;
737 
738  // For backward compatibility
739  if ($type == 'societe') {
740  $type = 'customer';
741  dol_syslog(get_class($this)."::del_type(): type 'societe' is deprecated, please use 'customer' instead", LOG_WARNING);
742  } elseif ($type == 'fournisseur') {
743  $type = 'supplier';
744  dol_syslog(get_class($this)."::del_type(): type 'fournisseur' is deprecated, please use 'supplier' instead", LOG_WARNING);
745  }
746 
747  $this->db->begin();
748 
749  $sql = "DELETE FROM ".MAIN_DB_PREFIX."categorie_".(empty($this->MAP_CAT_TABLE[$type]) ? $type : $this->MAP_CAT_TABLE[$type]);
750  $sql .= " WHERE fk_categorie = ".$this->id;
751  $sql .= " AND fk_".(empty($this->MAP_CAT_FK[$type]) ? $type : $this->MAP_CAT_FK[$type])." = ".$obj->id;
752 
753  dol_syslog(get_class($this).'::del_type', LOG_DEBUG);
754  if ($this->db->query($sql)) {
755  // Call trigger
756  $this->context = array('unlinkoff'=>$obj); // Save object we want to link category to into category instance to provide information to trigger
757  $result = $this->call_trigger('CATEGORY_UNLINK', $user);
758  if ($result < 0) { $error++; }
759  // End call triggers
760 
761  if (!$error) {
762  $this->db->commit();
763  return 1;
764  } else {
765  $this->db->rollback();
766  return -2;
767  }
768  } else {
769  $this->db->rollback();
770  $this->error = $this->db->lasterror();
771  return -1;
772  }
773  }
774 
787  public function getObjectsInCateg($type, $onlyids = 0, $limit = 0, $offset = 0, $sortfield = '', $sortorder = 'ASC')
788  {
789  global $user;
790 
791  $objs = array();
792 
793  $classnameforobj = $this->MAP_OBJ_CLASS[$type];
794  $obj = new $classnameforobj($this->db);
795 
796  $sql = "SELECT c.fk_".(empty($this->MAP_CAT_FK[$type]) ? $type : $this->MAP_CAT_FK[$type]);
797  $sql .= " FROM ".MAIN_DB_PREFIX."categorie_".(empty($this->MAP_CAT_TABLE[$type]) ? $type : $this->MAP_CAT_TABLE[$type])." as c";
798  $sql .= ", ".MAIN_DB_PREFIX.(empty($this->MAP_OBJ_TABLE[$type]) ? $type : $this->MAP_OBJ_TABLE[$type])." as o";
799  $sql .= " WHERE o.entity IN (".getEntity($obj->element).")";
800  $sql .= " AND c.fk_categorie = ".$this->id;
801  $sql .= " AND c.fk_".(empty($this->MAP_CAT_FK[$type]) ? $type : $this->MAP_CAT_FK[$type])." = o.rowid";
802  // Protection for external users
803  if (($type == 'customer' || $type == 'supplier') && $user->socid > 0) {
804  $sql .= " AND o.rowid = ".$user->socid;
805  }
806  if ($limit > 0 || $offset > 0) $sql .= $this->db->plimit($limit + 1, $offset);
807  $sql .= $this->db->order($sortfield, $sortorder);
808 
809  dol_syslog(get_class($this)."::getObjectsInCateg", LOG_DEBUG);
810  $resql = $this->db->query($sql);
811  if ($resql) {
812  while ($rec = $this->db->fetch_array($resql)) {
813  if ($onlyids) {
814  $objs[] = $rec['fk_'.(empty($this->MAP_CAT_FK[$type]) ? $type : $this->MAP_CAT_FK[$type])];
815  } else {
816  $classnameforobj = $this->MAP_OBJ_CLASS[$type];
817 
818  $obj = new $classnameforobj($this->db);
819  $obj->fetch($rec['fk_'.(empty($this->MAP_CAT_FK[$type]) ? $type : $this->MAP_CAT_FK[$type])]);
820 
821  $objs[] = $obj;
822  }
823  }
824  return $objs;
825  } else {
826  $this->error = $this->db->error().' sql='.$sql;
827  return -1;
828  }
829  }
830 
839  public function containsObject($type, $object_id)
840  {
841  $sql = "SELECT COUNT(*) as nb FROM ".MAIN_DB_PREFIX."categorie_".(empty($this->MAP_CAT_TABLE[$type]) ? $type : $this->MAP_CAT_TABLE[$type]);
842  $sql .= " WHERE fk_categorie = ".$this->id." AND fk_".(empty($this->MAP_CAT_FK[$type]) ? $type : $this->MAP_CAT_FK[$type])." = ".$object_id;
843  dol_syslog(get_class($this)."::containsObject", LOG_DEBUG);
844  $resql = $this->db->query($sql);
845  if ($resql) {
846  return $this->db->fetch_object($resql)->nb;
847  } else {
848  $this->error = $this->db->error().' sql='.$sql;
849  return -1;
850  }
851  }
852 
864  public function getListForItem($id, $type = 'customer', $sortfield = "s.rowid", $sortorder = 'ASC', $limit = 0, $page = 0)
865  {
866  global $conf;
867 
868  $categories = array();
869 
870  $sub_type = $type;
871  $subcol_name = "fk_".$type;
872  if ($type == "customer") {
873  $sub_type = "societe";
874  $subcol_name = "fk_soc";
875  }
876  if ($type == "supplier") {
877  $sub_type = "fournisseur";
878  $subcol_name = "fk_soc";
879  }
880  if ($type == "contact") {
881  $subcol_name = "fk_socpeople";
882  }
883 
884  $idoftype = array_search($type, self::$MAP_ID_TO_CODE);
885 
886  $sql = "SELECT s.rowid";
887  $sql .= " FROM ".MAIN_DB_PREFIX."categorie as s";
888  $sql .= " , ".MAIN_DB_PREFIX."categorie_".$sub_type." as sub ";
889  $sql .= ' WHERE s.entity IN ('.getEntity('category').')';
890  $sql .= ' AND s.type='.$idoftype;
891  $sql .= ' AND s.rowid = sub.fk_categorie';
892  $sql .= ' AND sub.'.$subcol_name.' = '.$id;
893 
894  $sql .= $this->db->order($sortfield, $sortorder);
895 
896  $offset = 0;
897  $nbtotalofrecords = '';
898  if (empty($conf->global->MAIN_DISABLE_FULL_SCANLIST)) {
899  $result = $this->db->query($sql);
900  $nbtotalofrecords = $this->db->num_rows($result);
901  if (($page * $limit) > $nbtotalofrecords) { // if total resultset is smaller then paging size (filtering), goto and load page 0
902  $page = 0;
903  $offset = 0;
904  }
905  }
906 
907  if ($limit) {
908  if ($page < 0) {
909  $page = 0;
910  }
911  $offset = $limit * $page;
912 
913  $sql .= $this->db->plimit($limit + 1, $offset);
914  }
915 
916  $result = $this->db->query($sql);
917  if ($result) {
918  $i = 0;
919  $num = $this->db->num_rows($result);
920  $min = min($num, ($limit <= 0 ? $num : $limit));
921  while ($i < $min) {
922  $obj = $this->db->fetch_object($result);
923  $category_static = new Categorie($this->db);
924  if ($category_static->fetch($obj->rowid)) {
925  $categories[$i]['id'] = $category_static->id;
926  $categories[$i]['fk_parent'] = $category_static->fk_parent;
927  $categories[$i]['label'] = $category_static->label;
928  $categories[$i]['description'] = $category_static->description;
929  $categories[$i]['color'] = $category_static->color;
930  $categories[$i]['socid'] = $category_static->socid;
931  $categories[$i]['ref_ext'] = $category_static->ref_ext;
932  $categories[$i]['visible'] = $category_static->visible;
933  $categories[$i]['type'] = $category_static->type;
934  $categories[$i]['entity'] = $category_static->entity;
935  $categories[$i]['array_options'] = $category_static->array_options;
936 
937  // multilangs
938  if (!empty($conf->global->MAIN_MULTILANGS)) {
939  $categories[$i]['multilangs'] = $category_static->multilangs;
940  }
941  }
942  $i++;
943  }
944  } else {
945  $this->error = $this->db->lasterror();
946  return -1;
947  }
948  if (!count($categories)) {
949  return 0;
950  }
951 
952  return $categories;
953  }
954 
955  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
961  public function get_filles()
962  {
963  // phpcs:enable
964  $sql = "SELECT rowid FROM ".MAIN_DB_PREFIX."categorie";
965  $sql .= " WHERE fk_parent = ".$this->id;
966  $sql .= " AND entity IN (".getEntity('category').")";
967 
968  $res = $this->db->query($sql);
969  if ($res) {
970  $cats = array();
971  while ($rec = $this->db->fetch_array($res)) {
972  $cat = new Categorie($this->db);
973  $cat->fetch($rec['rowid']);
974  $cats[] = $cat;
975  }
976  return $cats;
977  } else {
978  dol_print_error($this->db);
979  return -1;
980  }
981  }
982 
983  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
989  protected function load_motherof()
990  {
991  // phpcs:enable
992  $this->motherof = array();
993 
994  // Load array[child]=parent
995  $sql = "SELECT fk_parent as id_parent, rowid as id_son";
996  $sql .= " FROM ".MAIN_DB_PREFIX."categorie";
997  $sql .= " WHERE fk_parent != 0";
998  $sql .= " AND entity IN (".getEntity('category').")";
999 
1000  dol_syslog(get_class($this)."::load_motherof", LOG_DEBUG);
1001  $resql = $this->db->query($sql);
1002  if ($resql) {
1003  while ($obj = $this->db->fetch_object($resql)) {
1004  $this->motherof[$obj->id_son] = $obj->id_parent;
1005  }
1006  return 1;
1007  } else {
1008  dol_print_error($this->db);
1009  return -1;
1010  }
1011  }
1012 
1013  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1033  public function get_full_arbo($type, $markafterid = 0, $include = 0)
1034  {
1035  // phpcs:enable
1036  global $conf, $langs;
1037 
1038  if (!is_numeric($type)) $type = $this->MAP_ID[$type];
1039  if (is_null($type)) {
1040  $this->error = 'BadValueForParameterType';
1041  return -1;
1042  }
1043 
1044  if (is_string($markafterid)) {
1045  $markafterid = explode(',', $markafterid);
1046  } elseif (is_numeric($markafterid)) {
1047  if ($markafterid > 0) {
1048  $markafterid = array($markafterid);
1049  } else {
1050  $markafterid = array();
1051  }
1052  } elseif (!is_array($markafterid)) {
1053  $markafterid = array();
1054  }
1055 
1056  $this->cats = array();
1057 
1058  // Init this->motherof that is array(id_son=>id_parent, ...)
1059  $this->load_motherof();
1060  $current_lang = $langs->getDefaultLang();
1061 
1062  // Init $this->cats array
1063  $sql = "SELECT DISTINCT c.rowid, c.label, c.ref_ext, c.description, c.color, c.fk_parent, c.visible"; // Distinct reduce pb with old tables with duplicates
1064  if (!empty($conf->global->MAIN_MULTILANGS)) $sql .= ", t.label as label_trans, t.description as description_trans";
1065  $sql .= " FROM ".MAIN_DB_PREFIX."categorie as c";
1066  if (!empty($conf->global->MAIN_MULTILANGS)) $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."categorie_lang as t ON t.fk_category=c.rowid AND t.lang='".$this->db->escape($current_lang)."'";
1067  $sql .= " WHERE c.entity IN (".getEntity('category').")";
1068  $sql .= " AND c.type = ".(int) $type;
1069 
1070  dol_syslog(get_class($this)."::get_full_arbo get category list", LOG_DEBUG);
1071  $resql = $this->db->query($sql);
1072  if ($resql) {
1073  $i = 0;
1074  while ($obj = $this->db->fetch_object($resql)) {
1075  $this->cats[$obj->rowid]['rowid'] = $obj->rowid;
1076  $this->cats[$obj->rowid]['id'] = $obj->rowid;
1077  $this->cats[$obj->rowid]['fk_parent'] = $obj->fk_parent;
1078  $this->cats[$obj->rowid]['label'] = !empty($obj->label_trans) ? $obj->label_trans : $obj->label;
1079  $this->cats[$obj->rowid]['description'] = !empty($obj->description_trans) ? $obj->description_trans : $obj->description;
1080  $this->cats[$obj->rowid]['color'] = $obj->color;
1081  $this->cats[$obj->rowid]['visible'] = $obj->visible;
1082  $this->cats[$obj->rowid]['ref_ext'] = $obj->ref_ext;
1083  $i++;
1084  }
1085  } else {
1086  dol_print_error($this->db);
1087  return -1;
1088  }
1089 
1090  // We add the fullpath property to each elements of first level (no parent exists)
1091  dol_syslog(get_class($this)."::get_full_arbo call to build_path_from_id_categ", LOG_DEBUG);
1092  foreach ($this->cats as $key => $val) {
1093  //print 'key='.$key.'<br>'."\n";
1094  $this->build_path_from_id_categ($key, 0); // Process a branch from the root category key (this category has no parent)
1095  }
1096 
1097  // Include or exclude leaf including $markafterid from tree
1098  if (count($markafterid) > 0) {
1099  $keyfiltercatid = '('.implode('|', $markafterid).')';
1100 
1101  //print "Look to discard category ".$markafterid."\n";
1102  $keyfilter1 = '^'.$keyfiltercatid.'$';
1103  $keyfilter2 = '_'.$keyfiltercatid.'$';
1104  $keyfilter3 = '^'.$keyfiltercatid.'_';
1105  $keyfilter4 = '_'.$keyfiltercatid.'_';
1106  foreach ($this->cats as $key => $val) {
1107  $test = (preg_match('/'.$keyfilter1.'/', $val['fullpath']) || preg_match('/'.$keyfilter2.'/', $val['fullpath'])
1108  || preg_match('/'.$keyfilter3.'/', $val['fullpath']) || preg_match('/'.$keyfilter4.'/', $val['fullpath']));
1109 
1110  if (($test && !$include) || (!$test && $include)) {
1111  unset($this->cats[$key]);
1112  }
1113  }
1114  }
1115 
1116  dol_syslog(get_class($this)."::get_full_arbo dol_sort_array", LOG_DEBUG);
1117  $this->cats = dol_sort_array($this->cats, 'fulllabel', 'asc', true, false);
1118 
1119  //$this->debug_cats();
1120 
1121  return $this->cats;
1122  }
1123 
1124  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1135  public function build_path_from_id_categ($id_categ, $protection = 1000)
1136  {
1137  // phpcs:enable
1138  dol_syslog(get_class($this)."::build_path_from_id_categ id_categ=".$id_categ." protection=".$protection, LOG_DEBUG);
1139 
1140  if (!empty($this->cats[$id_categ]['fullpath'])) {
1141  // Already defined
1142  dol_syslog(get_class($this)."::build_path_from_id_categ fullpath and fulllabel already defined", LOG_WARNING);
1143  return;
1144  }
1145 
1146  // First build full array $motherof
1147  //$this->load_motherof(); // Disabled because already done by caller of build_path_from_id_categ
1148 
1149  // $this->cats[$id_categ] is supposed to be already an array. We just want to complete it with property fullpath and fulllabel
1150 
1151  // Define fullpath and fulllabel
1152  $this->cats[$id_categ]['fullpath'] = '_'.$id_categ;
1153  $this->cats[$id_categ]['fulllabel'] = $this->cats[$id_categ]['label'];
1154  $i = 0; $cursor_categ = $id_categ;
1155  //print 'Work for id_categ='.$id_categ.'<br>'."\n";
1156  while ((empty($protection) || $i < $protection) && !empty($this->motherof[$cursor_categ])) {
1157  //print '&nbsp; cursor_categ='.$cursor_categ.' i='.$i.' '.$this->motherof[$cursor_categ].'<br>'."\n";
1158  $this->cats[$id_categ]['fullpath'] = '_'.$this->motherof[$cursor_categ].$this->cats[$id_categ]['fullpath'];
1159  $this->cats[$id_categ]['fulllabel'] = $this->cats[$this->motherof[$cursor_categ]]['label'].' >> '.$this->cats[$id_categ]['fulllabel'];
1160  //print '&nbsp; Result for id_categ='.$id_categ.' : '.$this->cats[$id_categ]['fullpath'].' '.$this->cats[$id_categ]['fulllabel'].'<br>'."\n";
1161  $i++; $cursor_categ = $this->motherof[$cursor_categ];
1162  }
1163  //print 'Result for id_categ='.$id_categ.' : '.$this->cats[$id_categ]['fullpath'].'<br>'."\n";
1164 
1165  // We count number of _ to have level
1166  $nbunderscore = substr_count($this->cats[$id_categ]['fullpath'], '_');
1167  $this->cats[$id_categ]['level'] = ($nbunderscore ? $nbunderscore : null);
1168 
1169  return;
1170  }
1171 
1172  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1178  public function debug_cats()
1179  {
1180  // phpcs:enable
1181  // Display $this->cats
1182  foreach ($this->cats as $key => $val) {
1183  print 'id: '.$this->cats[$key]['id'];
1184  print ' label: '.$this->cats[$key]['label'];
1185  print ' mother: '.$this->cats[$key]['fk_parent'];
1186  //print ' children: '.(is_array($this->cats[$key]['id_children'])?join(',',$this->cats[$key]['id_children']):'');
1187  print ' fullpath: '.$this->cats[$key]['fullpath'];
1188  print ' fulllabel: '.$this->cats[$key]['fulllabel'];
1189  print "<br>\n";
1190  }
1191  }
1192 
1193 
1194  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1202  public function get_all_categories($type = null, $parent = false)
1203  {
1204  // phpcs:enable
1205  if (!is_numeric($type)) $type = $this->MAP_ID[$type];
1206 
1207  $sql = "SELECT rowid FROM ".MAIN_DB_PREFIX."categorie";
1208  $sql .= " WHERE entity IN (".getEntity('category').")";
1209  if (!is_null($type))
1210  $sql .= " AND type = ".(int) $type;
1211  if ($parent)
1212  $sql .= " AND fk_parent = 0";
1213 
1214  $res = $this->db->query($sql);
1215  if ($res) {
1216  $cats = array();
1217  while ($rec = $this->db->fetch_array($res)) {
1218  $cat = new Categorie($this->db);
1219  $cat->fetch($rec['rowid']);
1220  $cats[$rec['rowid']] = $cat;
1221  }
1222  return $cats;
1223  } else {
1224  dol_print_error($this->db);
1225  return -1;
1226  }
1227  }
1228 
1229  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1236  public function get_main_categories($type = null)
1237  {
1238  // phpcs:enable
1239  return $this->get_all_categories($type, true);
1240  }
1241 
1242  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1248  public function already_exists()
1249  {
1250  // phpcs:enable
1251  $type = $this->type;
1252 
1253  if (!is_numeric($type)) $type = $this->MAP_ID[$type];
1254 
1255  /* We have to select any rowid from llx_categorie which category's mother and label
1256  * are equals to those of the calling category
1257  */
1258  $sql = "SELECT c.rowid";
1259  $sql .= " FROM ".MAIN_DB_PREFIX."categorie as c ";
1260  $sql .= " WHERE c.entity IN (".getEntity('category').")";
1261  $sql .= " AND c.type = ".$type;
1262  $sql .= " AND c.fk_parent = ".$this->fk_parent;
1263  $sql .= " AND c.label = '".$this->db->escape($this->label)."'";
1264 
1265  dol_syslog(get_class($this)."::already_exists", LOG_DEBUG);
1266  $resql = $this->db->query($sql);
1267  if ($resql) {
1268  if ($this->db->num_rows($resql) > 0) { // Checking for empty resql
1269  $obj = $this->db->fetch_array($resql);
1270  /* If object called create, obj cannot have is id.
1271  * If object called update, he mustn't have the same label as an other category for this mother.
1272  * So if the result have the same id, update is not for label, and if result have an other one,
1273  * update may be for label.
1274  */
1275  if ($obj[0] > 0 && $obj[0] != $this->id) {
1276  dol_syslog(get_class($this)."::already_exists category with name=".$this->label." and parent ".$this->fk_parent." exists: rowid=".$obj[0]." current_id=".$this->id, LOG_DEBUG);
1277  return 1;
1278  }
1279  }
1280  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);
1281  return 0;
1282  } else {
1283  $this->error = $this->db->error();
1284  return -1;
1285  }
1286  }
1287 
1288 
1289  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1300  public function print_all_ways($sep = ' &gt;&gt; ', $url = '', $nocolor = 0, $addpicto = 0)
1301  {
1302  // phpcs:enable
1303  $ways = array();
1304 
1305  $allways = $this->get_all_ways(); // Load array of categories
1306  foreach ($allways as $way) {
1307  $w = array();
1308  $i = 0;
1309  $forced_color = '';
1310  foreach ($way as $cat) {
1311  $i++;
1312 
1313  if (empty($nocolor)) {
1314  $forced_color = 'toreplace';
1315  if ($i == count($way)) {
1316  // Check contrast with background and correct text color
1317  $forced_color = 'categtextwhite';
1318  if ($cat->color) {
1319  if (colorIsLight($cat->color)) $forced_color = 'categtextblack';
1320  }
1321  }
1322  }
1323 
1324  if ($url == '') {
1325  $link = '<a href="'.DOL_URL_ROOT.'/categories/viewcat.php?id='.$cat->id.'&type='.$cat->type.'" class="'.$forced_color.'">';
1326  $linkend = '</a>';
1327  $w[] = $link.($addpicto ? img_object('', 'category', 'class="paddingright"') : '').$cat->label.$linkend;
1328  } elseif ($url == 'none') {
1329  $link = '<span class="'.$forced_color.'">';
1330  $linkend = '</span>';
1331  $w[] = $link.($addpicto ? img_object('', 'category', 'class="paddingright"') : '').$cat->label.$linkend;
1332  } else {
1333  $w[] = '<a class="'.$forced_color.'" href="'.DOL_URL_ROOT.'/'.$url.'?catid='.$cat->id.'">'.($addpicto ? img_object('', 'category') : '').$cat->label.'</a>';
1334  }
1335  }
1336  $newcategwithpath = preg_replace('/toreplace/', $forced_color, implode($sep, $w));
1337 
1338  $ways[] = $newcategwithpath;
1339  }
1340 
1341  return $ways;
1342  }
1343 
1344 
1345  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1351  public function get_meres()
1352  {
1353  // phpcs:enable
1354  $parents = array();
1355 
1356  $sql = "SELECT fk_parent FROM ".MAIN_DB_PREFIX."categorie";
1357  $sql .= " WHERE rowid = ".$this->id;
1358 
1359  $res = $this->db->query($sql);
1360 
1361  if ($res) {
1362  while ($rec = $this->db->fetch_array($res)) {
1363  if ($rec['fk_parent'] > 0) {
1364  $cat = new Categorie($this->db);
1365  $cat->fetch($rec['fk_parent']);
1366  $parents[] = $cat;
1367  }
1368  }
1369  return $parents;
1370  } else {
1371  dol_print_error($this->db);
1372  return -1;
1373  }
1374  }
1375 
1376  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1383  public function get_all_ways()
1384  {
1385  // phpcs:enable
1386  $ways = array();
1387 
1388  $parents = $this->get_meres();
1389  if (!empty($parents)) {
1390  foreach ($parents as $parent) {
1391  $allways = $parent->get_all_ways();
1392  foreach ($allways as $way) {
1393  $w = $way;
1394  $w[] = $this;
1395  $ways[] = $w;
1396  }
1397  }
1398  }
1399 
1400  if (count($ways) == 0)
1401  $ways[0][0] = $this;
1402 
1403  return $ways;
1404  }
1405 
1416  public function containing($id, $type, $mode = 'object')
1417  {
1418  $cats = array();
1419 
1420  if (is_numeric($type)) $type = Categorie::$MAP_ID_TO_CODE[$type];
1421 
1422  if ($type === Categorie::TYPE_BANK_LINE) { // TODO Remove this with standard category code after migration of llx_bank_categ into llx_categorie
1423  // Load bank categories
1424  $sql = "SELECT c.label, c.rowid";
1425  $sql .= " FROM ".MAIN_DB_PREFIX."bank_class as a, ".MAIN_DB_PREFIX."bank_categ as c";
1426  $sql .= " WHERE a.lineid=".$id." AND a.fk_categ = c.rowid";
1427  $sql .= " AND c.entity IN (".getEntity('category').")";
1428  $sql .= " ORDER BY c.label";
1429 
1430  $res = $this->db->query($sql);
1431  if ($res) {
1432  while ($obj = $this->db->fetch_object($res)) {
1433  if ($mode == 'id') {
1434  $cats[] = $obj->rowid;
1435  } elseif ($mode == 'label') {
1436  $cats[] = $obj->label;
1437  } else {
1438  $cat = new Categorie($this->db);
1439  $cat->id = $obj->rowid;
1440  $cat->label = $obj->label;
1441  $cats[] = $cat;
1442  }
1443  }
1444  } else {
1445  dol_print_error($this->db);
1446  return -1;
1447  }
1448  } else {
1449  $sql = "SELECT ct.fk_categorie, c.label, c.rowid";
1450  $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";
1451  $sql .= " WHERE ct.fk_categorie = c.rowid AND ct.fk_".(empty($this->MAP_CAT_FK[$type]) ? $type : $this->MAP_CAT_FK[$type])." = ".(int) $id." AND c.type = ".$this->MAP_ID[$type];
1452  $sql .= " AND c.entity IN (".getEntity('category').")";
1453 
1454  $res = $this->db->query($sql);
1455  if ($res) {
1456  while ($obj = $this->db->fetch_object($res)) {
1457  if ($mode == 'id') {
1458  $cats[] = $obj->rowid;
1459  } elseif ($mode == 'label') {
1460  $cats[] = $obj->label;
1461  } else {
1462  $cat = new Categorie($this->db);
1463  $cat->fetch($obj->fk_categorie);
1464  $cats[] = $cat;
1465  }
1466  }
1467  } else {
1468  dol_print_error($this->db);
1469  return -1;
1470  }
1471  }
1472 
1473  return $cats;
1474  }
1475 
1476 
1488  public function rechercher($id, $nom, $type, $exact = false, $case = false)
1489  {
1490  // Deprecation warning
1491  if (is_numeric($type)) {
1492  dol_syslog(__METHOD__.': using numeric types is deprecated.', LOG_WARNING);
1493  }
1494 
1495  $cats = array();
1496 
1497  // For backward compatibility
1498  if (is_numeric($type)) {
1499  // We want to reverse lookup
1500  $map_type = array_flip($this->MAP_ID);
1501  $type = $map_type[$type];
1502  dol_syslog(get_class($this)."::rechercher(): numeric types are deprecated, please use string instead", LOG_WARNING);
1503  }
1504 
1505  // Generation requete recherche
1506  $sql = "SELECT rowid FROM ".MAIN_DB_PREFIX."categorie";
1507  $sql .= " WHERE type = ".$this->MAP_ID[$type];
1508  $sql .= " AND entity IN (".getEntity('category').")";
1509  if ($nom) {
1510  if (!$exact)
1511  $nom = '%'.str_replace('*', '%', $nom).'%';
1512  if (!$case)
1513  $sql .= " AND label LIKE '".$this->db->escape($nom)."'";
1514  else $sql .= " AND label LIKE BINARY '".$this->db->escape($nom)."'";
1515  }
1516  if ($id) {
1517  $sql .= " AND rowid = '".$id."'";
1518  }
1519 
1520  $res = $this->db->query($sql);
1521  if ($res) {
1522  while ($rec = $this->db->fetch_array($res)) {
1523  $cat = new Categorie($this->db);
1524  $cat->fetch($rec['rowid']);
1525  $cats[] = $cat;
1526  }
1527 
1528  return $cats;
1529  } else {
1530  $this->error = $this->db->error().' sql='.$sql;
1531  return -1;
1532  }
1533  }
1534 
1545  public function getNomUrl($withpicto = 0, $option = '', $maxlength = 0, $moreparam = '')
1546  {
1547  global $langs;
1548 
1549  $result = '';
1550  $label = $langs->trans("ShowCategory").': '.($this->ref ? $this->ref : $this->label);
1551 
1552  // Check contrast with background and correct text color
1553  $forced_color = 'categtextwhite';
1554  if ($this->color) {
1555  if (colorIsLight($this->color)) $forced_color = 'categtextblack';
1556  }
1557 
1558  $link = '<a href="'.DOL_URL_ROOT.'/categories/viewcat.php?id='.$this->id.'&type='.$this->type.$moreparam.'&backtopage='.urlencode($_SERVER['PHP_SELF'].($moreparam ? '?'.$moreparam : '')).'" title="'.dol_escape_htmltag($label, 1).'" class="classfortooltip '.$forced_color.'">';
1559  $linkend = '</a>';
1560 
1561  $picto = 'category';
1562 
1563 
1564  if ($withpicto) $result .= ($link.img_object($label, $picto, 'class="classfortooltip"').$linkend);
1565  if ($withpicto && $withpicto != 2) $result .= ' ';
1566  if ($withpicto != 2) $result .= $link.dol_trunc(($this->ref ? $this->ref : $this->label), $maxlength).$linkend;
1567  return $result;
1568  }
1569 
1570 
1571  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1579  public function add_photo($sdir, $file)
1580  {
1581  // phpcs:enable
1582  require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
1583 
1584  $dir = $sdir.'/'.get_exdir($this->id, 2, 0, 0, $this, 'category').$this->id."/";
1585  $dir .= "photos/";
1586 
1587  if (!file_exists($dir)) {
1588  dol_mkdir($dir);
1589  }
1590 
1591  if (file_exists($dir)) {
1592  if (is_array($file['name']) && count($file['name']) > 0) {
1593  $nbfile = count($file['name']);
1594  for ($i = 0; $i <= $nbfile; $i++) {
1595  $originImage = $dir.$file['name'][$i];
1596 
1597  // Cree fichier en taille origine
1598  dol_move_uploaded_file($file['tmp_name'][$i], $originImage, 1, 0, 0);
1599 
1600  if (file_exists($originImage)) {
1601  // Create thumbs
1602  $this->addThumbs($originImage);
1603  }
1604  }
1605  } else {
1606  $originImage = $dir.$file['name'];
1607 
1608  // Cree fichier en taille origine
1609  dol_move_uploaded_file($file['tmp_name'], $originImage, 1, 0, 0);
1610 
1611  if (file_exists($originImage)) {
1612  // Create thumbs
1613  $this->addThumbs($originImage);
1614  }
1615  }
1616  }
1617  }
1618 
1619  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1627  public function liste_photos($dir, $nbmax = 0)
1628  {
1629  // phpcs:enable
1630  include_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
1631 
1632  $nbphoto = 0;
1633  $tabobj = array();
1634 
1635  $dirthumb = $dir.'thumbs/';
1636 
1637  if (file_exists($dir)) {
1638  $handle = opendir($dir);
1639  if (is_resource($handle)) {
1640  while (($file = readdir($handle)) !== false) {
1641  if (dol_is_file($dir.$file) && preg_match('/(\.jpeg|\.jpg|\.bmp|\.gif|\.png|\.tiff)$/i', $dir.$file)) {
1642  $nbphoto++;
1643  $photo = $file;
1644 
1645  // On determine nom du fichier vignette
1646  $photo_vignette = '';
1647  if (preg_match('/(\.jpeg|\.jpg|\.bmp|\.gif|\.png|\.tiff)$/i', $photo, $regs)) {
1648  $photo_vignette = preg_replace('/'.$regs[0].'/i', '', $photo).'_small'.$regs[0];
1649  }
1650 
1651  // Objet
1652  $obj = array();
1653  $obj['photo'] = $photo;
1654  if ($photo_vignette && is_file($dirthumb.$photo_vignette)) $obj['photo_vignette'] = 'thumbs/'.$photo_vignette;
1655  else $obj['photo_vignette'] = "";
1656 
1657  $tabobj[$nbphoto - 1] = $obj;
1658 
1659  // On continue ou on arrete de boucler
1660  if ($nbmax && $nbphoto >= $nbmax) break;
1661  }
1662  }
1663 
1664  closedir($handle);
1665  }
1666  }
1667 
1668  return $tabobj;
1669  }
1670 
1671  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1678  public function delete_photo($file)
1679  {
1680  // phpcs:enable
1681  require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
1682 
1683  $dir = dirname($file).'/'; // Chemin du dossier contenant l'image d'origine
1684  $dirthumb = $dir.'/thumbs/'; // Chemin du dossier contenant la vignette
1685  $filename = preg_replace('/'.preg_quote($dir, '/').'/i', '', $file); // Nom du fichier
1686 
1687  // On efface l'image d'origine
1688  dol_delete_file($file, 1);
1689 
1690  // Si elle existe, on efface la vignette
1691  if (preg_match('/(\.jpeg|\.jpg|\.bmp|\.gif|\.png|\.tiff)$/i', $filename, $regs)) {
1692  $photo_vignette = preg_replace('/'.$regs[0].'/i', '', $filename).'_small'.$regs[0];
1693  if (file_exists($dirthumb.$photo_vignette)) {
1694  dol_delete_file($dirthumb.$photo_vignette, 1);
1695  }
1696  }
1697  }
1698 
1699  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1706  public function get_image_size($file)
1707  {
1708  // phpcs:enable
1709  $infoImg = getimagesize($file); // Recuperation des infos de l'image
1710  $this->imgWidth = $infoImg[0]; // Largeur de l'image
1711  $this->imgHeight = $infoImg[1]; // Hauteur de l'image
1712  }
1713 
1721  public function setMultiLangs($user)
1722  {
1723  global $langs;
1724 
1725  $langs_available = $langs->get_available_languages();
1726  $current_lang = $langs->getDefaultLang();
1727 
1728  foreach ($langs_available as $key => $value) {
1729  $sql = "SELECT rowid";
1730  $sql .= " FROM ".MAIN_DB_PREFIX."categorie_lang";
1731  $sql .= " WHERE fk_category=".$this->id;
1732  $sql .= " AND lang='".$key."'";
1733 
1734  $result = $this->db->query($sql);
1735 
1736  if ($key == $current_lang) {
1737  if ($this->db->num_rows($result)) { // si aucune ligne dans la base
1738  $sql2 = "UPDATE ".MAIN_DB_PREFIX."categorie_lang";
1739  $sql2 .= " SET label='".$this->db->escape($this->label)."',";
1740  $sql2 .= " description='".$this->db->escape($this->description)."'";
1741  $sql2 .= " WHERE fk_category=".$this->id." AND lang='".$this->db->escape($key)."'";
1742  } else {
1743  $sql2 = "INSERT INTO ".MAIN_DB_PREFIX."categorie_lang (fk_category, lang, label, description)";
1744  $sql2 .= " VALUES(".$this->id.",'".$key."','".$this->db->escape($this->label);
1745  $sql2 .= "','".$this->db->escape($this->multilangs["$key"]["description"])."')";
1746  }
1747  dol_syslog(get_class($this).'::setMultiLangs', LOG_DEBUG);
1748  if (!$this->db->query($sql2)) {
1749  $this->error = $this->db->lasterror();
1750  return -1;
1751  }
1752  } elseif (isset($this->multilangs["$key"])) {
1753  if ($this->db->num_rows($result)) { // si aucune ligne dans la base
1754  $sql2 = "UPDATE ".MAIN_DB_PREFIX."categorie_lang";
1755  $sql2 .= " SET label='".$this->db->escape($this->multilangs["$key"]["label"])."',";
1756  $sql2 .= " description='".$this->db->escape($this->multilangs["$key"]["description"])."'";
1757  $sql2 .= " WHERE fk_category=".$this->id." AND lang='".$this->db->escape($key)."'";
1758  } else {
1759  $sql2 = "INSERT INTO ".MAIN_DB_PREFIX."categorie_lang (fk_category, lang, label, description)";
1760  $sql2 .= " VALUES(".$this->id.",'".$key."','".$this->db->escape($this->multilangs["$key"]["label"]);
1761  $sql2 .= "','".$this->db->escape($this->multilangs["$key"]["description"])."')";
1762  }
1763 
1764  // on ne sauvegarde pas des champs vides
1765  if ($this->multilangs["$key"]["label"] || $this->multilangs["$key"]["description"] || $this->multilangs["$key"]["note"])
1766  dol_syslog(get_class($this).'::setMultiLangs', LOG_DEBUG);
1767  if (!$this->db->query($sql2)) {
1768  $this->error = $this->db->lasterror();
1769  return -1;
1770  }
1771  }
1772  }
1773 
1774  // Call trigger
1775  $result = $this->call_trigger('CATEGORY_SET_MULTILANGS', $user);
1776  if ($result < 0) {
1777  $this->error = $this->db->lasterror();
1778  return -1;
1779  }
1780  // End call triggers
1781 
1782  return 1;
1783  }
1784 
1790  public function getMultiLangs()
1791  {
1792  global $langs;
1793 
1794  $current_lang = $langs->getDefaultLang();
1795 
1796  $sql = "SELECT lang, label, description";
1797  $sql .= " FROM ".MAIN_DB_PREFIX."categorie_lang";
1798  $sql .= " WHERE fk_category=".$this->id;
1799 
1800  $result = $this->db->query($sql);
1801  if ($result) {
1802  while ($obj = $this->db->fetch_object($result)) {
1803  //print 'lang='.$obj->lang.' current='.$current_lang.'<br>';
1804  if ($obj->lang == $current_lang) { // si on a les traduct. dans la langue courante on les charge en infos principales.
1805  $this->label = $obj->label;
1806  $this->description = $obj->description;
1807  }
1808  $this->multilangs["$obj->lang"]["label"] = $obj->label;
1809  $this->multilangs["$obj->lang"]["description"] = $obj->description;
1810  }
1811  return 1;
1812  } else {
1813  $this->error = $langs->trans("Error")." : ".$this->db->error()." - ".$sql;
1814  return -1;
1815  }
1816  }
1817 
1824  public function getLibStatut($mode)
1825  {
1826  return '';
1827  }
1828 
1829 
1837  public function initAsSpecimen()
1838  {
1839  dol_syslog(get_class($this)."::initAsSpecimen");
1840 
1841  // Initialise parametres
1842  $this->id = 0;
1843  $this->fk_parent = 0;
1844  $this->label = 'SPECIMEN';
1845  $this->specimen = 1;
1846  $this->description = 'This is a description';
1847  $this->socid = 1;
1848  $this->type = self::TYPE_PRODUCT;
1849  }
1850 
1859  public static function replaceThirdparty(DoliDB $db, $origin_id, $dest_id)
1860  {
1861  $tables = array(
1862  'categorie_societe'
1863  );
1864 
1865  return CommonObject::commonReplaceThirdparty($db, $origin_id, $dest_id, $tables, 1);
1866  }
1867 
1875  public static function getFilterJoinQuery($type, $rowIdName)
1876  {
1877  if ($type == 'bank_account') $type = 'account';
1878 
1879  return " LEFT JOIN ".MAIN_DB_PREFIX."categorie_".$type." as cp ON ".$rowIdName." = cp.fk_".$type;
1880  }
1881 
1890  public static function getFilterSelectQuery($type, $rowIdName, $searchList)
1891  {
1892  if ($type == 'bank_account') $type = 'account';
1893 
1894  if (empty($searchList) && !is_array($searchList)) {
1895  return "";
1896  }
1897 
1898  $searchCategorySqlList = array();
1899  foreach ($searchList as $searchCategory) {
1900  if (intval($searchCategory) == -2) {
1901  $searchCategorySqlList[] = " cp.fk_categorie IS NULL";
1902  } elseif (intval($searchCategory) > 0) {
1903  $searchCategorySqlList[] = " ".$rowIdName." IN (SELECT fk_".$type." FROM ".MAIN_DB_PREFIX."categorie_".$type." WHERE fk_categorie = ".((int) $searchCategory).")";
1904  }
1905  }
1906 
1907  if (!empty($searchCategorySqlList)) {
1908  return " AND (".implode(' AND ', $searchCategorySqlList).")";
1909  } else {
1910  return "";
1911  }
1912  }
1913 
1919  public function countNbOfCategories()
1920  {
1921  dol_syslog(get_class($this)."::count_all_categories", LOG_DEBUG);
1922  $sql = "SELECT COUNT(rowid) FROM ".MAIN_DB_PREFIX."categorie";
1923  $sql .= " WHERE entity IN (".getEntity('category').")";
1924 
1925  $res = $this->db->query($sql);
1926  if ($res) {
1927  $obj = $this->db->fetch_object($res);
1928  return $obj->count;
1929  } else {
1930  dol_print_error($this->db);
1931  return -1;
1932  }
1933  }
1934 }
getMultiLangs()
Load array this-&gt;multilangs.
static replaceThirdparty(DoliDB $db, $origin_id, $dest_id)
Function used to replace a thirdparty id with another one.
fetch($id, $label= '', $type=null, $ref_ext= '')
Load category into memory from database.
containing($id, $type, $mode= 'object')
Return list of categories (object instances or labels) linked to element of id $id and type $type Sho...
addThumbs($file)
Build thumb.
create($user)
Add category into database.
</td > param sortfield sortorder printFieldListOption< tdclass="liste_titremaxwidthsearchright"></td ></tr >< trclass="liste_titre">< inputtype="checkbox"onClick="toggle(this)"/> Ref p ref Label p label Duration p duration center DesiredStock p desiredstock right StockLimitShort p seuil_stock_alerte right stock_physique right stock_real_warehouse right Ordered right StockToBuy right SupplierRef right param sortfield sortorder printFieldListTitle warehouseinternal SELECT description FROM product_lang WHERE qty< br > qty qty qty StockTooLow StockTooLow help help help< trclass="oddeven">< td >< inputtype="checkbox"class="check"name="choose'.$i.'"></td >< tdclass="nowrap"> stock</td >< td >< inputtype="hidden"name="desc'.$i.'"value="'.dol_escape_htmltag($objp-> description
Only used if Module[ID]Desc translation string is not found.
Definition: replenish.php:750
debug_cats()
Display content of $this-&gt;cats.
get_filles()
Return direct childs id of a category into an array.
add_photo($sdir, $file)
Deplace fichier uploade sous le nom $files dans le repertoire sdir.
setMultiLangs($user)
Update ou cree les traductions des infos produits.
dol_now($mode= 'auto')
Return date for now.
update(User $user)
Update category.
getListForItem($id, $type= 'customer', $sortfield="s.rowid", $sortorder= 'ASC', $limit=0, $page=0)
List categories of an element id.
Class to manage Dolibarr users.
Definition: user.class.php:44
Class to manage Dolibarr database access.
get_image_size($file)
Load size of image file.
static getFilterSelectQuery($type, $rowIdName, $searchList)
Return the addtional SQL SELECT query for filtering a list by a category.
delete_photo($file)
Efface la photo de la categorie et sa vignette.
static getFilterJoinQuery($type, $rowIdName)
Return the addtional SQL JOIN query for filtering a list by a category.
get_all_ways()
Returns in a table all possible paths to get to the category starting with the major categories repre...
add_type($obj, $type= '')
Link an object to the category.
$conf db
API class for accounts.
Definition: inc.php:54
get_all_categories($type=null, $parent=false)
Returns all categories.
insertExtraFields($trigger= '', $userused=null)
Add/Update all extra fields values for the current object.
del_type($obj, $type)
Delete object from category.
getEntity($element, $shared=1, $currentobject=null)
Get list of entity id to use.
Class to manage categories.
build_path_from_id_categ($id_categ, $protection=1000)
For category id_categ and its childs available in this-&gt;cats, define property fullpath and fulllabel...
get_main_categories($type=null)
Returns the top level categories (which are not child)
containsObject($type, $object_id)
Check for the presence of an object in a category.
get_full_arbo($type, $markafterid=0, $include=0)
Rebuilding the category tree as an array Return an array of table(&#39;id&#39;,&#39;id_mere&#39;,...) trie selon arbre et avec: id = id de la categorie id_mere = id de la categorie mere id_children = tableau des id enfant label = nom de la categorie fulllabel = nom avec chemin complet de la categorie fullpath = chemin complet compose des id.
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 (&quot; &gt;&gt; &quot; by defau...
static commonReplaceThirdparty(DoliDB $db, $origin_id, $dest_id, array $tables, $ignoreerrors=0)
Function used to replace a thirdparty id with another one.
getNomUrl($withpicto=0, $option= '', $maxlength=0, $moreparam= '')
Return name and link of category (with picto) Use -&gt;id, -&gt;ref, -&gt;label, -&gt;color.
dol_syslog($message, $level=LOG_INFO, $ident=0, $suffixinfilename= '', $restricttologhandler= '', $logcontext=null)
Write log message into outputs.
get_exdir($num, $level, $alpha, $withoutslash, $object, $modulepart= '')
Return a path to have a the directory according to object where files are stored. ...
getLibStatut($mode)
Return label of contact status.
__construct($db)
Constructor.
dol_delete_file($file, $disableglob=0, $nophperrors=0, $nohook=0, $object=null, $allowdotdot=false, $indexdatabase=1)
Remove a file or several files with a mask.
Definition: files.lib.php:1144
img_object($titlealt, $picto, $moreatt= '', $pictoisfullpath=false, $srconly=0, $notitle=0)
Show a picto called object_picto (generic function)
deleteExtraFields()
Delete all extra fields values for the current object.
load_motherof()
Load the array this-&gt;motherof that is array(id_son=&gt;id_parent, ...)
fetch_optionals($rowid=null, $optionsArray=null)
Function to get extra fields of an object into $this-&gt;array_options This method is in most cases call...
dol_move_uploaded_file($src_file, $dest_file, $allowoverwrite, $disablevirusscan=0, $uploaderrorcode=0, $nohook=0, $varfiles= 'addedfile', $upload_dir= '')
Make control on an uploaded file from an GUI page and move it to final destination.
Definition: files.lib.php:999
dol_is_file($pathoffile)
Return if path is a file.
Definition: files.lib.php:457
print $_SERVER["PHP_SELF"]
Edit parameters.
dol_sort_array(&$array, $index, $order= 'asc', $natsort=0, $case_sensitive=0, $keepindex=0)
Advanced sort array by second index function, which produces ascending (default) or descending output...
countNbOfCategories()
Count all categories.
print
Draft customers invoices.
Definition: index.php:89
get_meres()
Returns an array containing the list of parent categories.
getMapList()
Get map list.
call_trigger($triggerName, $user)
Call trigger based on this instance.
if(!empty($conf->facture->enabled)&&$user->rights->facture->lire) if((!empty($conf->fournisseur->enabled)&&empty($conf->global->MAIN_USE_NEW_SUPPLIERMOD)||!empty($conf->supplier_invoice->enabled))&&$user->rights->fournisseur->facture->lire) if(!empty($conf->don->enabled)&&$user->rights->don->lire) if(!empty($conf->tax->enabled)&&$user->rights->tax->charges->lire) if(!empty($conf->facture->enabled)&&!empty($conf->commande->enabled)&&$user->rights->commande->lire &&empty($conf->global->WORKFLOW_DISABLE_CREATE_INVOICE_FROM_ORDER)) if(!empty($conf->facture->enabled)&&$user->rights->facture->lire) if((!empty($conf->fournisseur->enabled)&&empty($conf->global->MAIN_USE_NEW_SUPPLIERMOD)||!empty($conf->supplier_invoice->enabled))&&$user->rights->fournisseur->facture->lire) $resql
Social contributions to pay.
Definition: index.php:1232
dol_print_error($db= '', $error= '', $errors=null)
Displays error message system with all the information to facilitate the diagnosis and the escalation...
liste_photos($dir, $nbmax=0)
Return tableau de toutes les photos de la categorie.
colorIsLight($stringcolor)
Return true if the color is light.
rechercher($id, $nom, $type, $exact=false, $case=false)
Returns categories whose id or name match add wildcards in the name unless $exact = true...
already_exists()
Check if no category with same label already exists for this cat&#39;s parent or root and for this cat&#39;s ...
if(preg_match('/crypted:/i', $dolibarr_main_db_pass)||!empty($dolibarr_main_db_encrypted_pass)) $conf db type
Definition: repair.php:105
initAsSpecimen()
Initialise an instance with random values.
Parent class of all other business classes (invoices, contracts, proposals, orders, ...)
dol_mkdir($dir, $dataroot= '', $newmask=null)
Creation of a directory (this can create recursive subdir)
getObjectsInCateg($type, $onlyids=0, $limit=0, $offset=0, $sortfield= '', $sortorder= 'ASC')
Return list of fetched instance of elements having this category.
dol_escape_htmltag($stringtoescape, $keepb=0, $keepn=0, $keepmoretags= '', $escapeonlyhtmltags=0)
Returns text escaped for inclusion in HTML alt or title tags, or into values of HTML input fields...