extrafields.class.php 55 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710
  1. <?php
  2. /* Copyright (C) 2002-2003 Rodolphe Quiedeville <rodolphe@quiedeville.org>
  3. * Copyright (C) 2002-2003 Jean-Louis Bergamo <jlb@j1b.org>
  4. * Copyright (C) 2004 Sebastien Di Cintio <sdicintio@ressource-toi.org>
  5. * Copyright (C) 2004 Benoit Mortier <benoit.mortier@opensides.be>
  6. * Copyright (C) 2009-2012 Laurent Destailleur <eldy@users.sourceforge.net>
  7. * Copyright (C) 2009-2012 Regis Houssin <regis.houssin@capnetworks.com>
  8. * Copyright (C) 2013 Florian Henry <forian.henry@open-concept.pro>
  9. * Copyright (C) 2015 Charles-Fr BENKE <charles.fr@benke.fr>
  10. * Copyright (C) 2016 Raphaël Doursenaud <rdoursenaud@gpcsolutions.fr>
  11. *
  12. * This program is free software; you can redistribute it and/or modify
  13. * it under the terms of the GNU General Public License as published by
  14. * the Free Software Foundation; either version 3 of the License, or
  15. * (at your option) any later version.
  16. *
  17. * This program is distributed in the hope that it will be useful,
  18. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  19. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  20. * GNU General Public License for more details.
  21. *
  22. * You should have received a copy of the GNU General Public License
  23. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  24. */
  25. /**
  26. * \file htdocs/core/class/extrafields.class.php
  27. * \ingroup core
  28. * \brief File of class to manage extra fields
  29. */
  30. /**
  31. * Class to manage standard extra fields
  32. */
  33. class ExtraFields
  34. {
  35. var $db;
  36. // type of element (for what object is the extrafield)
  37. var $attribute_elementtype;
  38. // Array with type of the extra field
  39. var $attribute_type;
  40. // Array with label of extra field
  41. var $attribute_label;
  42. // Array with size of extra field
  43. var $attribute_size;
  44. // array with list of possible values for some types of extra fields
  45. var $attribute_choice;
  46. // Array to store compute formula for computed fields
  47. var $attribute_computed;
  48. // Array to store default value
  49. var $attribute_default;
  50. // Array to store if attribute is unique or not
  51. var $attribute_unique;
  52. // Array to store if attribute is required or not
  53. var $attribute_required;
  54. // Array to store parameters of attribute (used in select type)
  55. var $attribute_param;
  56. // Array to store position of attribute
  57. var $attribute_pos;
  58. // Array to store if attribute is editable regardless of the document status
  59. var $attribute_alwayseditable;
  60. // Array to store permission to check
  61. var $attribute_perms;
  62. // Array to store permission to check
  63. var $attribute_list;
  64. // Array to store if extra field is hidden
  65. var $attribute_hidden; // warning, do not rely on this. If your module need a hidden data, it must use its own table.
  66. var $error;
  67. var $errno;
  68. public static $type2label=array(
  69. 'varchar'=>'String',
  70. 'text'=>'TextLong',
  71. 'int'=>'Int',
  72. 'double'=>'Float',
  73. 'date'=>'Date',
  74. 'datetime'=>'DateAndTime',
  75. 'boolean'=>'Boolean',
  76. 'price'=>'ExtrafieldPrice',
  77. 'phone'=>'ExtrafieldPhone',
  78. 'mail'=>'ExtrafieldMail',
  79. 'url'=>'ExtrafieldUrl',
  80. 'password' => 'ExtrafieldPassword',
  81. 'select' => 'ExtrafieldSelect',
  82. 'sellist' => 'ExtrafieldSelectList',
  83. 'radio' => 'ExtrafieldRadio',
  84. 'checkbox' => 'ExtrafieldCheckBox',
  85. 'chkbxlst' => 'ExtrafieldCheckBoxFromList',
  86. 'link' => 'ExtrafieldLink',
  87. 'separate' => 'ExtrafieldSeparator',
  88. );
  89. /**
  90. * Constructor
  91. *
  92. * @param DoliDB $db Database handler
  93. */
  94. function __construct($db)
  95. {
  96. $this->db = $db;
  97. $this->error = array();
  98. $this->attribute_elementtype = array();
  99. $this->attribute_type = array();
  100. $this->attribute_label = array();
  101. $this->attribute_size = array();
  102. $this->attribute_computed = array();
  103. $this->attribute_default = array();
  104. $this->attribute_unique = array();
  105. $this->attribute_required = array();
  106. $this->attribute_perms = array();
  107. $this->attribute_list = array();
  108. $this->attribute_hidden = array();
  109. }
  110. /**
  111. * Add a new extra field parameter
  112. *
  113. * @param string $attrname Code of attribute
  114. * @param string $label label of attribute
  115. * @param int $type Type of attribute ('boolean', 'int', 'text', 'varchar', 'date', 'datehour','price','phone','mail','password','url','select','checkbox', ...)
  116. * @param int $pos Position of attribute
  117. * @param string $size Size/length of attribute
  118. * @param string $elementtype Element type ('member', 'product', 'thirdparty', ...)
  119. * @param int $unique Is field unique or not
  120. * @param int $required Is field required or not
  121. * @param string $default_value Defaulted value (In database. use the default_value feature for default value on screen. Example: '', '0', 'null', 'avalue')
  122. * @param array $param Params for field
  123. * @param int $alwayseditable Is attribute always editable regardless of the document status
  124. * @param string $perms Permission to check
  125. * @param int $list Into list view by default
  126. * @param int $ishidden Is hidden extrafield (warning, do not rely on this. If your module need a hidden data, it must use its own table)
  127. * @param string $computed Computed value
  128. * @return int <=0 if KO, >0 if OK
  129. */
  130. function addExtraField($attrname, $label, $type, $pos, $size, $elementtype, $unique=0, $required=0, $default_value='', $param=0, $alwayseditable=0, $perms='', $list=0, $ishidden=0, $computed='')
  131. {
  132. if (empty($attrname)) return -1;
  133. if (empty($label)) return -1;
  134. if ($elementtype == 'thirdparty') $elementtype='societe';
  135. if ($elementtype == 'contact') $elementtype='socpeople';
  136. // Create field into database except for separator type which is not stored in database
  137. if ($type != 'separate')
  138. {
  139. $result=$this->create($attrname, $type, $size, $elementtype, $unique, $required, $default_value, $param, $perms, $list, $copmputed);
  140. }
  141. $err1=$this->errno;
  142. if ($result > 0 || $err1 == 'DB_ERROR_COLUMN_ALREADY_EXISTS' || $type == 'separate')
  143. {
  144. // Add declaration of field into table
  145. $result2=$this->create_label($attrname, $label, $type, $pos, $size, $elementtype, $unique, $required, $param, $alwayseditable, $perms, $list, $ishidden, $default, $computed);
  146. $err2=$this->errno;
  147. if ($result2 > 0 || ($err1 == 'DB_ERROR_COLUMN_ALREADY_EXISTS' && $err2 == 'DB_ERROR_RECORD_ALREADY_EXISTS'))
  148. {
  149. $this->error='';
  150. $this->errno=0;
  151. return 1;
  152. }
  153. else return -2;
  154. }
  155. else
  156. {
  157. return -1;
  158. }
  159. }
  160. /**
  161. * Add a new optional attribute.
  162. * This is a private method. For public method, use addExtraField.
  163. *
  164. * @param string $attrname code of attribute
  165. * @param int $type Type of attribute ('boolean', 'int', 'text', 'varchar', 'date', 'datehour','price','phone','mail','password','url','select','checkbox', ...)
  166. * @param string $length Size/length of attribute ('5', '24,8', ...)
  167. * @param string $elementtype Element type ('member', 'product', 'thirdparty', 'contact', ...)
  168. * @param int $unique Is field unique or not
  169. * @param int $required Is field required or not
  170. * @param string $default_value Default value for field (in database)
  171. * @param array $param Params for field (ex for select list : array('options'=>array('value'=>'label of option'))
  172. * @param string $perms Permission
  173. * @param int $list Into list view by default
  174. * @param string $computed Computed value
  175. * @return int <=0 if KO, >0 if OK
  176. */
  177. private function create($attrname, $type='varchar', $length=255, $elementtype='member', $unique=0, $required=0, $default_value='',$param='', $perms='', $list=0, $computed='')
  178. {
  179. if ($elementtype == 'thirdparty') $elementtype='societe';
  180. if ($elementtype == 'contact') $elementtype='socpeople';
  181. $table=$elementtype.'_extrafields';
  182. if (! empty($attrname) && preg_match("/^\w[a-zA-Z0-9_]*$/",$attrname) && ! is_numeric($attrname))
  183. {
  184. if ($type=='boolean') {
  185. $typedb='int';
  186. $lengthdb='1';
  187. } elseif($type=='price') {
  188. $typedb='double';
  189. $lengthdb='24,8';
  190. } elseif($type=='phone') {
  191. $typedb='varchar';
  192. $lengthdb='20';
  193. } elseif($type=='mail') {
  194. $typedb='varchar';
  195. $lengthdb='128';
  196. } elseif($type=='url') {
  197. $typedb='varchar';
  198. $lengthdb='255';
  199. } elseif (($type=='select') || ($type=='sellist') || ($type=='radio') ||($type=='checkbox') ||($type=='chkbxlst')){
  200. $typedb='text';
  201. $lengthdb='';
  202. } elseif ($type=='link') {
  203. $typedb='int';
  204. $lengthdb='11';
  205. } elseif($type=='password') {
  206. $typedb='varchar';
  207. $lengthdb='50';
  208. } else {
  209. $typedb=$type;
  210. $lengthdb=$length;
  211. }
  212. $field_desc = array(
  213. 'type'=>$typedb,
  214. 'value'=>$lengthdb,
  215. 'null'=>($required?'NOT NULL':'NULL'),
  216. 'default' => $default_value
  217. );
  218. $result=$this->db->DDLAddField(MAIN_DB_PREFIX.$table, $attrname, $field_desc);
  219. if ($result > 0)
  220. {
  221. if ($unique)
  222. {
  223. $sql="ALTER TABLE ".MAIN_DB_PREFIX.$table." ADD UNIQUE INDEX uk_".$table."_".$attrname." (".$attrname.")";
  224. $resql=$this->db->query($sql,1,'dml');
  225. }
  226. return 1;
  227. }
  228. else
  229. {
  230. $this->error=$this->db->lasterror();
  231. $this->errno=$this->db->lasterrno();
  232. return -1;
  233. }
  234. }
  235. else
  236. {
  237. return 0;
  238. }
  239. }
  240. /**
  241. * Add description of a new optional attribute
  242. *
  243. * @param string $attrname code of attribute
  244. * @param string $label label of attribute
  245. * @param int $type Type of attribute ('int', 'text', 'varchar', 'date', 'datehour', 'float')
  246. * @param int $pos Position of attribute
  247. * @param string $size Size/length of attribute ('5', '24,8', ...)
  248. * @param string $elementtype Element type ('member', 'product', 'thirdparty', ...)
  249. * @param int $unique Is field unique or not
  250. * @param int $required Is field required or not
  251. * @param array||string $param Params for field (ex for select list : array('options' => array(value'=>'label of option')) )
  252. * @param int $alwayseditable Is attribute always editable regardless of the document status
  253. * @param string $perms Permission to check
  254. * @param int $list Into list view by default
  255. * @param int $ishidden Is hidden extrafield (warning, do not rely on this. If your module need a hidden data, it must use its own table)
  256. * @param string $default Default value (in database. use the default_value feature for default value on screen).
  257. * @param string $computed Computed value
  258. * @return int <=0 if KO, >0 if OK
  259. */
  260. private function create_label($attrname, $label='', $type='', $pos=0, $size=0, $elementtype='member', $unique=0, $required=0, $param='', $alwayseditable=0, $perms='', $list=0, $ishidden=0, $default='', $computed='')
  261. {
  262. global $conf;
  263. if ($elementtype == 'thirdparty') $elementtype='societe';
  264. if ($elementtype == 'contact') $elementtype='socpeople';
  265. // Clean parameters
  266. if (empty($pos)) $pos=0;
  267. if (empty($list)) $list=0;
  268. if (! empty($attrname) && preg_match("/^\w[a-zA-Z0-9-_]*$/",$attrname) && ! is_numeric($attrname))
  269. {
  270. if(is_array($param) && count($param) > 0)
  271. {
  272. $params = $this->db->escape(serialize($param));
  273. }
  274. elseif (strlen($param) > 0)
  275. {
  276. $params = trim($param);
  277. }
  278. else
  279. {
  280. $params='';
  281. }
  282. $sql = "INSERT INTO ".MAIN_DB_PREFIX."extrafields(name, label, type, pos, size, entity, elementtype, fieldunique, fieldrequired, param, alwayseditable, perms, list, ishidden, fielddefault, fieldcomputed)";
  283. $sql.= " VALUES('".$attrname."',";
  284. $sql.= " '".$this->db->escape($label)."',";
  285. $sql.= " '".$type."',";
  286. $sql.= " '".$pos."',";
  287. $sql.= " '".$size."',";
  288. $sql.= " ".$conf->entity.",";
  289. $sql.= " '".$elementtype."',";
  290. $sql.= " '".$unique."',";
  291. $sql.= " '".$required."',";
  292. $sql.= " '".$params."',";
  293. $sql.= " '".$alwayseditable."',";
  294. $sql.= " ".($perms?"'".$this->db->escape($perms)."'":"null").",";
  295. $sql.= " ".$list.",";
  296. $sql.= " ".$ishidden.",";
  297. $sql.= " ".($default?"'".$this->db->escape($default)."'":"null").",";
  298. $sql.= " ".($computed?"'".$this->db->escape($computed)."'":"null");
  299. $sql.=')';
  300. dol_syslog(get_class($this)."::create_label", LOG_DEBUG);
  301. if ($this->db->query($sql))
  302. {
  303. return 1;
  304. }
  305. else
  306. {
  307. $this->error=$this->db->lasterror();
  308. $this->errno=$this->db->lasterrno();
  309. return -1;
  310. }
  311. }
  312. }
  313. /**
  314. * Delete an optional attribute
  315. *
  316. * @param string $attrname Code of attribute to delete
  317. * @param string $elementtype Element type ('member', 'product', 'thirdparty', 'contact', ...)
  318. * @return int < 0 if KO, 0 if nothing is done, 1 if OK
  319. */
  320. function delete($attrname, $elementtype='member')
  321. {
  322. if ($elementtype == 'thirdparty') $elementtype='societe';
  323. if ($elementtype == 'contact') $elementtype='socpeople';
  324. $table=$elementtype.'_extrafields';
  325. $error=0;
  326. if (! empty($attrname) && preg_match("/^\w[a-zA-Z0-9-_]*$/",$attrname))
  327. {
  328. $result=$this->delete_label($attrname,$elementtype);
  329. if ($result < 0)
  330. {
  331. $this->error=$this->db->lasterror();
  332. $error++;
  333. }
  334. if (! $error)
  335. {
  336. $sql = "SELECT COUNT(rowid) as nb";
  337. $sql.= " FROM ".MAIN_DB_PREFIX."extrafields";
  338. $sql.= " WHERE elementtype = '".$elementtype."'";
  339. $sql.= " AND name = '".$attrname."'";
  340. //$sql.= " AND entity IN (0,".$conf->entity.")"; Do not test on entity here. We want to see if there is still on field remaning in other entities before deleting field in table
  341. $resql = $this->db->query($sql);
  342. if ($resql)
  343. {
  344. $obj = $this->db->fetch_object($resql);
  345. if ($obj->nb <= 0)
  346. {
  347. $result=$this->db->DDLDropField(MAIN_DB_PREFIX.$table,$attrname); // This also drop the unique key
  348. if ($result < 0)
  349. {
  350. $this->error=$this->db->lasterror();
  351. $error++;
  352. }
  353. }
  354. }
  355. }
  356. return $result;
  357. }
  358. else
  359. {
  360. return 0;
  361. }
  362. }
  363. /**
  364. * Delete description of an optional attribute
  365. *
  366. * @param string $attrname Code of attribute to delete
  367. * @param string $elementtype Element type ('member', 'product', 'thirdparty', ...)
  368. * @return int < 0 if KO, 0 if nothing is done, 1 if OK
  369. */
  370. private function delete_label($attrname, $elementtype='member')
  371. {
  372. global $conf;
  373. if ($elementtype == 'thirdparty') $elementtype='societe';
  374. if ($elementtype == 'contact') $elementtype='socpeople';
  375. if (isset($attrname) && $attrname != '' && preg_match("/^\w[a-zA-Z0-9-_]*$/",$attrname))
  376. {
  377. $sql = "DELETE FROM ".MAIN_DB_PREFIX."extrafields";
  378. $sql.= " WHERE name = '".$attrname."'";
  379. $sql.= " AND entity IN (0,".$conf->entity.')';
  380. $sql.= " AND elementtype = '".$elementtype."'";
  381. dol_syslog(get_class($this)."::delete_label", LOG_DEBUG);
  382. $resql=$this->db->query($sql);
  383. if ($resql)
  384. {
  385. return 1;
  386. }
  387. else
  388. {
  389. print dol_print_error($this->db);
  390. return -1;
  391. }
  392. }
  393. else
  394. {
  395. return 0;
  396. }
  397. }
  398. /**
  399. * Modify type of a personalized attribute
  400. *
  401. * @param string $attrname Name of attribute
  402. * @param string $label Label of attribute
  403. * @param string $type Type of attribute
  404. * @param int $length Length of attribute
  405. * @param string $elementtype Element type ('member', 'product', 'thirdparty', 'contact', ...)
  406. * @param int $unique Is field unique or not
  407. * @param int $required Is field required or not
  408. * @param int $pos Position of attribute
  409. * @param array $param Params for field (ex for select list : array('options' => array(value'=>'label of option')) )
  410. * @param int $alwayseditable Is attribute always editable regardless of the document status
  411. * @param string $perms Permission to check
  412. * @param int $list Into list view by default
  413. * @param int $ishidden Is hidden extrafield (warning, do not rely on this. If your module need a hidden data, it must use its own table)
  414. * @param string $default Default value (in database. use the default_value feature for default value on screen).
  415. * @param string $computed Computed value
  416. * @return int >0 if OK, <=0 if KO
  417. */
  418. function update($attrname,$label,$type,$length,$elementtype,$unique=0,$required=0,$pos=0,$param='',$alwayseditable=0, $perms='',$list='',$ishidden=0,$default='',$computed='')
  419. {
  420. if ($elementtype == 'thirdparty') $elementtype='societe';
  421. if ($elementtype == 'contact') $elementtype='socpeople';
  422. $table=$elementtype.'_extrafields';
  423. if (isset($attrname) && $attrname != '' && preg_match("/^\w[a-zA-Z0-9-_]*$/",$attrname))
  424. {
  425. if ($type=='boolean') {
  426. $typedb='int';
  427. $lengthdb='1';
  428. } elseif($type=='price') {
  429. $typedb='double';
  430. $lengthdb='24,8';
  431. } elseif($type=='phone') {
  432. $typedb='varchar';
  433. $lengthdb='20';
  434. } elseif($type=='mail') {
  435. $typedb='varchar';
  436. $lengthdb='128';
  437. } elseif($type=='url') {
  438. $typedb='varchar';
  439. $lengthdb='255';
  440. } elseif (($type=='select') || ($type=='sellist') || ($type=='radio') || ($type=='checkbox') || ($type=='chkbxlst')) {
  441. $typedb='text';
  442. $lengthdb='';
  443. } elseif ($type=='link') {
  444. $typedb='int';
  445. $lengthdb='11';
  446. } elseif($type=='password') {
  447. $typedb='varchar';
  448. $lengthdb='50';
  449. } else {
  450. $typedb=$type;
  451. $lengthdb=$length;
  452. }
  453. $field_desc = array('type'=>$typedb, 'value'=>$lengthdb, 'null'=>($required?'NOT NULL':'NULL'));
  454. if ($type != 'separate') // No table update when separate type
  455. {
  456. $result=$this->db->DDLUpdateField(MAIN_DB_PREFIX.$table, $attrname, $field_desc);
  457. }
  458. if ($result > 0 || $type == 'separate')
  459. {
  460. if ($label)
  461. {
  462. $result=$this->update_label($attrname,$label,$type,$length,$elementtype,$unique,$required,$pos,$param,$alwayseditable,$perms,$list,$ishidden,$default,$computed);
  463. }
  464. if ($result > 0)
  465. {
  466. $sql='';
  467. if ($unique)
  468. {
  469. $sql="ALTER TABLE ".MAIN_DB_PREFIX.$table." ADD UNIQUE INDEX uk_".$table."_".$attrname." (".$attrname.")";
  470. }
  471. else
  472. {
  473. $sql="ALTER TABLE ".MAIN_DB_PREFIX.$table." DROP INDEX uk_".$table."_".$attrname;
  474. }
  475. dol_syslog(get_class($this).'::update', LOG_DEBUG);
  476. $resql=$this->db->query($sql,1,'dml');
  477. return 1;
  478. }
  479. else
  480. {
  481. $this->error=$this->db->lasterror();
  482. return -1;
  483. }
  484. }
  485. else
  486. {
  487. $this->error=$this->db->lasterror();
  488. return -1;
  489. }
  490. }
  491. else
  492. {
  493. return 0;
  494. }
  495. }
  496. /**
  497. * Modify description of personalized attribute
  498. *
  499. * @param string $attrname Name of attribute
  500. * @param string $label Label of attribute
  501. * @param string $type Type of attribute
  502. * @param int $size Length of attribute
  503. * @param string $elementtype Element type ('member', 'product', 'thirdparty', ...)
  504. * @param int $unique Is field unique or not
  505. * @param int $required Is field required or not
  506. * @param int $pos Position of attribute
  507. * @param array $param Params for field (ex for select list : array('options' => array(value'=>'label of option')) )
  508. * @param int $alwayseditable Is attribute always editable regardless of the document status
  509. * @param string $perms Permission to check
  510. * @param int $list Into list view by default
  511. * @param int $ishidden Is hidden extrafield (warning, do not rely on this. If your module need a hidden data, it must use its own table)
  512. * @param string $default Default value (in database. use the default_value feature for default value on screen).
  513. * @param string $computed Computed value
  514. * @return int <=0 if KO, >0 if OK
  515. */
  516. private function update_label($attrname,$label,$type,$size,$elementtype,$unique=0,$required=0,$pos=0,$param='',$alwayseditable=0,$perms='',$list=0,$ishidden=0,$default='',$computed='')
  517. {
  518. global $conf;
  519. dol_syslog(get_class($this)."::update_label ".$attrname.", ".$label.", ".$type.", ".$size.", ".$elementtype.", ".$unique.", ".$required.", ".$pos.", ".$alwayseditable.", ".$perms.", ".$list.", ".$ishidden.", ".$default.", ".$computed);
  520. // Clean parameters
  521. if ($elementtype == 'thirdparty') $elementtype='societe';
  522. if ($elementtype == 'contact') $elementtype='socpeople';
  523. if (empty($list)) $list=0;
  524. if (isset($attrname) && $attrname != '' && preg_match("/^\w[a-zA-Z0-9-_]*$/",$attrname))
  525. {
  526. $this->db->begin();
  527. if(is_array($param) && count($param) > 0)
  528. {
  529. $param = $this->db->escape(serialize($param));
  530. }
  531. $sql_del = "DELETE FROM ".MAIN_DB_PREFIX."extrafields";
  532. $sql_del.= " WHERE name = '".$attrname."'";
  533. $sql_del.= " AND entity = ".$conf->entity;
  534. $sql_del.= " AND elementtype = '".$elementtype."'";
  535. $resql1=$this->db->query($sql_del);
  536. $sql = "INSERT INTO ".MAIN_DB_PREFIX."extrafields(";
  537. $sql.= " name,"; // This is code
  538. $sql.= " entity,";
  539. $sql.= " label,";
  540. $sql.= " type,";
  541. $sql.= " size,";
  542. $sql.= " elementtype,";
  543. $sql.= " fieldunique,";
  544. $sql.= " fieldrequired,";
  545. $sql.= " perms,";
  546. $sql.= " pos,";
  547. $sql.= " alwayseditable,";
  548. $sql.= " param,";
  549. $sql.= " list,";
  550. $sql.= " ishidden,";
  551. $sql.= " fielddefault,";
  552. $sql.= " fieldcomputed";
  553. $sql.= ") VALUES (";
  554. $sql.= "'".$attrname."',";
  555. $sql.= " ".$conf->entity.",";
  556. $sql.= " '".$this->db->escape($label)."',";
  557. $sql.= " '".$type."',";
  558. $sql.= " '".$size."',";
  559. $sql.= " '".$elementtype."',";
  560. $sql.= " '".$unique."',";
  561. $sql.= " '".$required."',";
  562. $sql.= " ".($perms?"'".$this->db->escape($perms)."'":"null").",";
  563. $sql.= " '".$pos."',";
  564. $sql.= " '".$alwayseditable."',";
  565. $sql.= " '".$param."',";
  566. $sql.= " ".$list.", ";
  567. $sql.= " ".$ishidden.", ";
  568. $sql.= " ".($default?"'".$this->db->escape($default)."'":"null").",";
  569. $sql.= " ".($computed?"'".$this->db->escape($computed)."'":"null");
  570. $sql.= ")";
  571. $resql2=$this->db->query($sql);
  572. if ($resql1 && $resql2)
  573. {
  574. $this->db->commit();
  575. return 1;
  576. }
  577. else
  578. {
  579. $this->db->rollback();
  580. print dol_print_error($this->db);
  581. return -1;
  582. }
  583. }
  584. else
  585. {
  586. return 0;
  587. }
  588. }
  589. /**
  590. * Load array this->attribute_xxx like attribute_label, attribute_type, ...
  591. *
  592. * @param string $elementtype Type of element ('adherent', 'commande', 'thirdparty', 'facture', 'propal', 'product', ...)
  593. * @param boolean $forceload Force load of extra fields whatever is option MAIN_EXTRAFIELDS_DISABLED
  594. * @return array Array of attributes for all extra fields
  595. */
  596. function fetch_name_optionals_label($elementtype,$forceload=false)
  597. {
  598. global $conf;
  599. if ( empty($elementtype) ) return array();
  600. if ($elementtype == 'thirdparty') $elementtype='societe';
  601. if ($elementtype == 'contact') $elementtype='socpeople';
  602. $array_name_label=array();
  603. // For avoid conflicts with external modules
  604. if (!$forceload && !empty($conf->global->MAIN_EXTRAFIELDS_DISABLED)) return $array_name_label;
  605. $sql = "SELECT rowid,name,label,type,size,elementtype,fieldunique,fieldrequired,param,pos,alwayseditable,perms,list,ishidden,fielddefault,fieldcomputed";
  606. $sql.= " FROM ".MAIN_DB_PREFIX."extrafields";
  607. $sql.= " WHERE entity IN (0,".$conf->entity.")";
  608. if ($elementtype) $sql.= " AND elementtype = '".$elementtype."'";
  609. $sql.= " ORDER BY pos";
  610. $resql=$this->db->query($sql);
  611. if ($resql)
  612. {
  613. if ($this->db->num_rows($resql))
  614. {
  615. while ($tab = $this->db->fetch_object($resql))
  616. {
  617. // we can add this attribute to adherent object
  618. if ($tab->type != 'separate')
  619. {
  620. $array_name_label[$tab->name]=$tab->label;
  621. }
  622. $this->attribute_type[$tab->name]=$tab->type;
  623. $this->attribute_label[$tab->name]=$tab->label;
  624. $this->attribute_size[$tab->name]=$tab->size;
  625. $this->attribute_elementtype[$tab->name]=$tab->elementtype;
  626. $this->attribute_default[$tab->name]=$tab->fielddefault;
  627. $this->attribute_computed[$tab->name]=$tab->fieldcomputed;
  628. $this->attribute_unique[$tab->name]=$tab->fieldunique;
  629. $this->attribute_required[$tab->name]=$tab->fieldrequired;
  630. $this->attribute_param[$tab->name]=($tab->param ? unserialize($tab->param) : '');
  631. $this->attribute_pos[$tab->name]=$tab->pos;
  632. $this->attribute_alwayseditable[$tab->name]=$tab->alwayseditable;
  633. $this->attribute_perms[$tab->name]=$tab->perms;
  634. $this->attribute_list[$tab->name]=$tab->list;
  635. $this->attribute_hidden[$tab->name]=$tab->ishidden;
  636. }
  637. }
  638. }
  639. else
  640. {
  641. $this->error=$this->db->lasterror();
  642. dol_syslog(get_class($this)."::fetch_name_optionals_label ".$this->error, LOG_ERR);
  643. }
  644. return $array_name_label;
  645. }
  646. /**
  647. * Return HTML string to put an input field into a page
  648. *
  649. * @param string $key Key of attribute
  650. * @param string $value Preselected value to show (for date type it must be in timestamp format)
  651. * @param string $moreparam To add more parametes on html input tag
  652. * @param string $keyprefix Prefix string to add into name and id of field (can be used to avoid duplicate names)
  653. * @param string $keysuffix Suffix string to add into name and id of field (can be used to avoid duplicate names)
  654. * @param mixed $showsize Value for css to define size. May also be a numeric.
  655. * @param int $objectid Current object id
  656. * @return string
  657. */
  658. function showInputField($key, $value, $moreparam='', $keyprefix='', $keysuffix='', $showsize=0, $objectid=0)
  659. {
  660. global $conf,$langs;
  661. $label=$this->attribute_label[$key];
  662. $type =$this->attribute_type[$key];
  663. $size =$this->attribute_size[$key];
  664. $elementtype=$this->attribute_elementtype[$key];
  665. $default=$this->attribute_default[$key];
  666. $computed=$this->attribute_computed[$key];
  667. $unique=$this->attribute_unique[$key];
  668. $required=$this->attribute_required[$key];
  669. $param=$this->attribute_param[$key];
  670. $perms=$this->attribute_perms[$key];
  671. $list=$this->attribute_list[$key];
  672. $hidden=$this->attribute_hidden[$key];
  673. if ($computed) return '<span class="opacitymedium">'.$langs->trans("AutomaticallyCalculated").'</span>';
  674. if (empty($showsize))
  675. {
  676. if ($type == 'date')
  677. {
  678. //$showsize=10;
  679. $showsize = 'minwidth100imp';
  680. }
  681. elseif ($type == 'datetime')
  682. {
  683. //$showsize=19;
  684. $showsize = 'minwidth200imp';
  685. }
  686. elseif (in_array($type,array('int','double')))
  687. {
  688. //$showsize=10;
  689. $showsize = 'minwidth100imp';
  690. }
  691. elseif ($type == 'url')
  692. {
  693. $showsize='minwidth400imp';
  694. }
  695. elseif ($type == 'boolean')
  696. {
  697. $showsize='';
  698. }
  699. else
  700. {
  701. if (round($size) < 12)
  702. {
  703. $showsize = 'minwidth100imp';
  704. }
  705. else if (round($size) <= 48)
  706. {
  707. $showsize = 'minwidth200imp';
  708. }
  709. else
  710. {
  711. //$showsize=48;
  712. $showsize = 'minwidth400imp';
  713. }
  714. }
  715. }
  716. if (in_array($type,array('date','datetime')))
  717. {
  718. $tmp=explode(',',$size);
  719. $newsize=$tmp[0];
  720. $showtime = in_array($type,array('datetime')) ? 1 : 0;
  721. // Do not show current date when field not required (see select_date() method)
  722. if (!$required && $value == '') $value = '-1';
  723. require_once DOL_DOCUMENT_ROOT.'/core/class/html.form.class.php';
  724. global $form;
  725. if (! is_object($form)) $form=new Form($this->db);
  726. // TODO Must also support $moreparam
  727. $out = $form->select_date($value, $keysuffix.'options_'.$key.$keyprefix, $showtime, $showtime, $required, '', 1, 1, 1, 0, 1);
  728. }
  729. elseif (in_array($type,array('int')))
  730. {
  731. $tmp=explode(',',$size);
  732. $newsize=$tmp[0];
  733. $out='<input type="text" class="flat '.$showsize.' maxwidthonsmartphone" name="'.$keysuffix.'options_'.$key.$keyprefix.'" " maxlength="'.$newsize.'" value="'.$value.'"'.($moreparam?$moreparam:'').'>';
  734. }
  735. elseif ($type == 'varchar')
  736. {
  737. $out='<input type="text" class="flat '.$showsize.' maxwidthonsmartphone" name="'.$keysuffix.'options_'.$key.$keyprefix.'" maxlength="'.$size.'" value="'.dol_escape_htmltag($value).'"'.($moreparam?$moreparam:'').'>';
  738. }
  739. elseif (in_array($type, array('mail', 'phone', 'url')))
  740. {
  741. $out='<input type="text" class="flat '.$showsize.' maxwidthonsmartphone" name="'.$keysuffix.'options_'.$key.$keyprefix.'" value="'.$value.'" '.($moreparam?$moreparam:'').'>';
  742. }
  743. elseif ($type == 'text')
  744. {
  745. require_once DOL_DOCUMENT_ROOT.'/core/class/doleditor.class.php';
  746. $doleditor=new DolEditor($keysuffix.'options_'.$key.$keyprefix,$value,'',200,'dolibarr_notes','In',false,false,! empty($conf->fckeditor->enabled) && $conf->global->FCKEDITOR_ENABLE_SOCIETE,ROWS_5,'90%');
  747. $out=$doleditor->Create(1);
  748. }
  749. elseif ($type == 'boolean')
  750. {
  751. $checked='';
  752. if (!empty($value)) {
  753. $checked=' checked value="1" ';
  754. } else {
  755. $checked=' value="1" ';
  756. }
  757. $out='<input type="checkbox" class="flat '.$showsize.' maxwidthonsmartphone" name="'.$keysuffix.'options_'.$key.$keyprefix.'" '.$checked.' '.($moreparam?$moreparam:'').'>';
  758. }
  759. elseif ($type == 'price')
  760. {
  761. $out='<input type="text" class="flat '.$showsize.' maxwidthonsmartphone" name="'.$keysuffix.'options_'.$key.$keyprefix.'" value="'.price2num($value).'" '.($moreparam?$moreparam:'').'> '.$langs->getCurrencySymbol($conf->currency);
  762. }
  763. elseif ($type == 'double')
  764. {
  765. if (!empty($value)) {
  766. $value=price($value);
  767. }
  768. $out='<input type="text" class="flat '.$showsize.' maxwidthonsmartphone" name="'.$keysuffix.'options_'.$key.$keyprefix.'" value="'.$value.'" '.($moreparam?$moreparam:'').'> ';
  769. }
  770. elseif ($type == 'select')
  771. {
  772. $out = '';
  773. if (! empty($conf->use_javascript_ajax) && ! empty($conf->global->MAIN_EXTRAFIELDS_USE_SELECT2))
  774. {
  775. include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
  776. $out.= ajax_combobox($keysuffix.'options_'.$key.$keyprefix, array(), 0);
  777. }
  778. $out.='<select class="flat '.$showsize.' maxwidthonsmartphone" name="'.$keysuffix.'options_'.$key.$keyprefix.'" id="options_'.$key.$keyprefix.'" '.($moreparam?$moreparam:'').'>';
  779. $out.='<option value="0">&nbsp;</option>';
  780. foreach ($param['options'] as $key => $val)
  781. {
  782. if ($key == '') continue;
  783. list($val, $parent) = explode('|', $val);
  784. $out.='<option value="'.$key.'"';
  785. $out.= ($value==$key?' selected':'');
  786. $out.= (!empty($parent)?' parent="'.$parent.'"':'');
  787. $out.='>'.$val.'</option>';
  788. }
  789. $out.='</select>';
  790. }
  791. elseif ($type == 'sellist')
  792. {
  793. $out = '';
  794. if (! empty($conf->use_javascript_ajax) && ! empty($conf->global->MAIN_EXTRAFIELDS_USE_SELECT2))
  795. {
  796. include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
  797. $out.= ajax_combobox($keysuffix.'options_'.$key.$keyprefix, array(), 0);
  798. }
  799. $out.='<select class="flat '.$showsize.' maxwidthonsmartphone" name="'.$keysuffix.'options_'.$key.$keyprefix.'" id="options_'.$key.$keyprefix.'" '.($moreparam?$moreparam:'').'>';
  800. if (is_array($param['options']))
  801. {
  802. $param_list=array_keys($param['options']);
  803. $InfoFieldList = explode(":", $param_list[0]);
  804. // 0 : tableName
  805. // 1 : label field name
  806. // 2 : key fields name (if differ of rowid)
  807. // 3 : key field parent (for dependent lists)
  808. // 4 : where clause filter on column or table extrafield, syntax field='value' or extra.field=value
  809. $keyList=(empty($InfoFieldList[2])?'rowid':$InfoFieldList[2].' as rowid');
  810. if (count($InfoFieldList) > 4 && ! empty($InfoFieldList[4]))
  811. {
  812. if (strpos($InfoFieldList[4], 'extra.') !== false)
  813. {
  814. $keyList='main.'.$InfoFieldList[2].' as rowid';
  815. } else {
  816. $keyList=$InfoFieldList[2].' as rowid';
  817. }
  818. }
  819. if (count($InfoFieldList) > 3 && ! empty($InfoFieldList[3]))
  820. {
  821. list($parentName, $parentField) = explode('|', $InfoFieldList[3]);
  822. $keyList.= ', '.$parentField;
  823. }
  824. $fields_label = explode('|',$InfoFieldList[1]);
  825. if (is_array($fields_label))
  826. {
  827. $keyList .=', ';
  828. $keyList .= implode(', ', $fields_label);
  829. }
  830. $sqlwhere='';
  831. $sql = 'SELECT '.$keyList;
  832. $sql.= ' FROM '.MAIN_DB_PREFIX .$InfoFieldList[0];
  833. if (!empty($InfoFieldList[4]))
  834. {
  835. // can use SELECT request
  836. if (strpos($InfoFieldList[4], '$SEL$')!==false) {
  837. $InfoFieldList[4]=str_replace('$SEL$','SELECT',$InfoFieldList[4]);
  838. }
  839. // current object id can be use into filter
  840. if (strpos($InfoFieldList[4], '$ID$')!==false && !empty($objectid)) {
  841. $InfoFieldList[4]=str_replace('$ID$',$objectid,$InfoFieldList[4]);
  842. } else {
  843. $InfoFieldList[4]=str_replace('$ID$','0',$InfoFieldList[4]);
  844. }
  845. //We have to join on extrafield table
  846. if (strpos($InfoFieldList[4], 'extra')!==false)
  847. {
  848. $sql.= ' as main, '.MAIN_DB_PREFIX .$InfoFieldList[0].'_extrafields as extra';
  849. $sqlwhere.= ' WHERE extra.fk_object=main.'.$InfoFieldList[2]. ' AND '.$InfoFieldList[4];
  850. }
  851. else
  852. {
  853. $sqlwhere.= ' WHERE '.$InfoFieldList[4];
  854. }
  855. }
  856. else
  857. {
  858. $sqlwhere.= ' WHERE 1=1';
  859. }
  860. // Some tables may have field, some other not. For the moment we disable it.
  861. if (in_array($InfoFieldList[0],array('tablewithentity')))
  862. {
  863. $sqlwhere.= ' AND entity = '.$conf->entity;
  864. }
  865. $sql.=$sqlwhere;
  866. //print $sql;
  867. $sql .= ' ORDER BY ' . implode(', ', $fields_label);
  868. dol_syslog(get_class($this).'::showInputField type=sellist', LOG_DEBUG);
  869. $resql = $this->db->query($sql);
  870. if ($resql)
  871. {
  872. $out.='<option value="0">&nbsp;</option>';
  873. $num = $this->db->num_rows($resql);
  874. $i = 0;
  875. while ($i < $num)
  876. {
  877. $labeltoshow='';
  878. $obj = $this->db->fetch_object($resql);
  879. // Several field into label (eq table:code|libelle:rowid)
  880. $fields_label = explode('|',$InfoFieldList[1]);
  881. if(is_array($fields_label))
  882. {
  883. $notrans = true;
  884. foreach ($fields_label as $field_toshow)
  885. {
  886. $labeltoshow.= $obj->$field_toshow.' ';
  887. }
  888. }
  889. else
  890. {
  891. $labeltoshow=$obj->{$InfoFieldList[1]};
  892. }
  893. $labeltoshow=dol_trunc($labeltoshow,45);
  894. if ($value==$obj->rowid)
  895. {
  896. foreach ($fields_label as $field_toshow)
  897. {
  898. $translabel=$langs->trans($obj->$field_toshow);
  899. if ($translabel!=$obj->$field_toshow) {
  900. $labeltoshow=dol_trunc($translabel,18).' ';
  901. }else {
  902. $labeltoshow=dol_trunc($obj->$field_toshow,18).' ';
  903. }
  904. }
  905. $out.='<option value="'.$obj->rowid.'" selected>'.$labeltoshow.'</option>';
  906. }
  907. else
  908. {
  909. if(!$notrans)
  910. {
  911. $translabel=$langs->trans($obj->{$InfoFieldList[1]});
  912. if ($translabel!=$obj->{$InfoFieldList[1]}) {
  913. $labeltoshow=dol_trunc($translabel,18);
  914. }
  915. else {
  916. $labeltoshow=dol_trunc($obj->{$InfoFieldList[1]},18);
  917. }
  918. }
  919. if (empty($labeltoshow)) $labeltoshow='(not defined)';
  920. if ($value==$obj->rowid)
  921. {
  922. $out.='<option value="'.$obj->rowid.'" selected>'.$labeltoshow.'</option>';
  923. }
  924. if (!empty($InfoFieldList[3]))
  925. {
  926. $parent = $parentName.':'.$obj->{$parentField};
  927. }
  928. $out.='<option value="'.$obj->rowid.'"';
  929. $out.= ($value==$obj->rowid?' selected':'');
  930. $out.= (!empty($parent)?' parent="'.$parent.'"':'');
  931. $out.='>'.$labeltoshow.'</option>';
  932. }
  933. $i++;
  934. }
  935. $this->db->free($resql);
  936. }
  937. else {
  938. print 'Error in request '.$sql.' '.$this->db->lasterror().'. Check setup of extra parameters.<br>';
  939. }
  940. }
  941. $out.='</select>';
  942. }
  943. elseif ($type == 'checkbox')
  944. {
  945. require_once DOL_DOCUMENT_ROOT.'/core/class/html.form.class.php';
  946. $form = new Form($db);
  947. $value_arr=explode(',',$value);
  948. $out=$form->multiselectarray($keysuffix.'options_'.$key.$keyprefix, $param['options'], $value_arr, '', 0, '', 0, '100%');
  949. }
  950. elseif ($type == 'radio')
  951. {
  952. $out='';
  953. foreach ($param['options'] as $keyopt=>$val )
  954. {
  955. $out.='<input class="flat '.$showsize.'" type="radio" name="'.$keysuffix.'options_'.$key.$keyprefix.'" '.($moreparam?$moreparam:'');
  956. $out.=' value="'.$keyopt.'"';
  957. $out.=' id="'.$keysuffix.'options_'.$key.$keyprefix.'_'.$keyopt.'"';
  958. $out.= ($value==$keyopt?'checked':'');
  959. $out.='/><label for="'.$keysuffix.'options_'.$key.$keyprefix.'_'.$keyopt.'">'.$val.'</label><br>';
  960. }
  961. }
  962. elseif ($type == 'chkbxlst')
  963. {
  964. if (is_array($value)) {
  965. $value_arr = $value;
  966. }
  967. else {
  968. $value_arr = explode(',', $value);
  969. }
  970. if (is_array($param['options'])) {
  971. $param_list = array_keys($param['options']);
  972. $InfoFieldList = explode(":", $param_list[0]);
  973. // 0 : tableName
  974. // 1 : label field name
  975. // 2 : key fields name (if differ of rowid)
  976. // 3 : key field parent (for dependent lists)
  977. // 4 : where clause filter on column or table extrafield, syntax field='value' or extra.field=value
  978. $keyList = (empty($InfoFieldList[2]) ? 'rowid' : $InfoFieldList[2] . ' as rowid');
  979. if (count($InfoFieldList) > 3 && ! empty($InfoFieldList[3])) {
  980. list ( $parentName, $parentField ) = explode('|', $InfoFieldList[3]);
  981. $keyList .= ', ' . $parentField;
  982. }
  983. if (count($InfoFieldList) > 4 && ! empty($InfoFieldList[4])) {
  984. if (strpos($InfoFieldList[4], 'extra.') !== false) {
  985. $keyList = 'main.' . $InfoFieldList[2] . ' as rowid';
  986. } else {
  987. $keyList = $InfoFieldList[2] . ' as rowid';
  988. }
  989. }
  990. $fields_label = explode('|', $InfoFieldList[1]);
  991. if (is_array($fields_label)) {
  992. $keyList .= ', ';
  993. $keyList .= implode(', ', $fields_label);
  994. }
  995. $sqlwhere = '';
  996. $sql = 'SELECT ' . $keyList;
  997. $sql .= ' FROM ' . MAIN_DB_PREFIX . $InfoFieldList[0];
  998. if (! empty($InfoFieldList[4])) {
  999. // can use SELECT request
  1000. if (strpos($InfoFieldList[4], '$SEL$')!==false) {
  1001. $InfoFieldList[4]=str_replace('$SEL$','SELECT',$InfoFieldList[4]);
  1002. }
  1003. // current object id can be use into filter
  1004. if (strpos($InfoFieldList[4], '$ID$')!==false && !empty($objectid)) {
  1005. $InfoFieldList[4]=str_replace('$ID$',$objectid,$InfoFieldList[4]);
  1006. } else {
  1007. $InfoFieldList[4]=str_replace('$ID$','0',$InfoFieldList[4]);
  1008. }
  1009. // We have to join on extrafield table
  1010. if (strpos($InfoFieldList[4], 'extra') !== false) {
  1011. $sql .= ' as main, ' . MAIN_DB_PREFIX . $InfoFieldList[0] . '_extrafields as extra';
  1012. $sqlwhere .= ' WHERE extra.fk_object=main.' . $InfoFieldList[2] . ' AND ' . $InfoFieldList[4];
  1013. } else {
  1014. $sqlwhere .= ' WHERE ' . $InfoFieldList[4];
  1015. }
  1016. } else {
  1017. $sqlwhere .= ' WHERE 1=1';
  1018. }
  1019. // Some tables may have field, some other not. For the moment we disable it.
  1020. if (in_array($InfoFieldList[0], array ('tablewithentity')))
  1021. {
  1022. $sqlwhere .= ' AND entity = ' . $conf->entity;
  1023. }
  1024. // $sql.=preg_replace('/^ AND /','',$sqlwhere);
  1025. // print $sql;
  1026. $sql .= $sqlwhere;
  1027. dol_syslog(get_class($this) . '::showInputField type=chkbxlst',LOG_DEBUG);
  1028. $resql = $this->db->query($sql);
  1029. if ($resql) {
  1030. $num = $this->db->num_rows($resql);
  1031. $i = 0;
  1032. $data=array();
  1033. while ( $i < $num ) {
  1034. $labeltoshow = '';
  1035. $obj = $this->db->fetch_object($resql);
  1036. // Several field into label (eq table:code|libelle:rowid)
  1037. $fields_label = explode('|', $InfoFieldList[1]);
  1038. if (is_array($fields_label)) {
  1039. $notrans = true;
  1040. foreach ( $fields_label as $field_toshow ) {
  1041. $labeltoshow .= $obj->$field_toshow . ' ';
  1042. }
  1043. } else {
  1044. $labeltoshow = $obj->{$InfoFieldList[1]};
  1045. }
  1046. $labeltoshow = dol_trunc($labeltoshow, 45);
  1047. if (is_array($value_arr) && in_array($obj->rowid, $value_arr)) {
  1048. foreach ( $fields_label as $field_toshow ) {
  1049. $translabel = $langs->trans($obj->$field_toshow);
  1050. if ($translabel != $obj->$field_toshow) {
  1051. $labeltoshow = dol_trunc($translabel, 18) . ' ';
  1052. } else {
  1053. $labeltoshow = dol_trunc($obj->$field_toshow, 18) . ' ';
  1054. }
  1055. }
  1056. $data[$obj->rowid]=$labeltoshow;
  1057. } else {
  1058. if (! $notrans) {
  1059. $translabel = $langs->trans($obj->{$InfoFieldList[1]});
  1060. if ($translabel != $obj->{$InfoFieldList[1]}) {
  1061. $labeltoshow = dol_trunc($translabel, 18);
  1062. } else {
  1063. $labeltoshow = dol_trunc($obj->{$InfoFieldList[1]}, 18);
  1064. }
  1065. }
  1066. if (empty($labeltoshow))
  1067. $labeltoshow = '(not defined)';
  1068. if (is_array($value_arr) && in_array($obj->rowid, $value_arr)) {
  1069. $data[$obj->rowid]=$labeltoshow;
  1070. }
  1071. if (! empty($InfoFieldList[3])) {
  1072. $parent = $parentName . ':' . $obj->{$parentField};
  1073. }
  1074. $data[$obj->rowid]=$labeltoshow;
  1075. }
  1076. $i ++;
  1077. }
  1078. $this->db->free($resql);
  1079. require_once DOL_DOCUMENT_ROOT.'/core/class/html.form.class.php';
  1080. $form = new Form($db);
  1081. $out=$form->multiselectarray($keysuffix.'options_'.$key.$keyprefix, $data, $value_arr, '', 0, '', 0, '100%');
  1082. } else {
  1083. print 'Error in request ' . $sql . ' ' . $this->db->lasterror() . '. Check setup of extra parameters.<br>';
  1084. }
  1085. }
  1086. $out .= '</select>';
  1087. }
  1088. elseif ($type == 'link')
  1089. {
  1090. $out='';
  1091. $param_list=array_keys($param['options']);
  1092. // 0 : ObjectName
  1093. // 1 : classPath
  1094. $InfoFieldList = explode(":", $param_list[0]);
  1095. dol_include_once($InfoFieldList[1]);
  1096. if ($InfoFieldList[0] && class_exists($InfoFieldList[0]))
  1097. {
  1098. $valuetoshow=$value;
  1099. if (!empty($value))
  1100. {
  1101. $object = new $InfoFieldList[0]($this->db);
  1102. $resfetch=$object->fetch($value);
  1103. if ($resfetch > 0)
  1104. {
  1105. $valuetoshow=$object->ref;
  1106. if ($object->element == 'societe') $valuetoshow=$object->name; // Special case for thirdparty because ->ref is not name but id (because name is not unique)
  1107. }
  1108. }
  1109. $out.='<input type="text" class="flat '.$showsize.'" name="'.$keysuffix.'options_'.$key.$keyprefix.'" value="'.$valuetoshow.'" >';
  1110. }
  1111. else
  1112. {
  1113. dol_syslog('Error bad setup of extrafield', LOG_WARNING);
  1114. $out.='Error bad setup of extrafield';
  1115. }
  1116. }
  1117. elseif ($type == 'password')
  1118. {
  1119. $out='<input type="password" class="flat '.$showsize.'" name="'.$keysuffix.'options_'.$key.$keyprefix.'" value="'.$value.'" '.($moreparam?$moreparam:'').'>';
  1120. }
  1121. if (!empty($hidden)) {
  1122. $out='<input type="hidden" value="'.$value.'" name="'.$keysuffix.'options_'.$key.$keyprefix.'" id="'.$keysuffix.'options_'.$key.$keyprefix.'"/>';
  1123. }
  1124. /* Add comments
  1125. if ($type == 'date') $out.=' (YYYY-MM-DD)';
  1126. elseif ($type == 'datetime') $out.=' (YYYY-MM-DD HH:MM:SS)';
  1127. */
  1128. return $out;
  1129. }
  1130. /**
  1131. * Return HTML string to put an output field into a page
  1132. *
  1133. * @param string $key Key of attribute
  1134. * @param string $value Value to show
  1135. * @param string $moreparam To add more parametes on html input tag (only checkbox use html input for output rendering)
  1136. * @return string Formated value
  1137. */
  1138. function showOutputField($key,$value,$moreparam='')
  1139. {
  1140. global $conf,$langs;
  1141. $elementtype=$this->attribute_elementtype[$key];
  1142. $label=$this->attribute_label[$key];
  1143. $type=$this->attribute_type[$key];
  1144. $size=$this->attribute_size[$key];
  1145. $default=$this->attribute_default[$key];
  1146. $computed=$this->attribute_computed[$key];
  1147. $unique=$this->attribute_unique[$key];
  1148. $required=$this->attribute_required[$key];
  1149. $params=$this->attribute_param[$key];
  1150. $perms=$this->attribute_perms[$key];
  1151. $list=$this->attribute_list[$key];
  1152. $hidden=$this->attribute_hidden[$key]; // warning, do not rely on this. If your module need a hidden data, it must use its own table.
  1153. // If field is a computed field, value must become result of compute
  1154. if ($computed)
  1155. {
  1156. // Make the eval of compute string
  1157. //var_dump($computed);
  1158. $value = dol_eval($computed, 1, 0);
  1159. }
  1160. $showsize=0;
  1161. if ($type == 'date')
  1162. {
  1163. $showsize=10;
  1164. $value=dol_print_date($value,'day');
  1165. }
  1166. elseif ($type == 'datetime')
  1167. {
  1168. $showsize=19;
  1169. $value=dol_print_date($value,'dayhour');
  1170. }
  1171. elseif ($type == 'int')
  1172. {
  1173. $showsize=10;
  1174. }
  1175. elseif ($type == 'double')
  1176. {
  1177. if (!empty($value)) {
  1178. $value=price($value);
  1179. }
  1180. }
  1181. elseif ($type == 'boolean')
  1182. {
  1183. $checked='';
  1184. if (!empty($value)) {
  1185. $checked=' checked ';
  1186. }
  1187. $value='<input type="checkbox" '.$checked.' '.($moreparam?$moreparam:'').' readonly disabled>';
  1188. }
  1189. elseif ($type == 'mail')
  1190. {
  1191. $value=dol_print_email($value,0,0,0,64,1,1);
  1192. }
  1193. elseif ($type == 'url')
  1194. {
  1195. $value=dol_print_url($value,'_blank',32,1);
  1196. }
  1197. elseif ($type == 'phone')
  1198. {
  1199. $value=dol_print_phone($value, '', 0, 0, '', '&nbsp;', 1);
  1200. }
  1201. elseif ($type == 'price')
  1202. {
  1203. $value=price($value,0,$langs,0,0,-1,$conf->currency);
  1204. }
  1205. elseif ($type == 'select')
  1206. {
  1207. $value=$params['options'][$value];
  1208. }
  1209. elseif ($type == 'sellist')
  1210. {
  1211. $param_list=array_keys($params['options']);
  1212. $InfoFieldList = explode(":", $param_list[0]);
  1213. $selectkey="rowid";
  1214. $keyList='rowid';
  1215. if (count($InfoFieldList)>=3)
  1216. {
  1217. $selectkey = $InfoFieldList[2];
  1218. $keyList=$InfoFieldList[2].' as rowid';
  1219. }
  1220. $fields_label = explode('|',$InfoFieldList[1]);
  1221. if(is_array($fields_label)) {
  1222. $keyList .=', ';
  1223. $keyList .= implode(', ', $fields_label);
  1224. }
  1225. $sql = 'SELECT '.$keyList;
  1226. $sql.= ' FROM '.MAIN_DB_PREFIX .$InfoFieldList[0];
  1227. if (strpos($InfoFieldList[4], 'extra')!==false)
  1228. {
  1229. $sql.= ' as main';
  1230. }
  1231. if ($selectkey=='rowid' && empty($value)) {
  1232. $sql.= " WHERE ".$selectkey."=0";
  1233. } elseif ($selectkey=='rowid') {
  1234. $sql.= " WHERE ".$selectkey."=".$this->db->escape($value);
  1235. }else {
  1236. $sql.= " WHERE ".$selectkey."='".$this->db->escape($value)."'";
  1237. }
  1238. //$sql.= ' AND entity = '.$conf->entity;
  1239. dol_syslog(get_class($this).':showOutputField:$type=sellist', LOG_DEBUG);
  1240. $resql = $this->db->query($sql);
  1241. if ($resql)
  1242. {
  1243. $value=''; // value was used, so now we reste it to use it to build final output
  1244. $obj = $this->db->fetch_object($resql);
  1245. // Several field into label (eq table:code|libelle:rowid)
  1246. $fields_label = explode('|',$InfoFieldList[1]);
  1247. if(is_array($fields_label) && count($fields_label)>1)
  1248. {
  1249. foreach ($fields_label as $field_toshow)
  1250. {
  1251. $translabel='';
  1252. if (!empty($obj->$field_toshow)) {
  1253. $translabel=$langs->trans($obj->$field_toshow);
  1254. }
  1255. if ($translabel!=$field_toshow) {
  1256. $value.=dol_trunc($translabel,18).' ';
  1257. }else {
  1258. $value.=$obj->$field_toshow.' ';
  1259. }
  1260. }
  1261. }
  1262. else
  1263. {
  1264. $translabel='';
  1265. if (!empty($obj->{$InfoFieldList[1]})) {
  1266. $translabel=$langs->trans($obj->{$InfoFieldList[1]});
  1267. }
  1268. if ($translabel!=$obj->{$InfoFieldList[1]}) {
  1269. $value=dol_trunc($translabel,18);
  1270. }else {
  1271. $value=$obj->{$InfoFieldList[1]};
  1272. }
  1273. }
  1274. }
  1275. else dol_syslog(get_class($this).'::showOutputField error '.$this->db->lasterror(), LOG_WARNING);
  1276. }
  1277. elseif ($type == 'radio')
  1278. {
  1279. $value=$params['options'][$value];
  1280. }
  1281. elseif ($type == 'checkbox')
  1282. {
  1283. $value_arr=explode(',',$value);
  1284. $value='';
  1285. if (is_array($value_arr))
  1286. {
  1287. foreach ($value_arr as $keyval=>$valueval) {
  1288. $toprint[]='<li class="select2-search-choice-dolibarr noborderoncategories" style="background: #aaa">'.$params['options'][$valueval].'</li>';
  1289. }
  1290. }
  1291. $value='<div class="select2-container-multi-dolibarr" style="width: 90%;"><ul class="select2-choices-dolibarr">'.implode(' ', $toprint).'</ul></div>';
  1292. }
  1293. elseif ($type == 'chkbxlst')
  1294. {
  1295. $value_arr = explode(',', $value);
  1296. $param_list = array_keys($params['options']);
  1297. $InfoFieldList = explode(":", $param_list[0]);
  1298. $selectkey = "rowid";
  1299. $keyList = 'rowid';
  1300. if (count($InfoFieldList) >= 3) {
  1301. $selectkey = $InfoFieldList[2];
  1302. $keyList = $InfoFieldList[2] . ' as rowid';
  1303. }
  1304. $fields_label = explode('|', $InfoFieldList[1]);
  1305. if (is_array($fields_label)) {
  1306. $keyList .= ', ';
  1307. $keyList .= implode(', ', $fields_label);
  1308. }
  1309. $sql = 'SELECT ' . $keyList;
  1310. $sql .= ' FROM ' . MAIN_DB_PREFIX . $InfoFieldList[0];
  1311. if (strpos($InfoFieldList[4], 'extra') !== false) {
  1312. $sql .= ' as main';
  1313. }
  1314. // $sql.= " WHERE ".$selectkey."='".$this->db->escape($value)."'";
  1315. // $sql.= ' AND entity = '.$conf->entity;
  1316. dol_syslog(get_class($this) . ':showOutputField:$type=chkbxlst',LOG_DEBUG);
  1317. $resql = $this->db->query($sql);
  1318. if ($resql) {
  1319. $value = ''; // value was used, so now we reste it to use it to build final output
  1320. $toprint=array();
  1321. while ( $obj = $this->db->fetch_object($resql) ) {
  1322. // Several field into label (eq table:code|libelle:rowid)
  1323. $fields_label = explode('|', $InfoFieldList[1]);
  1324. if (is_array($value_arr) && in_array($obj->rowid, $value_arr)) {
  1325. if (is_array($fields_label) && count($fields_label) > 1) {
  1326. foreach ( $fields_label as $field_toshow ) {
  1327. $translabel = '';
  1328. if (! empty($obj->$field_toshow)) {
  1329. $translabel = $langs->trans($obj->$field_toshow);
  1330. }
  1331. if ($translabel != $field_toshow) {
  1332. $toprint[]='<li class="select2-search-choice-dolibarr noborderoncategories" style="background: #aaa">'.dol_trunc($translabel, 18).'</li>';
  1333. } else {
  1334. $toprint[]='<li class="select2-search-choice-dolibarr noborderoncategories" style="background: #aaa">'.$obj->$field_toshow.'</li>';
  1335. }
  1336. }
  1337. } else {
  1338. $translabel = '';
  1339. if (! empty($obj->{$InfoFieldList[1]})) {
  1340. $translabel = $langs->trans($obj->{$InfoFieldList[1]});
  1341. }
  1342. if ($translabel != $obj->{$InfoFieldList[1]}) {
  1343. $toprint[]='<li class="select2-search-choice-dolibarr noborderoncategories" style="background: #aaa">'.dol_trunc($translabel, 18).'</li>';
  1344. } else {
  1345. $toprint[]='<li class="select2-search-choice-dolibarr noborderoncategories" style="background: #aaa">'.$obj->{$InfoFieldList[1]}.'</li>';
  1346. }
  1347. }
  1348. }
  1349. }
  1350. $value='<div class="select2-container-multi-dolibarr" style="width: 90%;"><ul class="select2-choices-dolibarr">'.implode(' ', $toprint).'</ul></div>';
  1351. } else {
  1352. dol_syslog(get_class($this) . '::showOutputField error ' . $this->db->lasterror(), LOG_WARNING);
  1353. }
  1354. }
  1355. elseif ($type == 'link')
  1356. {
  1357. $out='';
  1358. // only if something to display (perf)
  1359. if ($value)
  1360. {
  1361. $param_list=array_keys($params['options']);
  1362. // 0 : ObjectName
  1363. // 1 : classPath
  1364. $InfoFieldList = explode(":", $param_list[0]);
  1365. dol_include_once($InfoFieldList[1]);
  1366. if ($InfoFieldList[0] && class_exists($InfoFieldList[0]))
  1367. {
  1368. $object = new $InfoFieldList[0]($this->db);
  1369. $object->fetch($value);
  1370. $value=$object->getNomUrl(3);
  1371. }
  1372. else
  1373. {
  1374. dol_syslog('Error bad setup of extrafield', LOG_WARNING);
  1375. $out.='Error bad setup of extrafield';
  1376. }
  1377. }
  1378. }
  1379. elseif ($type == 'text')
  1380. {
  1381. $value=dol_htmlentitiesbr($value);
  1382. }
  1383. elseif ($type == 'password')
  1384. {
  1385. $value=preg_replace('/./i','*',$value);
  1386. }
  1387. else
  1388. {
  1389. $showsize=round($size);
  1390. if ($showsize > 48) $showsize=48;
  1391. }
  1392. //print $type.'-'.$size;
  1393. $out=$value;
  1394. if (!empty($hidden)) {
  1395. $out='';
  1396. }
  1397. return $out;
  1398. }
  1399. /**
  1400. * Return tag to describe alignement to use for this extrafield
  1401. *
  1402. * @param string $key Key of attribute
  1403. * @return string Formated value
  1404. */
  1405. function getAlignFlag($key)
  1406. {
  1407. global $conf,$langs;
  1408. $type=$this->attribute_type[$key];
  1409. $align='';
  1410. if ($type == 'date')
  1411. {
  1412. $align="center";
  1413. }
  1414. elseif ($type == 'datetime')
  1415. {
  1416. $align="center";
  1417. }
  1418. elseif ($type == 'int')
  1419. {
  1420. $align="right";
  1421. }
  1422. elseif ($type == 'double')
  1423. {
  1424. $align="right";
  1425. }
  1426. elseif ($type == 'boolean')
  1427. {
  1428. $align="center";
  1429. }
  1430. elseif ($type == 'radio')
  1431. {
  1432. $align="center";
  1433. }
  1434. elseif ($type == 'checkbox')
  1435. {
  1436. $align="center";
  1437. }
  1438. return $align;
  1439. }
  1440. /**
  1441. * Return HTML string to print separator extrafield
  1442. *
  1443. * @param string $key Key of attribute
  1444. * @return string
  1445. */
  1446. function showSeparator($key)
  1447. {
  1448. $out = '<tr class="liste_titre"><td colspan="4"><strong>'.$this->attribute_label[$key].'</strong></td></tr>';
  1449. return $out;
  1450. }
  1451. /**
  1452. * Fill array_options property of object by extrafields value (using for data sent by forms)
  1453. *
  1454. * @param array $extralabels $array of extrafields
  1455. * @param object $object Object
  1456. * @param string $onlykey Only following key is filled. When we make update of only one extrafield ($action = 'update_extras'), calling page must must set this to avoid to have other extrafields being reset.
  1457. * @return int 1 if array_options set, 0 if no value, -1 if error (field required missing for example)
  1458. */
  1459. function setOptionalsFromPost($extralabels,&$object,$onlykey='')
  1460. {
  1461. global $_POST, $langs;
  1462. $nofillrequired='';// For error when required field left blank
  1463. $error_field_required = array();
  1464. if (is_array($extralabels))
  1465. {
  1466. // Get extra fields
  1467. foreach ($extralabels as $key => $value)
  1468. {
  1469. if (! empty($onlykey) && $key != $onlykey) continue;
  1470. $key_type = $this->attribute_type[$key];
  1471. if($this->attribute_required[$key] && !GETPOST("options_$key",2))
  1472. {
  1473. $nofillrequired++;
  1474. $error_field_required[] = $value;
  1475. }
  1476. if (in_array($key_type,array('date','datetime')))
  1477. {
  1478. // Clean parameters
  1479. $value_key=dol_mktime($_POST["options_".$key."hour"], $_POST["options_".$key."min"], 0, $_POST["options_".$key."month"], $_POST["options_".$key."day"], $_POST["options_".$key."year"]);
  1480. }
  1481. else if (in_array($key_type,array('checkbox','chkbxlst')))
  1482. {
  1483. $value_arr=GETPOST("options_".$key);
  1484. if (!empty($value_arr)) {
  1485. $value_key=implode($value_arr,',');
  1486. }else {
  1487. $value_key='';
  1488. }
  1489. }
  1490. else if (in_array($key_type,array('price','double')))
  1491. {
  1492. $value_arr=GETPOST("options_".$key);
  1493. $value_key=price2num($value_arr);
  1494. }
  1495. else
  1496. {
  1497. $value_key=GETPOST("options_".$key);
  1498. }
  1499. $object->array_options["options_".$key]=$value_key;
  1500. }
  1501. if($nofillrequired) {
  1502. $langs->load('errors');
  1503. setEventMessages($langs->trans('ErrorFieldsRequired').' : '.implode(', ',$error_field_required), null, 'errors');
  1504. return -1;
  1505. }
  1506. else {
  1507. return 1;
  1508. }
  1509. }
  1510. else {
  1511. return 0;
  1512. }
  1513. }
  1514. /**
  1515. * return array_options array for object by extrafields value (using for data send by forms)
  1516. *
  1517. * @param array $extralabels $array of extrafields
  1518. * @param string $keyprefix Prefix string to add into name and id of field (can be used to avoid duplicate names)
  1519. * @param string $keysuffix Suffix string to add into name and id of field (can be used to avoid duplicate names)
  1520. * @return int 1 if array_options set / 0 if no value
  1521. */
  1522. function getOptionalsFromPost($extralabels,$keyprefix='',$keysuffix='')
  1523. {
  1524. global $_POST;
  1525. $array_options = array();
  1526. if (is_array($extralabels))
  1527. {
  1528. // Get extra fields
  1529. foreach ($extralabels as $key => $value)
  1530. {
  1531. $key_type = $this->attribute_type[$key];
  1532. if (in_array($key_type,array('date','datetime')))
  1533. {
  1534. // Clean parameters
  1535. $value_key=dol_mktime($_POST[$keysuffix."options_".$key.$keyprefix."hour"], $_POST[$keysuffix."options_".$key.$keyprefix."min"], 0, $_POST[$keysuffix."options_".$key.$keyprefix."month"], $_POST[$keysuffix."options_".$key.$keyprefix."day"], $_POST[$keysuffix."options_".$key.$keyprefix."year"]);
  1536. }
  1537. else if (in_array($key_type,array('checkbox')))
  1538. {
  1539. $value_arr=GETPOST($keysuffix."options_".$key.$keyprefix);
  1540. // Make sure we get an array even if there's only one checkbox
  1541. $value_arr=(array) $value_arr;
  1542. $value_key=implode(',', $value_arr);
  1543. }
  1544. else if (in_array($key_type,array('price','double')))
  1545. {
  1546. $value_arr=GETPOST($keysuffix."options_".$key.$keyprefix);
  1547. $value_key=price2num($value_arr);
  1548. }
  1549. else
  1550. {
  1551. $value_key=GETPOST($keysuffix."options_".$key.$keyprefix);
  1552. }
  1553. $array_options[$keysuffix."options_".$key]=$value_key; // No keyprefix here. keyprefix is used only for read.
  1554. }
  1555. return $array_options;
  1556. }
  1557. else {
  1558. return 0;
  1559. }
  1560. }
  1561. }