PageRenderTime 49ms CodeModel.GetById 17ms RepoModel.GetById 0ms app.codeStats 0ms

/htdocs/categories/class/categorie.class.php

https://github.com/asterix14/dolibarr
PHP | 1366 lines | 888 code | 160 blank | 318 comment | 135 complexity | 3bd8830261ff47e326f2c677fbdb6174 MD5 | raw file
Possible License(s): LGPL-2.0
  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-2011 Regis Houssin <regis@dolibarr.fr>
  6. * Copyright (C) 2006-2011 Laurent Destailleur <eldy@users.sourceforge.net>
  7. * Copyright (C) 2007 Patrick Raguin <patrick.raguin@gmail.com>
  8. *
  9. * This program is free software; you can redistribute it and/or modify
  10. * it under the terms of the GNU General Public License as published by
  11. * the Free Software Foundation; either version 2 of the License, or
  12. * (at your option) any later version.
  13. *
  14. * This program is distributed in the hope that it will be useful,
  15. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  17. * GNU General Public License for more details.
  18. *
  19. * You should have received a copy of the GNU General Public License
  20. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  21. */
  22. /**
  23. * \file htdocs/categories/class/categorie.class.php
  24. * \ingroup categorie
  25. * \brief File of class to manage categories
  26. */
  27. require_once(DOL_DOCUMENT_ROOT."/product/class/product.class.php");
  28. require_once(DOL_DOCUMENT_ROOT."/fourn/class/fournisseur.class.php");
  29. /**
  30. * \class Categorie
  31. * \brief Class to manage categories
  32. */
  33. class Categorie
  34. {
  35. public $element='category';
  36. public $table_element='category';
  37. var $id;
  38. var $id_mere;
  39. var $label;
  40. var $description;
  41. var $socid;
  42. var $type; // 0=Product, 1=Supplier, 2=Customer/Prospect, 3=Member
  43. var $parentId;
  44. var $cats=array(); // Tableau en memoire des categories
  45. var $motherof = array(); // Tableau des correspondances id_fille -> id_mere
  46. /**
  47. * Constructor
  48. *
  49. * @param DoliDB $DB Database handler
  50. * @param int $id Id of category to fetch during init
  51. */
  52. function Categorie($DB, $id=-1)
  53. {
  54. $this->db = $DB;
  55. $this->id = $id;
  56. if ($id != -1) $this->fetch($this->id);
  57. }
  58. /**
  59. * Load category into memory from database
  60. *
  61. * @param int $id Id of category
  62. * @return int <0 if KO, >0 if OK
  63. */
  64. function fetch($id)
  65. {
  66. $sql = "SELECT rowid, label, description, fk_soc, visible, type";
  67. $sql.= " FROM ".MAIN_DB_PREFIX."categorie";
  68. $sql.= " WHERE rowid = ".$id;
  69. dol_syslog("Categorie::fetch sql=".$sql);
  70. $resql = $this->db->query($sql);
  71. if ($resql)
  72. {
  73. $res = $this->db->fetch_array($resql);
  74. $this->id = $res['rowid'];
  75. $this->label = $res['label'];
  76. $this->description = $res['description'];
  77. $this->socid = $res['fk_soc'];
  78. $this->visible = $res['visible'];
  79. $this->type = $res['type'];
  80. $this->db->free($resql);
  81. }
  82. else
  83. {
  84. dol_print_error($this->db);
  85. return -1;
  86. }
  87. $sql = "SELECT fk_categorie_mere";
  88. $sql.= " FROM ".MAIN_DB_PREFIX."categorie_association";
  89. $sql.= " WHERE fk_categorie_fille = ".$id;
  90. dol_syslog("Categorie::fetch sql=".$sql);
  91. $resql = $this->db->query($sql);
  92. if ($resql)
  93. {
  94. $res = $this->db->fetch_array($resql);
  95. $this->id_mere = $res['fk_categorie_mere'];
  96. $this->parentId = $res['fk_categorie_mere'] ? $res['fk_categorie_mere'] : 0;
  97. return $this->id;
  98. }
  99. else
  100. {
  101. dol_print_error($this->db);
  102. return -1;
  103. }
  104. }
  105. /**
  106. * Add category into database
  107. *
  108. * @return int -1 : erreur SQL
  109. * -2 : nouvel ID inconnu
  110. * -3 : categorie invalide
  111. */
  112. function create()
  113. {
  114. global $conf,$langs;
  115. $langs->load('categories');
  116. // Clean parameters
  117. if (empty($this->visible)) $this->visible=0;
  118. $this->parentId = ($this->id_mere) != "" ? intval($this->id_mere) : 0;
  119. if ($this->already_exists())
  120. {
  121. $this->error=$langs->trans("ImpossibleAddCat");
  122. $this->error.=" : ".$langs->trans("CategoryExistsAtSameLevel");
  123. return -1;
  124. }
  125. $sql = "INSERT INTO ".MAIN_DB_PREFIX."categorie (label, description,";
  126. if ($conf->global->CATEGORY_ASSIGNED_TO_A_CUSTOMER)
  127. {
  128. $sql.= "fk_soc,";
  129. }
  130. $sql.= " visible,";
  131. $sql.= " type,";
  132. $sql.= " entity";
  133. //$sql.= ", fk_parent_id";
  134. $sql.= ")";
  135. $sql.= " VALUES ('".$this->db->escape($this->label)."', '".$this->db->escape($this->description)."',";
  136. if ($conf->global->CATEGORY_ASSIGNED_TO_A_CUSTOMER)
  137. {
  138. $sql.= ($this->socid != -1 ? $this->socid : 'null').",";
  139. }
  140. $sql.= "'".$this->visible."',".$this->type.",".$conf->entity;
  141. //$sql.= ",".$this->parentId;
  142. $sql.= ")";
  143. $res = $this->db->query($sql);
  144. if ($res)
  145. {
  146. $id = $this->db->last_insert_id(MAIN_DB_PREFIX."categorie");
  147. if ($id > 0)
  148. {
  149. $this->id = $id;
  150. if($this->id_mere != "")
  151. {
  152. if($this->add_fille() < 0)
  153. {
  154. $this->error=$langs->trans("ImpossibleAssociateCategory");
  155. return -1;
  156. }
  157. }
  158. // Appel des triggers
  159. include_once(DOL_DOCUMENT_ROOT . "/core/class/interfaces.class.php");
  160. $interface=new Interfaces($this->db);
  161. $result=$interface->run_triggers('CATEGORY_CREATE',$this,$user,$langs,$conf);
  162. if ($result < 0) { $error++; $this->errors=$interface->errors; }
  163. // Fin appel triggers
  164. return $id;
  165. }
  166. else
  167. {
  168. return -2;
  169. }
  170. }
  171. else
  172. {
  173. dol_print_error($this->db);
  174. return -1;
  175. }
  176. }
  177. /**
  178. * Update category
  179. *
  180. * @return int 1 : OK
  181. * -1 : SQL error
  182. * -2 : invalid category
  183. */
  184. function update()
  185. {
  186. global $conf, $langs;
  187. // Clean parameters
  188. $this->label=trim($this->label);
  189. $this->description=trim($this->description);
  190. $this->parentId = ($this->id_mere) != "" ? intval($this->id_mere) : 0;
  191. $this->visible = ($this->visible) != "" ? intval($this->visible) : 0;
  192. if ($this->already_exists())
  193. {
  194. $this->error=$langs->trans("ImpossibleUpdateCat");
  195. $this->error.=" : ".$langs->trans("CategoryExistsAtSameLevel");
  196. return -1;
  197. }
  198. $this->db->begin();
  199. $sql = 'DELETE FROM '.MAIN_DB_PREFIX.'categorie_association';
  200. $sql.= ' WHERE fk_categorie_fille = '.$this->id;
  201. dol_syslog("Categorie::update sql=".$sql);
  202. if (! $this->db->query($sql))
  203. {
  204. $this->db->rollback();
  205. dol_print_error($this->db);
  206. return -1;
  207. }
  208. if($this->id_mere !="" && $this->id_mere!=$this->id)
  209. {
  210. $sql = 'INSERT INTO '.MAIN_DB_PREFIX.'categorie_association(fk_categorie_mere,fk_categorie_fille)';
  211. $sql.= ' VALUES ('.$this->id_mere.', '.$this->id.')';
  212. dol_syslog("Categorie::update sql=".$sql);
  213. if (! $this->db->query($sql))
  214. {
  215. $this->db->rollback();
  216. dol_print_error($this->db);
  217. return -1;
  218. }
  219. }
  220. $sql = "UPDATE ".MAIN_DB_PREFIX."categorie";
  221. $sql.= " SET label = '".$this->db->escape($this->label)."'";
  222. if ($this->description)
  223. {
  224. $sql .= ", description = '".$this->db->escape($this->description)."'";
  225. }
  226. if ($conf->global->CATEGORY_ASSIGNED_TO_A_CUSTOMER)
  227. {
  228. $sql .= ", fk_soc = ".($this->socid != -1 ? $this->socid : 'null');
  229. }
  230. $sql .= ", visible = '".$this->visible."'";
  231. //$sql .= ", fk_parent_id = ".$this->parentId;
  232. $sql .= " WHERE rowid = ".$this->id;
  233. dol_syslog("Categorie::update sql=".$sql);
  234. if ($this->db->query($sql))
  235. {
  236. $this->db->commit();
  237. // Appel des triggers
  238. include_once(DOL_DOCUMENT_ROOT . "/core/class/interfaces.class.php");
  239. $interface=new Interfaces($this->db);
  240. $result=$interface->run_triggers('CATEGORY_MODIFY',$this,$user,$langs,$conf);
  241. if ($result < 0) { $error++; $this->errors=$interface->errors; }
  242. // Fin appel triggers
  243. return 1;
  244. }
  245. else
  246. {
  247. $this->db->rollback();
  248. dol_print_error($this->db);
  249. return -1;
  250. }
  251. }
  252. /**
  253. * Delete a category from database
  254. *
  255. * @param User $user Object user that ask to delete
  256. * @return void
  257. */
  258. function delete($user)
  259. {
  260. global $conf,$langs;
  261. $error=0;
  262. dol_syslog("Categorie::remove");
  263. $this->db->begin();
  264. if (! $error)
  265. {
  266. $sql = "DELETE FROM ".MAIN_DB_PREFIX."categorie_societe";
  267. $sql .= " WHERE fk_categorie = ".$this->id;
  268. if (!$this->db->query($sql))
  269. {
  270. $this->error=$this->db->lasterror();
  271. dol_syslog("Error sql=".$sql." ".$this->error, LOG_ERR);
  272. $error++;
  273. }
  274. }
  275. if (! $error)
  276. {
  277. $sql = "DELETE FROM ".MAIN_DB_PREFIX."categorie_fournisseur";
  278. $sql .= " WHERE fk_categorie = ".$this->id;
  279. if (!$this->db->query($sql))
  280. {
  281. $this->error=$this->db->lasterror();
  282. dol_syslog("Error sql=".$sql." ".$this->error, LOG_ERR);
  283. $error++;
  284. }
  285. }
  286. if (! $error)
  287. {
  288. $sql = "DELETE FROM ".MAIN_DB_PREFIX."categorie_product";
  289. $sql .= " WHERE fk_categorie = ".$this->id;
  290. if (!$this->db->query($sql))
  291. {
  292. $this->error=$this->db->lasterror();
  293. dol_syslog("Error sql=".$sql." ".$this->error, LOG_ERR);
  294. $error++;
  295. }
  296. }
  297. if (! $error)
  298. {
  299. $sql = "DELETE FROM ".MAIN_DB_PREFIX."categorie_member";
  300. $sql .= " WHERE fk_categorie = ".$this->id;
  301. if (!$this->db->query($sql))
  302. {
  303. $this->error=$this->db->lasterror();
  304. dol_syslog("Error sql=".$sql." ".$this->error, LOG_ERR);
  305. $error++;
  306. }
  307. }
  308. // Link childs to parent
  309. if (! $error)
  310. {
  311. $sql = "DELETE FROM ".MAIN_DB_PREFIX."categorie_association";
  312. $sql .= " WHERE fk_categorie_mere = ".$this->id;
  313. $sql .= " OR fk_categorie_fille = ".$this->id;
  314. if (!$this->db->query($sql))
  315. {
  316. $this->error=$this->db->lasterror();
  317. dol_syslog("Error sql=".$sql." ".$this->error, LOG_ERR);
  318. $error++;
  319. }
  320. }
  321. // Delete category
  322. if (! $error)
  323. {
  324. $sql = "DELETE FROM ".MAIN_DB_PREFIX."categorie";
  325. $sql .= " WHERE rowid = ".$this->id;
  326. if (!$this->db->query($sql))
  327. {
  328. $this->error=$this->db->lasterror();
  329. dol_syslog("Error sql=".$sql." ".$this->error, LOG_ERR);
  330. $error++;
  331. }
  332. else
  333. {
  334. // Appel des triggers
  335. include_once(DOL_DOCUMENT_ROOT . "/core/class/interfaces.class.php");
  336. $interface=new Interfaces($this->db);
  337. $result=$interface->run_triggers('CATEGORY_DELETE',$this,$user,$langs,$conf);
  338. if ($result < 0) { $error++; $this->errors=$interface->errors; $this->error=join(',',$this->errors); }
  339. // Fin appel triggers
  340. }
  341. }
  342. if (! $error)
  343. {
  344. $this->db->commit();
  345. return 1;
  346. }
  347. else
  348. {
  349. $this->db->rollback();
  350. return -1;
  351. }
  352. }
  353. /**
  354. * Ajout d'une sous-categorie
  355. *
  356. * @return int 1 : OK
  357. * -2 : $fille est deja dans la famille de $this
  358. * -3 : categorie ($this ou $fille) invalide
  359. */
  360. function add_fille()
  361. {
  362. $sql = "INSERT INTO ".MAIN_DB_PREFIX."categorie_association (fk_categorie_mere, fk_categorie_fille)";
  363. $sql.= " VALUES (".$this->id_mere.", ".$this->id.")";
  364. if ($this->db->query($sql))
  365. {
  366. return 1;
  367. }
  368. else
  369. {
  370. dol_print_error($this->db);
  371. return -1;
  372. }
  373. }
  374. /**
  375. * Suppression d'une sous-categorie (seulement "desassociation")
  376. *
  377. * @param Category $fille Objet category
  378. * @return int 1 : OK
  379. * -3 : categorie ($this ou $fille) invalide
  380. */
  381. function del_fille($fille)
  382. {
  383. if (!$this->check() || !$fille->check())
  384. {
  385. return -3;
  386. }
  387. $sql = "DELETE FROM ".MAIN_DB_PREFIX."categorie_association";
  388. $sql .= " WHERE fk_categorie_mere = ".$this->id." and fk_categorie_fille = ".$fille->id;
  389. if ($this->db->query($sql))
  390. {
  391. return 1;
  392. }
  393. else
  394. {
  395. $this->error=$this->db->error().' sql='.$sql;
  396. return -1;
  397. }
  398. }
  399. /**
  400. * Link an object to the category
  401. *
  402. * @param Object $obj Object to link to category
  403. * @param string $type Type of category
  404. * @return int 1 : OK, -1 : erreur SQL, -2 : id non renseign, -3 : Already linked
  405. */
  406. function add_type($obj,$type)
  407. {
  408. if ($this->id == -1)
  409. {
  410. return -2;
  411. }
  412. $sql = "INSERT INTO ".MAIN_DB_PREFIX."categorie_".$type." (fk_categorie, fk_".($type=='fournisseur'?'societe':$type).")";
  413. $sql .= " VALUES (".$this->id.", ".$obj->id.")";
  414. if ($this->db->query($sql))
  415. {
  416. return 1;
  417. }
  418. else
  419. {
  420. if ($this->db->lasterrno() == 'DB_ERROR_RECORD_ALREADY_EXISTS')
  421. {
  422. $this->error=$this->db->lasterrno();
  423. return -3;
  424. }
  425. else
  426. {
  427. $this->error=$this->db->error().' sql='.$sql;
  428. }
  429. return -1;
  430. }
  431. }
  432. /**
  433. * Delete object from category
  434. *
  435. * @param Object $obj Object
  436. * @param string $type Type
  437. * @return int 1 if OK, -1 if KO
  438. */
  439. function del_type($obj,$type)
  440. {
  441. $sql = "DELETE FROM ".MAIN_DB_PREFIX."categorie_".$type;
  442. $sql .= " WHERE fk_categorie = ".$this->id;
  443. $sql .= " AND fk_".($type=='fournisseur'?'societe':$type)." = ".$obj->id;
  444. if ($this->db->query($sql))
  445. {
  446. return 1;
  447. }
  448. else
  449. {
  450. $this->error=$this->db->error().' sql='.$sql;
  451. return -1;
  452. }
  453. }
  454. /**
  455. * Return list of contents of a category
  456. *
  457. * @param string $field Field name for select in table. Full field name will be fk_field.
  458. * @param string $classname PHP Class of object to store entity
  459. * @param string $table Table name for select in table. Full table name will be PREFIX_categorie_table.
  460. * @return void
  461. */
  462. function get_type($field,$classname,$table='')
  463. {
  464. $objs = array();
  465. // Clean parameters
  466. if (empty($table)) $table=$field;
  467. $sql = "SELECT fk_".$field." FROM ".MAIN_DB_PREFIX."categorie_".$table;
  468. $sql.= " WHERE fk_categorie = ".$this->id;
  469. dol_syslog("Categorie::get_type sql=".$sql);
  470. $resql = $this->db->query($sql);
  471. if ($resql)
  472. {
  473. while ($rec = $this->db->fetch_array($resql))
  474. {
  475. $obj = new $classname($this->db);
  476. $obj->fetch($rec['fk_'.$field]);
  477. $objs[] = $obj;
  478. }
  479. return $objs;
  480. }
  481. else
  482. {
  483. $this->error=$this->db->error().' sql='.$sql;
  484. dol_syslog("Categorie::get_type ".$this->error, LOG_ERR);
  485. return -1;
  486. }
  487. }
  488. /**
  489. * Retourne les filles de la categorie
  490. *
  491. * @return void
  492. */
  493. function get_filles()
  494. {
  495. $sql = "SELECT fk_categorie_fille FROM ".MAIN_DB_PREFIX."categorie_association ";
  496. $sql .= "WHERE fk_categorie_mere = ".$this->id;
  497. $res = $this->db->query($sql);
  498. if ($res)
  499. {
  500. $cats = array ();
  501. while ($rec = $this->db->fetch_array($res))
  502. {
  503. $cat = new Categorie($this->db, $rec['fk_categorie_fille']);
  504. $cats[] = $cat;
  505. }
  506. return $cats;
  507. }
  508. else
  509. {
  510. dol_print_error($this->db);
  511. return -1;
  512. }
  513. }
  514. /**
  515. * Return category description
  516. *
  517. * @param int $cate Category id
  518. * @return string Description
  519. */
  520. function get_desc($cate)
  521. {
  522. $sql = "SELECT description FROM ".MAIN_DB_PREFIX."categorie ";
  523. $sql .= "WHERE rowid = ".$cate;
  524. $res = $this->db->query($sql);
  525. $n = $this->db->fetch_array($res);
  526. return($n[0]);
  527. }
  528. /**
  529. * La categorie $fille est-elle une fille de cette categorie ?
  530. *
  531. * @param Category $fille Object category
  532. * @return void
  533. */
  534. function is_fille($fille)
  535. {
  536. $sql = "SELECT count(fk_categorie_fille) FROM ".MAIN_DB_PREFIX."categorie_association ";
  537. $sql .= "WHERE fk_categorie_mere = ".$this->id." AND fk_categorie_fille = ".$fille->id;
  538. $res = $this->db->query($sql);
  539. $n = $this->db->fetch_array($res);
  540. return ($n[0] > 0);
  541. }
  542. /**
  543. * Reconstruit l'arborescence des categories sous la forme d'un tableau
  544. * Renvoi un tableau de tableau('id','id_mere',...) trie selon arbre et avec:
  545. * id = id de la categorie
  546. * id_mere = id de la categorie mere
  547. * id_children = tableau des id enfant
  548. * label = nom de la categorie
  549. * fulllabel = nom avec chemin complet de la categorie
  550. * fullpath = chemin complet compose des id
  551. *
  552. * @param string $type Type of categories (0=product, 1=suppliers, 2=customers, 3=members)
  553. * @param int $markafterid Mark all categories after this leaf in category tree.
  554. * @return array Array of categories
  555. */
  556. function get_full_arbo($type,$markafterid=0)
  557. {
  558. global $conf;
  559. $this->cats = array();
  560. // Charge tableau des meres
  561. $sql = "SELECT ca.fk_categorie_mere as id_mere, ca.fk_categorie_fille as id_fille";
  562. $sql.= " FROM ".MAIN_DB_PREFIX."categorie_association ca";
  563. $sql.= ", ".MAIN_DB_PREFIX."categorie as c";
  564. $sql.= " WHERE ca.fk_categorie_mere = c.rowid";
  565. $sql.= " AND c.entity = ".$conf->entity;
  566. // Load array this->motherof
  567. dol_syslog("Categorie::get_full_arbo build motherof array sql=".$sql, LOG_DEBUG);
  568. $resql = $this->db->query($sql);
  569. if ($resql)
  570. {
  571. while ($obj=$this->db->fetch_object($resql))
  572. {
  573. $this->motherof[$obj->id_fille]=$obj->id_mere;
  574. }
  575. }
  576. else
  577. {
  578. dol_print_error($this->db);
  579. return -1;
  580. }
  581. // Init $this->cats array
  582. $sql = "SELECT DISTINCT c.rowid, c.label as label, ca.fk_categorie_fille as rowid_fille"; // Distinct reduce pb with old tables with duplicates
  583. $sql.= " FROM ".MAIN_DB_PREFIX."categorie as c";
  584. $sql.= " LEFT JOIN ".MAIN_DB_PREFIX."categorie_association as ca";
  585. $sql.= " ON c.rowid = ca.fk_categorie_mere";
  586. $sql.= " WHERE c.type = ".$type;
  587. $sql.= " AND c.entity = ".$conf->entity;
  588. $sql.= " ORDER BY c.label, c.rowid";
  589. dol_syslog("Categorie::get_full_arbo get category list sql=".$sql, LOG_DEBUG);
  590. $resql = $this->db->query($sql);
  591. if ($resql)
  592. {
  593. $i=0;
  594. while ($obj = $this->db->fetch_object($resql))
  595. {
  596. $this->cats[$obj->rowid]['id'] = $obj->rowid;
  597. if (isset($this->motherof[$obj->rowid])) $this->cats[$obj->rowid]['id_mere'] = $this->motherof[$obj->rowid];
  598. $this->cats[$obj->rowid]['label'] = $obj->label;
  599. if ($obj->rowid_fille)
  600. {
  601. $this->cats[$obj->rowid]['id_children'][]=$obj->rowid_fille;
  602. }
  603. $i++;
  604. }
  605. }
  606. else
  607. {
  608. dol_print_error($this->db);
  609. return -1;
  610. }
  611. // We add the fullpath property to each elements of first level (no parent exists)
  612. dol_syslog("Categorie::get_full_arbo call to build_path_from_id_categ", LOG_DEBUG);
  613. foreach($this->cats as $key => $val)
  614. {
  615. if (isset($this->motherof[$key])) continue;
  616. $this->build_path_from_id_categ($key,0); // Process a branch from the root category key (this category has no parent)
  617. }
  618. // Exclude tree for $markafterid
  619. if ($markafterid)
  620. {
  621. //print "Look to discard category ".$markafterid."\n";
  622. $keyfilter1='^'.$markafterid.'$';
  623. $keyfilter2='_'.$markafterid.'$';
  624. $keyfilter3='^'.$markafterid.'_';
  625. $keyfilter4='_'.$markafterid.'_';
  626. foreach($this->cats as $key => $val)
  627. {
  628. if (preg_match('/'.$keyfilter1.'/',$val['fullpath']) || preg_match('/'.$keyfilter2.'/',$val['fullpath'])
  629. || preg_match('/'.$keyfilter3.'/',$val['fullpath']) || preg_match('/'.$keyfilter4.'/',$val['fullpath']))
  630. {
  631. //print "Categ discarded ".$this->cats[$key]['fullpath']."\n";
  632. //$this->cats[$key]['marked']=1;
  633. unset($this->cats[$key]);
  634. }
  635. }
  636. }
  637. dol_syslog("Categorie::get_full_arbo dol_sort_array", LOG_DEBUG);
  638. $this->cats=dol_sort_array($this->cats, 'fulllabel', 'asc', true, false);
  639. //$this->debug_cats();
  640. return $this->cats;
  641. }
  642. /**
  643. * For category id_categ and its childs available in this->cats, define property fullpath and fulllabel
  644. *
  645. * @param int $id_categ id_categ entry to update
  646. * @param int $protection Deep counter to avoid infinite loop
  647. * @return void
  648. */
  649. function build_path_from_id_categ($id_categ,$protection=0)
  650. {
  651. dol_syslog("Categorie::build_path_from_id_categ id_categ=".$id_categ." protection=".$protection, LOG_DEBUG);
  652. //if (! empty($this->cats[$id_categ]['fullpath']))
  653. //{
  654. // Already defined
  655. // dol_syslog("Categorie::build_path_from_id_categ fullpath and fulllabel already defined", LOG_WARNING);
  656. // return;
  657. //}
  658. // Define fullpath and fulllabel
  659. if (isset($this->cats[$id_categ]['id_mere']))
  660. {
  661. $this->cats[$id_categ]['fullpath'] =$this->cats[$this->cats[$id_categ]['id_mere']]['fullpath'];
  662. $this->cats[$id_categ]['fullpath'].='_'.$id_categ;
  663. $this->cats[$id_categ]['fulllabel'] =$this->cats[$this->cats[$id_categ]['id_mere']]['fulllabel'];
  664. $this->cats[$id_categ]['fulllabel'].=' >> '.$this->cats[$id_categ]['label'];
  665. }
  666. else
  667. {
  668. $this->cats[$id_categ]['fullpath']='_'.$id_categ;
  669. $this->cats[$id_categ]['fulllabel']=$this->cats[$id_categ]['label'];
  670. }
  671. // We count number of _ to have level
  672. $this->cats[$id_categ]['level']=dol_strlen(preg_replace('/[^_]/i','',$this->cats[$id_categ]['fullpath']));
  673. // Process all childs on several levels of this category
  674. $protection++;
  675. if ($protection > 10) return; // On ne traite pas plus de 10 niveaux de profondeurs
  676. if (! is_array($this->cats[$id_categ]['id_children'])) return;
  677. foreach($this->cats[$id_categ]['id_children'] as $key => $idchild)
  678. {
  679. // Protection when a category has itself as a child (should not happen)
  680. if ($idchild == $id_categ)
  681. {
  682. dol_syslog("Categorie::build_path_from_id_categ bad couple (".$idchild.",".$id_categ.") in association table: An entry should not have itself has child", LOG_WARNING);
  683. continue;
  684. }
  685. $this->build_path_from_id_categ($idchild,$protection);
  686. }
  687. return;
  688. }
  689. /**
  690. * Affiche contenu de $this->cats
  691. *
  692. * @return void
  693. */
  694. function debug_cats()
  695. {
  696. // Affiche $this->cats
  697. foreach($this->cats as $key => $val)
  698. {
  699. print 'id: '.$this->cats[$key]['id'];
  700. print ' label: '.$this->cats[$key]['label'];
  701. print ' mother: '.$this->cats[$key]['id_mere'];
  702. print ' children: '.(is_array($this->cats[$key]['id_children'])?join(',',$this->cats[$key]['id_children']):'');
  703. print ' fullpath: '.$this->cats[$key]['fullpath'];
  704. print ' fulllabel: '.$this->cats[$key]['fulllabel'];
  705. print "<br>\n";
  706. }
  707. }
  708. /**
  709. * Retourne toutes les categories
  710. *
  711. * @return array Tableau d'objet Categorie
  712. */
  713. function get_all_categories ()
  714. {
  715. $sql = "SELECT rowid FROM ".MAIN_DB_PREFIX."categorie";
  716. $res = $this->db->query($sql);
  717. if ($res)
  718. {
  719. $cats = array ();
  720. while ($record = $this->db->fetch_array($res))
  721. {
  722. $cat = new Categorie($this->db, $record['rowid']);
  723. $cats[$record['rowid']] = $cat;
  724. }
  725. return $cats;
  726. }
  727. else
  728. {
  729. dol_print_error($this->db);
  730. return -1;
  731. }
  732. }
  733. /**
  734. * Retourne le nombre total de categories
  735. *
  736. * @return int Nombre de categories
  737. */
  738. function get_nb_categories()
  739. {
  740. $sql = "SELECT count(rowid)";
  741. $sql.= " FROM ".MAIN_DB_PREFIX."categorie";
  742. $res = $this->db->query($sql);
  743. if ($res)
  744. {
  745. $res = $this->db->fetch_array($res);
  746. return $res[0];
  747. }
  748. else
  749. {
  750. dol_print_error($this->db);
  751. return -1;
  752. }
  753. }
  754. /**
  755. * Check if no category with same label already exists for this cat's parent or root and for this cat's type
  756. *
  757. * @return boolean 1 if already exist, 0 otherwise, -1 if error
  758. */
  759. function already_exists()
  760. {
  761. if($this->id_mere != "") // mother_id defined
  762. {
  763. /* We have to select any rowid from llx_categorie which category's mother and label
  764. * are equals to those of the calling category
  765. */
  766. $sql = "SELECT c.rowid";
  767. $sql.= " FROM ".MAIN_DB_PREFIX."categorie as c ";
  768. $sql.= " JOIN ".MAIN_DB_PREFIX."categorie_association as ca";
  769. $sql.= " ON c.rowid=ca.fk_categorie_fille";
  770. $sql.= " WHERE ca.fk_categorie_mere=".$this->id_mere;
  771. $sql.= " AND c.label='".$this->db->escape($this->label)."'";
  772. }
  773. else // mother_id undefined (so it's root)
  774. {
  775. /* We have to select any rowid from llx_categorie which which category's type and label
  776. * are equals to those of the calling category, AND which doesn't exist in categorie association
  777. * as children (rowid != fk_categorie_fille)
  778. */
  779. $sql = "SELECT c.rowid";
  780. $sql.= " FROM ".MAIN_DB_PREFIX."categorie as c ";
  781. $sql.= " JOIN ".MAIN_DB_PREFIX."categorie_association as ca";
  782. $sql.= " ON c.rowid!=ca.fk_categorie_fille";
  783. $sql.= " WHERE c.type=".$this->type;
  784. $sql.= " AND c.label='".$this->db->escape($this->label)."'";
  785. }
  786. dol_syslog("Categorie::already_exists sql=".$sql);
  787. $res = $this->db->query($sql);
  788. if ($res)
  789. {
  790. if($this->db->num_rows($resql) > 0) // Checking for empty resql
  791. {
  792. $obj = $this->db->fetch_array($res);
  793. /* If object called create, obj cannot have is id.
  794. * If object called update, he mustn't have the same label as an other category for this mother.
  795. * So if the result have the same id, update is not for label, and if result have an other one,
  796. * update may be for label.
  797. */
  798. if($obj[0] > 0 && $obj[0] != $this->id) return 1;
  799. }
  800. return 0;
  801. }
  802. else
  803. {
  804. dol_print_error($this->db);
  805. return -1;
  806. }
  807. }
  808. /**
  809. * Retourne les categories de premier niveau (qui ne sont pas filles)
  810. *
  811. * @return void
  812. */
  813. function get_main_categories()
  814. {
  815. $allcats = $this->get_all_categories();
  816. $maincats = array ();
  817. $filles = array ();
  818. $sql = "SELECT fk_categorie_fille FROM ".MAIN_DB_PREFIX."categorie_association";
  819. $res = $this->db->query($sql);
  820. while ($res = $this->db->fetch_array($res))
  821. {
  822. $filles[] = $res['fk_categorie_fille'];
  823. }
  824. foreach ($allcats as $cat)
  825. {
  826. if (! in_array($cat->id, $filles))
  827. {
  828. $maincats[] = $cat;
  829. }
  830. }
  831. return $maincats;
  832. }
  833. /**
  834. * Retourne les chemin de la categorie, avec les noms des categories
  835. * separes par $sep (" >> " par defaut)
  836. *
  837. * @param string $sep Separator
  838. * @param string $url Url
  839. * @return void
  840. */
  841. function print_all_ways ($sep = " &gt;&gt; ", $url='')
  842. {
  843. $ways = array ();
  844. foreach ($this->get_all_ways() as $way)
  845. {
  846. $w = array ();
  847. foreach ($way as $cat)
  848. {
  849. if ($url == '')
  850. {
  851. $w[] = "<a href='".DOL_URL_ROOT."/categories/viewcat.php?id=".$cat->id."&amp;type=".$cat->type."'>".$cat->label."</a>";
  852. }
  853. else
  854. {
  855. $w[] = "<a href='".DOL_URL_ROOT."/$url?catid=".$cat->id."'>".$cat->label."</a>";
  856. }
  857. }
  858. $ways[] = implode($sep, $w);
  859. }
  860. return $ways;
  861. }
  862. /**
  863. * Affiche le chemin le plus court pour se rendre a un produit
  864. *
  865. * @param int $id Id of category
  866. * @param string $type Type of category
  867. * @return void
  868. */
  869. function get_primary_way($id, $type="")
  870. {
  871. $primary_way = Array("taille"=>-1,"chemin"=>Array());
  872. $meres = $this->containing($id,$type);
  873. foreach ($meres as $mere)
  874. {
  875. foreach ($mere->get_all_ways() as $way)
  876. {
  877. if(count($way) < $primary_way["taille"] || $primary_way["taille"] < 0)
  878. {
  879. $primary_way["taille"] = count($way);
  880. $primary_way["chemin"] = $way;
  881. }
  882. }
  883. }
  884. return $primary_way["chemin"];
  885. }
  886. /**
  887. * Affiche le chemin le plus court pour se rendre a un produit
  888. *
  889. * @param int $id Id of category
  890. * @param string $sep Separator
  891. * @param string $url Url
  892. * @param string $type Type
  893. * @return void
  894. */
  895. function print_primary_way($id, $sep= " &gt;&gt; ", $url="", $type="")
  896. {
  897. $primary_way = Array();
  898. $way = $this->get_primary_way($id,$type);
  899. $w = array();
  900. foreach ($way as $cat)
  901. {
  902. if ($url == '')
  903. {
  904. $w[] = "<a href='".DOL_URL_ROOT."/categories/viewcat.php?id=".$cat->id."'>".$cat->label."</a>";
  905. }
  906. else
  907. {
  908. $w[] = "<a href='".DOL_URL_ROOT."/".$url."?catid=".$cat->id."'>".$cat->label."</a>";
  909. }
  910. }
  911. return implode($sep, $w);
  912. }
  913. /**
  914. * Retourne un tableau contenant la liste des categories meres
  915. *
  916. * @return void
  917. */
  918. function get_meres()
  919. {
  920. $meres = array();
  921. $sql = "SELECT fk_categorie_mere FROM ".MAIN_DB_PREFIX."categorie_association ";
  922. $sql .= "WHERE fk_categorie_fille = ".$this->id;
  923. $res = $this->db->query($sql);
  924. if ($res)
  925. {
  926. while ($cat = $this->db->fetch_array($res))
  927. {
  928. $meres[] = new Categorie($this->db, $cat['fk_categorie_mere']);
  929. }
  930. return $meres;
  931. }
  932. else
  933. {
  934. dol_print_error($this->db);
  935. return -1;
  936. }
  937. }
  938. /**
  939. * Retourne dans un tableau tous les chemins possibles pour arriver a la categorie
  940. * en partant des categories principales, representes par des tableaux de categories
  941. *
  942. * @return void
  943. */
  944. function get_all_ways ()
  945. {
  946. $ways = array ();
  947. foreach ($this->get_meres() as $mere)
  948. {
  949. foreach ($mere->get_all_ways() as $way)
  950. {
  951. $w = $way;
  952. $w[] = $this;
  953. $ways[] = $w;
  954. }
  955. }
  956. if (count($ways) == 0)
  957. $ways[0][0] = $this;
  958. return $ways;
  959. }
  960. /**
  961. * Return list of categories linked to element of type $type with id $typeid
  962. *
  963. * @param int $id Id of element
  964. * @param int $typeid Type id of link (0,1,2,3...)
  965. * @return array List of category objects
  966. */
  967. function containing($id,$typeid)
  968. {
  969. $cats = array ();
  970. $table=''; $type='';
  971. if ($typeid == 0) { $table='product'; $type='product'; }
  972. if ($typeid == 1) { $table='societe'; $type='fournisseur'; }
  973. if ($typeid == 2) { $table='societe'; $type='societe'; }
  974. if ($typeid == 3) { $table='member'; $type='member'; }
  975. $sql = "SELECT ct.fk_categorie";
  976. $sql.= " FROM ".MAIN_DB_PREFIX."categorie_".$type." as ct";
  977. $sql.= " LEFT JOIN ".MAIN_DB_PREFIX."categorie as c ON ct.fk_categorie = c.rowid";
  978. $sql.= " WHERE ct.fk_".$table." = ".$id." AND c.type = ".$typeid;
  979. $res = $this->db->query($sql);
  980. if ($res)
  981. {
  982. while ($cat = $this->db->fetch_array($res))
  983. {
  984. $cats[] = new Categorie($this->db, $cat['fk_categorie']);
  985. }
  986. return $cats;
  987. }
  988. else
  989. {
  990. dol_print_error($this->db);
  991. return -1;
  992. }
  993. }
  994. /**
  995. * Retourne les categories dont l'id ou le nom correspond
  996. * ajoute des wildcards au nom sauf si $exact = true
  997. *
  998. * @param int $id Id
  999. * @param string $nom Name
  1000. * @param string $type Type
  1001. * @param boolean $exact Ture or false
  1002. * @return array Array of category id
  1003. */
  1004. function rechercher($id, $nom, $type, $exact = false)
  1005. {
  1006. $cats = array ();
  1007. // Generation requete recherche
  1008. $sql = "SELECT rowid FROM ".MAIN_DB_PREFIX."categorie ";
  1009. $sql .= "WHERE type = ".$type." ";
  1010. if ($nom)
  1011. {
  1012. if (! $exact)
  1013. {
  1014. $nom = '%'.str_replace('*', '%', $nom).'%';
  1015. }
  1016. $sql.= "AND label LIKE '".$nom."'";
  1017. }
  1018. if ($id)
  1019. {
  1020. $sql.="AND rowid = '".$id."'";
  1021. }
  1022. $res = $this->db->query($sql);
  1023. if ($res)
  1024. {
  1025. while ($id = $this->db->fetch_array($res))
  1026. {
  1027. $cats[] = new Categorie($this->db, $id['rowid']);
  1028. }
  1029. return $cats;
  1030. }
  1031. else
  1032. {
  1033. $this->error=$this->db->error().' sql='.$sql;
  1034. dol_syslog("Categorie::rechercher ".$this->error, LOG_ERR);
  1035. return -1;
  1036. }
  1037. }
  1038. /**
  1039. * Return name and link of category (with picto)
  1040. *
  1041. * @param int $withpicto 0=Pas de picto, 1=Inclut le picto dans le lien, 2=Picto seul
  1042. * @param string $option Sur quoi pointe le lien ('', 'xyz')
  1043. * @param int $maxlength Max length of text
  1044. * @return string Chaine avec URL
  1045. */
  1046. function getNomUrl($withpicto=0,$option='',$maxlength=0)
  1047. {
  1048. global $langs;
  1049. $result='';
  1050. $lien = '<a href="'.DOL_URL_ROOT.'/categories/viewcat.php?id='.$this->id.'&type='.$this->type.'">';
  1051. $label=$langs->trans("ShowCategory").': '.$this->label;
  1052. $lienfin='</a>';
  1053. $picto='category';
  1054. if ($withpicto) $result.=($lien.img_object($label,$picto).$lienfin);
  1055. if ($withpicto && $withpicto != 2) $result.=' ';
  1056. if ($withpicto != 2) $result.=$lien.dol_trunc($this->ref,$maxlength).$lienfin;
  1057. return $result;
  1058. }
  1059. /**
  1060. * Deplace fichier uploade sous le nom $files dans le repertoire sdir
  1061. *
  1062. * @param string $sdir Repertoire destination finale
  1063. * @param string $file Nom du fichier uploade
  1064. * @param int $maxWidth Largeur maximum que dois faire la miniature (160 par defaut)
  1065. * @param int $maxHeight Hauteur maximum que dois faire la miniature (120 par defaut)
  1066. * @return void
  1067. */
  1068. function add_photo($sdir, $file, $maxWidth = 160, $maxHeight = 120)
  1069. {
  1070. require_once(DOL_DOCUMENT_ROOT."/core/lib/files.lib.php");
  1071. $dir = $sdir .'/'. get_exdir($this->id,2) . $this->id ."/";
  1072. $dir .= "photos/";
  1073. if (! file_exists($dir))
  1074. {
  1075. create_exdir($dir);
  1076. }
  1077. if (file_exists($dir))
  1078. {
  1079. $originImage = $dir . $file['name'];
  1080. // Cree fichier en taille origine
  1081. $result=dol_move_uploaded_file($file['tmp_name'], $originImage, 1, 0, 0);
  1082. if (file_exists($originImage))
  1083. {
  1084. // Cree fichier en taille vignette
  1085. $this->add_thumb($originImage,$maxWidth,$maxHeight);
  1086. }
  1087. }
  1088. }
  1089. /**
  1090. * Build thumb
  1091. *
  1092. * @param string $file Chemin du fichier d'origine
  1093. * @param int $maxWidth Largeur maximum que dois faire la miniature (160 par defaut)
  1094. * @param int $maxHeight Hauteur maximum que dois faire la miniature (120 par defaut)
  1095. * @return void
  1096. */
  1097. function add_thumb($file, $maxWidth = 160, $maxHeight = 120)
  1098. {
  1099. require_once(DOL_DOCUMENT_ROOT ."/core/lib/images.lib.php");
  1100. if (file_exists($file))
  1101. {
  1102. vignette($file,$maxWidth,$maxHeight);
  1103. }
  1104. }
  1105. /**
  1106. * Return tableau de toutes les photos de la categorie
  1107. *
  1108. * @param string $dir Repertoire a scanner
  1109. * @param int $nbmax Nombre maximum de photos (0=pas de max)
  1110. * @return array Tableau de photos
  1111. */
  1112. function liste_photos($dir,$nbmax=0)
  1113. {
  1114. $nbphoto=0;
  1115. $tabobj=array();
  1116. $dirthumb = $dir.'thumbs/';
  1117. if (file_exists($dir))
  1118. {
  1119. $handle=opendir($dir);
  1120. if (is_resource($handle))
  1121. {
  1122. while (($file = readdir($handle)) != false)
  1123. {
  1124. if (is_file($dir.$file))
  1125. {
  1126. $nbphoto++;
  1127. $photo = $file;
  1128. // On determine nom du fichier vignette
  1129. $photo_vignette='';
  1130. if (preg_match('/(\.jpg|\.bmp|\.gif|\.png|\.tiff)$/i',$photo,$regs))
  1131. {
  1132. $photo_vignette=preg_replace('/'.$regs[0].'/i','',$photo).'_small'.$regs[0];
  1133. }
  1134. // Objet
  1135. $obj=array();
  1136. $obj['photo']=$photo;
  1137. if ($photo_vignette && is_file($dirthumb.$photo_vignette)) $obj['photo_vignette']=$photo_vignette;
  1138. else $obj['photo_vignette']="";
  1139. $tabobj[$nbphoto-1]=$obj;
  1140. // On continue ou on arrete de boucler
  1141. if ($nbmax && $nbphoto >= $nbmax) break;
  1142. }
  1143. }
  1144. closedir($handle);
  1145. }
  1146. }
  1147. return $tabobj;
  1148. }
  1149. /**
  1150. * Efface la photo de la categorie et sa vignette
  1151. *
  1152. * @param string $file Path to file
  1153. * @return void
  1154. */
  1155. function delete_photo($file)
  1156. {
  1157. require_once(DOL_DOCUMENT_ROOT."/core/lib/files.lib.php");
  1158. $dir = dirname($file).'/'; // Chemin du dossier contenant l'image d'origine
  1159. $dirthumb = $dir.'/thumbs/'; // Chemin du dossier contenant la vignette
  1160. $filename = preg_replace('/'.preg_quote($dir,'/').'/i','',$file); // Nom du fichier
  1161. // On efface l'image d'origine
  1162. dol_delete_file($file,1);
  1163. // Si elle existe, on efface la vignette
  1164. if (preg_match('/(\.jpg|\.bmp|\.gif|\.png|\.tiff)$/i',$filename,$regs))
  1165. {
  1166. $photo_vignette=preg_replace('/'.$regs[0].'/i','',$filename).'_small'.$regs[0];
  1167. if (file_exists($dirthumb.$photo_vignette))
  1168. {
  1169. dol_delete_file($dirthumb.$photo_vignette,1);
  1170. }
  1171. }
  1172. }
  1173. /**
  1174. * Load size of image file
  1175. *
  1176. * @param string $file Path to file
  1177. * @return void
  1178. */
  1179. function get_image_size($file)
  1180. {
  1181. $infoImg = getimagesize($file); // Recuperation des infos de l'image
  1182. $this->imgWidth = $infoImg[0]; // Largeur de l'image
  1183. $this->imgHeight = $infoImg[1]; // Hauteur de l'image
  1184. }
  1185. /**
  1186. * Initialise an instance with random values.
  1187. * Used to build previews or test instances.
  1188. * id must be 0 if object instance is a specimen.
  1189. *
  1190. * @return void
  1191. */
  1192. function initAsSpecimen()
  1193. {
  1194. global $user,$langs,$conf;
  1195. dol_syslog(get_class($this)."::initAsSpecimen");
  1196. // Initialise parametres
  1197. $this->id=0;
  1198. $this->id_mere=0;
  1199. $this->label = 'SPECIMEN';
  1200. $this->specimen=1;
  1201. $this->description = 'This is a description';
  1202. $this->socid = 1;
  1203. $this->type = 0;
  1204. }
  1205. }
  1206. ?>