extrafields.class.php 93 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253
  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@inodbox.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. * Copyright (C) 2017 Nicolas ZABOURI <info@inovea-conseil.com>
  12. * Copyright (C) 2018-2021 Frédéric France <frederic.france@netlogic.fr>
  13. * Copyright (C) 2022 Antonin MARCHAL <antonin@letempledujeu.fr>
  14. *
  15. * This program is free software; you can redistribute it and/or modify
  16. * it under the terms of the GNU General Public License as published by
  17. * the Free Software Foundation; either version 3 of the License, or
  18. * (at your option) any later version.
  19. *
  20. * This program is distributed in the hope that it will be useful,
  21. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  22. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  23. * GNU General Public License for more details.
  24. *
  25. * You should have received a copy of the GNU General Public License
  26. * along with this program. If not, see <https://www.gnu.org/licenses/>.
  27. */
  28. /**
  29. * \file htdocs/custom/rollerstorage/class/extrafields.class.php
  30. * \ingroup core
  31. * \brief File of class to manage extra fields
  32. */
  33. /**
  34. * Class to manage standard extra fields
  35. */
  36. class Extrafields2
  37. {
  38. /**
  39. * @var DoliDB Database handler.
  40. */
  41. public $db;
  42. /**
  43. * @var array Array with type of the extra field
  44. * @deprecated
  45. */
  46. public $attribute_type;
  47. /**
  48. * @var array Array with label of extra field
  49. * @deprecated
  50. */
  51. public $attribute_label;
  52. /**
  53. * @var array Array with list of possible values for some types of extra fields
  54. * @deprecated
  55. */
  56. public $attribute_choice;
  57. /**
  58. * @var array array to store extrafields definition
  59. * @deprecated
  60. */
  61. public $attribute_list;
  62. /**
  63. * @var array New array to store extrafields definition
  64. */
  65. public $attributes;
  66. /**
  67. * @var array Array with boolean of status of groups
  68. */
  69. public $expand_display;
  70. /**
  71. * @var string Error code (or message)
  72. */
  73. public $error = '';
  74. /**
  75. * @var string[] Array of Error code (or message)
  76. */
  77. public $errors = array();
  78. /**
  79. * @var string DB Error number
  80. */
  81. public $errno;
  82. public static $type2label = array(
  83. 'varchar'=>'String1Line',
  84. 'text'=>'TextLongNLines',
  85. 'html'=>'HtmlText',
  86. 'int'=>'Int',
  87. 'double'=>'Float',
  88. 'date'=>'Date',
  89. 'datetime'=>'DateAndTime',
  90. 'boolean'=>'Boolean',
  91. 'price'=>'ExtrafieldPrice',
  92. 'phone'=>'ExtrafieldPhone',
  93. 'mail'=>'ExtrafieldMail',
  94. 'url'=>'ExtrafieldUrl',
  95. 'password' => 'ExtrafieldPassword',
  96. 'select' => 'ExtrafieldSelect',
  97. 'sellist' => 'ExtrafieldSelectList',
  98. 'radio' => 'ExtrafieldRadio',
  99. 'checkbox' => 'ExtrafieldCheckBox',
  100. 'chkbxlst' => 'ExtrafieldCheckBoxFromList',
  101. 'link' => 'ExtrafieldLink',
  102. 'separate' => 'ExtrafieldSeparator',
  103. );
  104. /**
  105. * Constructor
  106. *
  107. * @param DoliDB $db Database handler
  108. */
  109. public function __construct($db)
  110. {
  111. $this->db = $db;
  112. $this->error = '';
  113. $this->errors = array();
  114. $this->attributes = array();
  115. // For old usage
  116. $this->attribute_type = array();
  117. $this->attribute_label = array();
  118. }
  119. /**
  120. * Add a new extra field parameter
  121. *
  122. * @param string $attrname Code of attribute
  123. * @param string $label label of attribute
  124. * @param string $type Type of attribute ('boolean','int','varchar','text','html','date','datehour','price','phone','mail','password','url','select','checkbox','separate',...)
  125. * @param int $pos Position of attribute
  126. * @param string $size Size/length definition of attribute ('5', '24,8', ...). For float, it contains 2 numeric separated with a comma.
  127. * @param string $elementtype Element type. Same value than object->table_element (Example 'member', 'product', 'thirdparty', ...)
  128. * @param int $unique Is field unique or not
  129. * @param int $required Is field required or not
  130. * @param string $default_value Defaulted value (In database. use the default_value feature for default value on screen. Example: '', '0', 'null', 'avalue')
  131. * @param array|string $param Params for field (ex for select list : array('options' => array(value'=>'label of option')) )
  132. * @param int $alwayseditable Is attribute always editable regardless of the document status
  133. * @param string $perms Permission to check
  134. * @param string $list Visibilty ('0'=never visible, '1'=visible on list+forms, '2'=list only, '3'=form only or 'eval string')
  135. * @param string $help Text with help tooltip
  136. * @param string $computed Computed value
  137. * @param string $entity Entity of extrafields (for multicompany modules)
  138. * @param string $langfile Language file
  139. * @param string $enabled Condition to have the field enabled or not
  140. * @param int $totalizable Is a measure. Must show a total on lists
  141. * @param int $printable Is extrafield displayed on PDF
  142. * @return int <=0 if KO, >0 if OK
  143. */
  144. public function addExtraField($attrname, $label, $type, $pos, $size, $elementtype, $unique = 0, $required = 0, $default_value = '', $param = '', $alwayseditable = 0, $perms = '', $list = '-1', $help = '', $computed = '', $entity = '', $langfile = '', $enabled = '1', $totalizable = 0, $printable = 0)
  145. {
  146. if (empty($attrname)) {
  147. return -1;
  148. }
  149. if (empty($label)) {
  150. return -1;
  151. }
  152. $result = 0;
  153. if ($type == 'separate') {
  154. $unique = 0;
  155. $required = 0;
  156. } // Force unique and not required if this is a separator field to avoid troubles.
  157. if ($elementtype == 'thirdparty') {
  158. $elementtype = 'societe';
  159. }
  160. if ($elementtype == 'contact') {
  161. $elementtype = 'socpeople';
  162. }
  163. // Create field into database except for separator type which is not stored in database
  164. if ($type != 'separate') {
  165. $result = $this->create($attrname, $type, $size, $elementtype, $unique, $required, $default_value, $param, $perms, $list, $computed, $help);
  166. }
  167. $err1 = $this->errno;
  168. if ($result > 0 || $err1 == 'DB_ERROR_COLUMN_ALREADY_EXISTS' || $type == 'separate') {
  169. // Add declaration of field into table
  170. $result2 = $this->create_label($attrname, $label, $type, $pos, $size, $elementtype, $unique, $required, $param, $alwayseditable, $perms, $list, $help, $default_value, $computed, $entity, $langfile, $enabled, $totalizable, $printable);
  171. $err2 = $this->errno;
  172. if ($result2 > 0 || ($err1 == 'DB_ERROR_COLUMN_ALREADY_EXISTS' && $err2 == 'DB_ERROR_RECORD_ALREADY_EXISTS')) {
  173. $this->error = '';
  174. $this->errno = 0;
  175. return 1;
  176. } else {
  177. return -2;
  178. }
  179. } else {
  180. return -1;
  181. }
  182. }
  183. /**
  184. * Add a new optional attribute.
  185. * This is a private method. For public method, use addExtraField.
  186. *
  187. * @param string $attrname code of attribute
  188. * @param int $type Type of attribute ('boolean', 'int', 'varchar', 'text', 'html', 'date', 'datehour','price','phone','mail','password','url','select','checkbox', ...)
  189. * @param string $length Size/length of attribute ('5', '24,8', ...)
  190. * @param string $elementtype Element type ('member', 'product', 'thirdparty', 'contact', ...)
  191. * @param int $unique Is field unique or not
  192. * @param int $required Is field required or not
  193. * @param string $default_value Default value for field (in database)
  194. * @param array $param Params for field (ex for select list : array('options'=>array('value'=>'label of option'))
  195. * @param string $perms Permission
  196. * @param string $list Into list view by default
  197. * @param string $computed Computed value
  198. * @param string $help Help on tooltip
  199. * @return int <=0 if KO, >0 if OK
  200. */
  201. private function create($attrname, $type = 'varchar', $length = 255, $elementtype = 'member', $unique = 0, $required = 0, $default_value = '', $param = '', $perms = '', $list = '0', $computed = '', $help = '')
  202. {
  203. if ($elementtype == 'thirdparty') {
  204. $elementtype = 'societe';
  205. }
  206. if ($elementtype == 'contact') {
  207. $elementtype = 'socpeople';
  208. }
  209. $table = $elementtype.'_extrafields';
  210. if ($elementtype == 'categorie') {
  211. $table = 'categories_extrafields';
  212. }
  213. if (!empty($attrname) && preg_match("/^\w[a-zA-Z0-9_]*$/", $attrname) && !is_numeric($attrname)) {
  214. if ($type == 'boolean') {
  215. $typedb = 'int';
  216. $lengthdb = '1';
  217. } elseif ($type == 'price') {
  218. $typedb = 'double';
  219. $lengthdb = '24,8';
  220. } elseif ($type == 'phone') {
  221. $typedb = 'varchar';
  222. $lengthdb = '20';
  223. } elseif ($type == 'mail') {
  224. $typedb = 'varchar';
  225. $lengthdb = '128';
  226. } elseif ($type == 'url') {
  227. $typedb = 'varchar';
  228. $lengthdb = '255';
  229. } elseif (($type == 'select') || ($type == 'sellist') || ($type == 'radio') || ($type == 'checkbox') || ($type == 'chkbxlst')) {
  230. $typedb = 'varchar';
  231. $lengthdb = '255';
  232. } elseif ($type == 'link') {
  233. $typedb = 'int';
  234. $lengthdb = '11';
  235. } elseif ($type == 'html') {
  236. $typedb = 'text';
  237. $lengthdb = $length;
  238. } elseif ($type == 'password') {
  239. $typedb = 'varchar';
  240. $lengthdb = '128';
  241. } else {
  242. $typedb = $type;
  243. $lengthdb = $length;
  244. if ($type == 'varchar' && empty($lengthdb)) {
  245. $lengthdb = '255';
  246. }
  247. }
  248. $field_desc = array(
  249. 'type'=>$typedb,
  250. 'value'=>$lengthdb,
  251. 'null'=>($required ? 'NOT NULL' : 'NULL'),
  252. 'default' => $default_value
  253. );
  254. $result = $this->db->DDLAddField($this->db->prefix().$table, $attrname, $field_desc);
  255. if ($result > 0) {
  256. if ($unique) {
  257. $sql = "ALTER TABLE ".$this->db->prefix().$table." ADD UNIQUE INDEX uk_".$table."_".$attrname." (".$attrname.")";
  258. $resql = $this->db->query($sql, 1, 'dml');
  259. }
  260. return 1;
  261. } else {
  262. $this->error = $this->db->lasterror();
  263. $this->errno = $this->db->lasterrno();
  264. return -1;
  265. }
  266. } else {
  267. return 0;
  268. }
  269. }
  270. // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
  271. /**
  272. * Add description of a new optional attribute
  273. *
  274. * @param string $attrname code of attribute
  275. * @param string $label label of attribute
  276. * @param int $type Type of attribute ('int', 'varchar', 'text', 'html', 'date', 'datehour', 'float')
  277. * @param int $pos Position of attribute
  278. * @param string $size Size/length of attribute ('5', '24,8', ...)
  279. * @param string $elementtype Element type ('member', 'product', 'thirdparty', ...)
  280. * @param int $unique Is field unique or not
  281. * @param int $required Is field required or not
  282. * @param array|string $param Params for field (ex for select list : array('options' => array(value'=>'label of option')) )
  283. * @param int $alwayseditable Is attribute always editable regardless of the document status
  284. * @param string $perms Permission to check
  285. * @param string $list Visibily
  286. * @param string $help Help on tooltip
  287. * @param string $default Default value (in database. use the default_value feature for default value on screen).
  288. * @param string $computed Computed value
  289. * @param string $entity Entity of extrafields
  290. * @param string $langfile Language file
  291. * @param string $enabled Condition to have the field enabled or not
  292. * @param int $totalizable Is a measure. Must show a total on lists
  293. * @param int $printable Is extrafield displayed on PDF
  294. * @return int <=0 if KO, >0 if OK
  295. * @throws Exception
  296. */
  297. private function create_label($attrname, $label = '', $type = '', $pos = 0, $size = 0, $elementtype = 'member', $unique = 0, $required = 0, $param = '', $alwayseditable = 0, $perms = '', $list = '-1', $help = '', $default = '', $computed = '', $entity = '', $langfile = '', $enabled = '1', $totalizable = 0, $printable = 0)
  298. {
  299. // phpcs:enable
  300. global $conf, $user;
  301. if ($elementtype == 'thirdparty') {
  302. $elementtype = 'societe';
  303. }
  304. if ($elementtype == 'contact') {
  305. $elementtype = 'socpeople';
  306. }
  307. // Clean parameters
  308. if (empty($pos)) {
  309. $pos = 0;
  310. }
  311. if (empty($list)) {
  312. $list = '0';
  313. }
  314. if (empty($required)) {
  315. $required = 0;
  316. }
  317. if (empty($unique)) {
  318. $unique = 0;
  319. }
  320. if (empty($printable)) {
  321. $printable = 0;
  322. }
  323. if (empty($alwayseditable)) {
  324. $alwayseditable = 0;
  325. }
  326. if (empty($totalizable)) {
  327. $totalizable = 0;
  328. }
  329. if (!empty($attrname) && preg_match("/^\w[a-zA-Z0-9-_]*$/", $attrname) && !is_numeric($attrname)) {
  330. if (is_array($param) && count($param) > 0) {
  331. $params = serialize($param);
  332. } elseif (strlen($param) > 0) {
  333. $params = trim($param);
  334. } else {
  335. $params = '';
  336. }
  337. $sql = "INSERT INTO ".$this->db->prefix()."extrafields(";
  338. $sql .= " name,";
  339. $sql .= " label,";
  340. $sql .= " type,";
  341. $sql .= " pos,";
  342. $sql .= " size,";
  343. $sql .= " entity,";
  344. $sql .= " elementtype,";
  345. $sql .= " fieldunique,";
  346. $sql .= " fieldrequired,";
  347. $sql .= " param,";
  348. $sql .= " alwayseditable,";
  349. $sql .= " perms,";
  350. $sql .= " langs,";
  351. $sql .= " list,";
  352. $sql .= " printable,";
  353. $sql .= " fielddefault,";
  354. $sql .= " fieldcomputed,";
  355. $sql .= " fk_user_author,";
  356. $sql .= " fk_user_modif,";
  357. $sql .= " datec,";
  358. $sql .= " enabled,";
  359. $sql .= " help,";
  360. $sql .= " totalizable";
  361. $sql .= " )";
  362. $sql .= " VALUES('".$this->db->escape($attrname)."',";
  363. $sql .= " '".$this->db->escape($label)."',";
  364. $sql .= " '".$this->db->escape($type)."',";
  365. $sql .= " ".((int) $pos).",";
  366. $sql .= " '".$this->db->escape($size)."',";
  367. $sql .= " ".($entity === '' ? $conf->entity : $entity).",";
  368. $sql .= " '".$this->db->escape($elementtype)."',";
  369. $sql .= " ".((int) $unique).",";
  370. $sql .= " ".((int) $required).",";
  371. $sql .= " '".$this->db->escape($params)."',";
  372. $sql .= " ".((int) $alwayseditable).",";
  373. $sql .= " ".($perms ? "'".$this->db->escape($perms)."'" : "null").",";
  374. $sql .= " ".($langfile ? "'".$this->db->escape($langfile)."'" : "null").",";
  375. $sql .= " '".$this->db->escape($list)."',";
  376. $sql .= " '".$this->db->escape($printable)."',";
  377. $sql .= " ".($default ? "'".$this->db->escape($default)."'" : "null").",";
  378. $sql .= " ".($computed ? "'".$this->db->escape($computed)."'" : "null").",";
  379. $sql .= " ".(is_object($user) ? $user->id : 0).",";
  380. $sql .= " ".(is_object($user) ? $user->id : 0).",";
  381. $sql .= "'".$this->db->idate(dol_now())."',";
  382. $sql .= " ".($enabled ? "'".$this->db->escape($enabled)."'" : "1").",";
  383. $sql .= " ".($help ? "'".$this->db->escape($help)."'" : "null").",";
  384. $sql .= " ".($totalizable ? 'TRUE' : 'FALSE');
  385. $sql .= ')';
  386. dol_syslog(get_class($this)."::create_label", LOG_DEBUG);
  387. if ($this->db->query($sql)) {
  388. return 1;
  389. } else {
  390. $this->error = $this->db->lasterror();
  391. $this->errno = $this->db->lasterrno();
  392. return -1;
  393. }
  394. }
  395. }
  396. /**
  397. * Delete an optional attribute
  398. *
  399. * @param string $attrname Code of attribute to delete
  400. * @param string $elementtype Element type ('member', 'product', 'thirdparty', 'contact', ...)
  401. * @return int < 0 if KO, 0 if nothing is done, 1 if OK
  402. */
  403. public function delete($attrname, $elementtype = 'member')
  404. {
  405. if ($elementtype == 'thirdparty') {
  406. $elementtype = 'societe';
  407. }
  408. if ($elementtype == 'contact') {
  409. $elementtype = 'socpeople';
  410. }
  411. $table = $elementtype.'_extrafields';
  412. if ($elementtype == 'categorie') {
  413. $table = 'categories_extrafields';
  414. }
  415. $error = 0;
  416. if (!empty($attrname) && preg_match("/^\w[a-zA-Z0-9-_]*$/", $attrname)) {
  417. $result = $this->delete_label($attrname, $elementtype);
  418. if ($result < 0) {
  419. $this->error = $this->db->lasterror();
  420. $this->errors[] = $this->db->lasterror();
  421. $error++;
  422. }
  423. if (!$error) {
  424. $sql = "SELECT COUNT(rowid) as nb";
  425. $sql .= " FROM ".$this->db->prefix()."extrafields";
  426. $sql .= " WHERE elementtype = '".$this->db->escape($elementtype)."'";
  427. $sql .= " AND name = '".$this->db->escape($attrname)."'";
  428. //$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
  429. $resql = $this->db->query($sql);
  430. if ($resql) {
  431. $obj = $this->db->fetch_object($resql);
  432. if ($obj->nb <= 0) {
  433. $result = $this->db->DDLDropField($this->db->prefix().$table, $attrname); // This also drop the unique key
  434. if ($result < 0) {
  435. $this->error = $this->db->lasterror();
  436. $this->errors[] = $this->db->lasterror();
  437. $error++;
  438. }
  439. }
  440. }
  441. }
  442. return $result;
  443. } else {
  444. return 0;
  445. }
  446. }
  447. // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
  448. /**
  449. * Delete description of an optional attribute
  450. *
  451. * @param string $attrname Code of attribute to delete
  452. * @param string $elementtype Element type ('member', 'product', 'thirdparty', ...)
  453. * @return int < 0 if KO, 0 if nothing is done, 1 if OK
  454. */
  455. private function delete_label($attrname, $elementtype = 'member')
  456. {
  457. // phpcs:enable
  458. global $conf;
  459. if ($elementtype == 'thirdparty') {
  460. $elementtype = 'societe';
  461. }
  462. if ($elementtype == 'contact') {
  463. $elementtype = 'socpeople';
  464. }
  465. if (isset($attrname) && $attrname != '' && preg_match("/^\w[a-zA-Z0-9-_]*$/", $attrname)) {
  466. $sql = "DELETE FROM ".$this->db->prefix()."extrafields";
  467. $sql .= " WHERE name = '".$this->db->escape($attrname)."'";
  468. $sql .= " AND entity IN (0,".$conf->entity.')';
  469. $sql .= " AND elementtype = '".$this->db->escape($elementtype)."'";
  470. dol_syslog(get_class($this)."::delete_label", LOG_DEBUG);
  471. $resql = $this->db->query($sql);
  472. if ($resql) {
  473. return 1;
  474. } else {
  475. dol_print_error($this->db);
  476. return -1;
  477. }
  478. } else {
  479. return 0;
  480. }
  481. }
  482. /**
  483. * Modify type of a personalized attribute
  484. *
  485. * @param string $attrname Name of attribute
  486. * @param string $label Label of attribute
  487. * @param string $type Type of attribute ('boolean', 'int', 'varchar', 'text', 'html', 'date', 'datehour','price','phone','mail','password','url','select','checkbox', ...)
  488. * @param int $length Length of attribute
  489. * @param string $elementtype Element type ('member', 'product', 'thirdparty', 'contact', ...)
  490. * @param int $unique Is field unique or not
  491. * @param int $required Is field required or not
  492. * @param int $pos Position of attribute
  493. * @param array $param Params for field (ex for select list : array('options' => array(value'=>'label of option')) )
  494. * @param int $alwayseditable Is attribute always editable regardless of the document status
  495. * @param string $perms Permission to check
  496. * @param string $list Visibility
  497. * @param string $help Help on tooltip
  498. * @param string $default Default value (in database. use the default_value feature for default value on screen).
  499. * @param string $computed Computed value
  500. * @param string $entity Entity of extrafields
  501. * @param string $langfile Language file
  502. * @param string $enabled Condition to have the field enabled or not
  503. * @param int $totalizable Is extrafield totalizable on list
  504. * @param int $printable Is extrafield displayed on PDF
  505. * @return int >0 if OK, <=0 if KO
  506. * @throws Exception
  507. */
  508. public function update($attrname, $label, $type, $length, $elementtype, $unique = 0, $required = 0, $pos = 0, $param = '', $alwayseditable = 0, $perms = '', $list = '', $help = '', $default = '', $computed = '', $entity = '', $langfile = '', $enabled = '1', $totalizable = 0, $printable = 0)
  509. {
  510. global $hookmanager;
  511. if ($elementtype == 'thirdparty') {
  512. $elementtype = 'societe';
  513. }
  514. if ($elementtype == 'contact') {
  515. $elementtype = 'socpeople';
  516. }
  517. $table = $elementtype.'_extrafields';
  518. if ($elementtype == 'categorie') {
  519. $table = 'categories_extrafields';
  520. }
  521. if (isset($attrname) && $attrname != '' && preg_match("/^\w[a-zA-Z0-9-_]*$/", $attrname)) {
  522. if ($type == 'boolean') {
  523. $typedb = 'int';
  524. $lengthdb = '1';
  525. } elseif ($type == 'price') {
  526. $typedb = 'double';
  527. $lengthdb = '24,8';
  528. } elseif ($type == 'phone') {
  529. $typedb = 'varchar';
  530. $lengthdb = '20';
  531. } elseif ($type == 'mail') {
  532. $typedb = 'varchar';
  533. $lengthdb = '128';
  534. } elseif ($type == 'url') {
  535. $typedb = 'varchar';
  536. $lengthdb = '255';
  537. } elseif (($type == 'select') || ($type == 'sellist') || ($type == 'radio') || ($type == 'checkbox') || ($type == 'chkbxlst')) {
  538. $typedb = 'varchar';
  539. $lengthdb = '255';
  540. } elseif ($type == 'html') {
  541. $typedb = 'text';
  542. } elseif ($type == 'link') {
  543. $typedb = 'int';
  544. $lengthdb = '11';
  545. } elseif ($type == 'password') {
  546. $typedb = 'varchar';
  547. $lengthdb = '50';
  548. } else {
  549. $typedb = $type;
  550. $lengthdb = $length;
  551. }
  552. $field_desc = array('type'=>$typedb, 'value'=>$lengthdb, 'null'=>($required ? 'NOT NULL' : 'NULL'), 'default'=>$default);
  553. if (is_object($hookmanager)) {
  554. $hookmanager->initHooks(array('extrafieldsdao'));
  555. $parameters = array('field_desc'=>&$field_desc, 'table'=>$table, 'attr_name'=>$attrname, 'label'=>$label, 'type'=>$type, 'length'=>$length, 'unique'=>$unique, 'required'=>$required, 'pos'=>$pos, 'param'=>$param, 'alwayseditable'=>$alwayseditable, 'perms'=>$perms, 'list'=>$list, 'help'=>$help, 'default'=>$default, 'computed'=>$computed, 'entity'=>$entity, 'langfile'=>$langfile, 'enabled'=>$enabled, 'totalizable'=>$totalizable, 'printable'=>$printable);
  556. $reshook = $hookmanager->executeHooks('updateExtrafields', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks
  557. if ($reshook < 0) {
  558. $this->error = $this->db->lasterror();
  559. return -1;
  560. }
  561. }
  562. if ($type != 'separate') { // No table update when separate type
  563. $result = $this->db->DDLUpdateField($this->db->prefix().$table, $attrname, $field_desc);
  564. }
  565. if ($result > 0 || $type == 'separate') {
  566. if ($label) {
  567. $result = $this->update_label($attrname, $label, $type, $length, $elementtype, $unique, $required, $pos, $param, $alwayseditable, $perms, $list, $help, $default, $computed, $entity, $langfile, $enabled, $totalizable, $printable);
  568. }
  569. if ($result > 0) {
  570. $sql = '';
  571. if ($unique) {
  572. $sql = "ALTER TABLE ".$this->db->prefix().$table." ADD UNIQUE INDEX uk_".$table."_".$attrname." (".$attrname.")";
  573. } else {
  574. $sql = "ALTER TABLE ".$this->db->prefix().$table." DROP INDEX IF EXISTS uk_".$table."_".$attrname;
  575. }
  576. dol_syslog(get_class($this).'::update', LOG_DEBUG);
  577. $resql = $this->db->query($sql, 1, 'dml');
  578. /*if ($resql < 0) {
  579. $this->error = $this->db->lasterror();
  580. return -1;
  581. }*/
  582. return 1;
  583. } else {
  584. $this->error = $this->db->lasterror();
  585. return -1;
  586. }
  587. } else {
  588. $this->error = $this->db->lasterror();
  589. return -1;
  590. }
  591. } else {
  592. return 0;
  593. }
  594. }
  595. // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
  596. /**
  597. * Modify description of personalized attribute
  598. *
  599. * @param string $attrname Name of attribute
  600. * @param string $label Label of attribute
  601. * @param string $type Type of attribute
  602. * @param int $size Length of attribute
  603. * @param string $elementtype Element type ('member', 'product', 'thirdparty', ...)
  604. * @param int $unique Is field unique or not
  605. * @param int $required Is field required or not
  606. * @param int $pos Position of attribute
  607. * @param array $param Params for field (ex for select list : array('options' => array(value'=>'label of option')) )
  608. * @param int $alwayseditable Is attribute always editable regardless of the document status
  609. * @param string $perms Permission to check
  610. * @param string $list Visiblity
  611. * @param string $help Help on tooltip.
  612. * @param string $default Default value (in database. use the default_value feature for default value on screen).
  613. * @param string $computed Computed value
  614. * @param string $entity Entity of extrafields
  615. * @param string $langfile Language file
  616. * @param string $enabled Condition to have the field enabled or not
  617. * @param int $totalizable Is extrafield totalizable on list
  618. * @param int $printable Is extrafield displayed on PDF
  619. * @return int <=0 if KO, >0 if OK
  620. * @throws Exception
  621. */
  622. private function update_label($attrname, $label, $type, $size, $elementtype, $unique = 0, $required = 0, $pos = 0, $param = '', $alwayseditable = 0, $perms = '', $list = '0', $help = '', $default = '', $computed = '', $entity = '', $langfile = '', $enabled = '1', $totalizable = 0, $printable = 0)
  623. {
  624. // phpcs:enable
  625. global $conf, $user;
  626. dol_syslog(get_class($this)."::update_label ".$attrname.", ".$label.", ".$type.", ".$size.", ".$elementtype.", ".$unique.", ".$required.", ".$pos.", ".$alwayseditable.", ".$perms.", ".$list.", ".$default.", ".$computed.", ".$entity.", ".$langfile.", ".$enabled.", ".$totalizable.", ".$printable);
  627. // Clean parameters
  628. if ($elementtype == 'thirdparty') {
  629. $elementtype = 'societe';
  630. }
  631. if ($elementtype == 'contact') {
  632. $elementtype = 'socpeople';
  633. }
  634. if (empty($pos)) {
  635. $pos = 0;
  636. }
  637. if (empty($list)) {
  638. $list = '0';
  639. }
  640. if (empty($totalizable)) {
  641. $totalizable = 0;
  642. }
  643. if (empty($required)) {
  644. $required = 0;
  645. }
  646. if (empty($unique)) {
  647. $unique = 0;
  648. }
  649. if (empty($alwayseditable)) {
  650. $alwayseditable = 0;
  651. }
  652. if (isset($attrname) && $attrname != '' && preg_match("/^\w[a-zA-Z0-9-_]*$/", $attrname)) {
  653. $this->db->begin();
  654. if (is_array($param) && count($param) > 0) {
  655. $params = serialize($param);
  656. } elseif (strlen($param) > 0) {
  657. $params = trim($param);
  658. } else {
  659. $params = '';
  660. }
  661. if ($entity === '' || $entity != '0') {
  662. // We dont want on all entities, we delete all and current
  663. $sql_del = "DELETE FROM ".$this->db->prefix()."extrafields";
  664. $sql_del .= " WHERE name = '".$this->db->escape($attrname)."'";
  665. $sql_del .= " AND entity IN (0, ".($entity === '' ? $conf->entity : $entity).")";
  666. $sql_del .= " AND elementtype = '".$this->db->escape($elementtype)."'";
  667. } else {
  668. // We want on all entities ($entities = '0'), we delete on all only (we keep setup specific to each entity)
  669. $sql_del = "DELETE FROM ".$this->db->prefix()."extrafields";
  670. $sql_del .= " WHERE name = '".$this->db->escape($attrname)."'";
  671. $sql_del .= " AND entity = 0";
  672. $sql_del .= " AND elementtype = '".$this->db->escape($elementtype)."'";
  673. }
  674. $resql1 = $this->db->query($sql_del);
  675. $sql = "INSERT INTO ".$this->db->prefix()."extrafields(";
  676. $sql .= " name,"; // This is code
  677. $sql .= " entity,";
  678. $sql .= " label,";
  679. $sql .= " type,";
  680. $sql .= " size,";
  681. $sql .= " elementtype,";
  682. $sql .= " fieldunique,";
  683. $sql .= " fieldrequired,";
  684. $sql .= " perms,";
  685. $sql .= " langs,";
  686. $sql .= " pos,";
  687. $sql .= " alwayseditable,";
  688. $sql .= " param,";
  689. $sql .= " list,";
  690. $sql .= " printable,";
  691. $sql .= " totalizable,";
  692. $sql .= " fielddefault,";
  693. $sql .= " fieldcomputed,";
  694. $sql .= " fk_user_author,";
  695. $sql .= " fk_user_modif,";
  696. $sql .= " datec,";
  697. $sql .= " enabled,";
  698. $sql .= " help";
  699. $sql .= ") VALUES (";
  700. $sql .= "'".$this->db->escape($attrname)."',";
  701. $sql .= " ".($entity === '' ? $conf->entity : $entity).",";
  702. $sql .= " '".$this->db->escape($label)."',";
  703. $sql .= " '".$this->db->escape($type)."',";
  704. $sql .= " '".$this->db->escape($size)."',";
  705. $sql .= " '".$this->db->escape($elementtype)."',";
  706. $sql .= " ".$unique.",";
  707. $sql .= " ".$required.",";
  708. $sql .= " ".($perms ? "'".$this->db->escape($perms)."'" : "null").",";
  709. $sql .= " ".($langfile ? "'".$this->db->escape($langfile)."'" : "null").",";
  710. $sql .= " ".$pos.",";
  711. $sql .= " '".$this->db->escape($alwayseditable)."',";
  712. $sql .= " '".$this->db->escape($params)."',";
  713. $sql .= " '".$this->db->escape($list)."', ";
  714. $sql .= " '".$this->db->escape($printable)."', ";
  715. $sql .= " ".($totalizable ? 'TRUE' : 'FALSE').",";
  716. $sql .= " ".(($default != '') ? "'".$this->db->escape($default)."'" : "null").",";
  717. $sql .= " ".($computed ? "'".$this->db->escape($computed)."'" : "null").",";
  718. $sql .= " ".$user->id.",";
  719. $sql .= " ".$user->id.",";
  720. $sql .= "'".$this->db->idate(dol_now())."',";
  721. $sql .= "'".$this->db->escape($enabled)."',";
  722. $sql .= " ".($help ? "'".$this->db->escape($help)."'" : "null");
  723. $sql .= ")";
  724. $resql2 = $this->db->query($sql);
  725. if ($resql1 && $resql2) {
  726. $this->db->commit();
  727. return 1;
  728. } else {
  729. $this->db->rollback();
  730. dol_print_error($this->db);
  731. return -1;
  732. }
  733. } else {
  734. return 0;
  735. }
  736. }
  737. // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
  738. /**
  739. * Load array this->attributes (and some old this->attribute_xxx like attribute_label, attribute_type, ...
  740. *
  741. * @param string $elementtype Type of element ('' = all or $object->table_element like 'adherent', 'commande', 'thirdparty', 'facture', 'propal', 'product', ...).
  742. * @param boolean $forceload Force load of extra fields whatever is status of cache.
  743. * @return array Array of attributes keys+label for all extra fields.
  744. */
  745. public function fetch_name_optionals_label($elementtype, $forceload = false)
  746. {
  747. // phpcs:enable
  748. global $conf;
  749. if (empty($elementtype)) {
  750. return array();
  751. }
  752. if ($elementtype == 'thirdparty') {
  753. $elementtype = 'societe';
  754. }
  755. if ($elementtype == 'contact') {
  756. $elementtype = 'socpeople';
  757. }
  758. if ($elementtype == 'order_supplier') {
  759. $elementtype = 'commande_fournisseur';
  760. }
  761. $array_name_label = array();
  762. // We should not have several time this request. If we have, there is some optimization to do by calling a simple $extrafields->fetch_optionals() in top of code and not into subcode
  763. $sql = "SELECT rowid, name, label, type, size, elementtype, fieldunique, fieldrequired, param, pos, alwayseditable, perms, langs, list, printable, totalizable, fielddefault, fieldcomputed, entity, enabled, help,";
  764. $sql .= " css, cssview, csslist";
  765. $sql .= " FROM ".$this->db->prefix()."extrafields";
  766. //$sql.= " WHERE entity IN (0,".$conf->entity.")"; // Filter is done later
  767. if ($elementtype) {
  768. $sql .= " WHERE elementtype = '".$this->db->escape($elementtype)."'"; // Filed with object->table_element
  769. }
  770. $sql .= " ORDER BY pos";
  771. $resql = $this->db->query($sql);
  772. if ($resql) {
  773. if ($this->db->num_rows($resql)) {
  774. while ($tab = $this->db->fetch_object($resql)) {
  775. if ($tab->entity != 0 && $tab->entity != $conf->entity) {
  776. // This field is not in current entity. We discard but before we save it into the array of mandatory fields if it is a mandatory field without default value
  777. if ($tab->fieldrequired && is_null($tab->fielddefault)) {
  778. $this->attributes[$tab->elementtype]['mandatoryfieldsofotherentities'][$tab->name] = $tab->type;
  779. }
  780. continue;
  781. }
  782. // We can add this attribute to object. TODO Remove this and return $this->attributes[$elementtype]['label']
  783. if ($tab->type != 'separate') {
  784. $array_name_label[$tab->name] = $tab->label;
  785. }
  786. // Old usage
  787. $this->attribute_type[$tab->name] = $tab->type;
  788. $this->attribute_label[$tab->name] = $tab->label;
  789. // New usage
  790. $this->attributes[$tab->elementtype]['type'][$tab->name] = $tab->type;
  791. $this->attributes[$tab->elementtype]['label'][$tab->name] = $tab->label;
  792. $this->attributes[$tab->elementtype]['size'][$tab->name] = $tab->size;
  793. $this->attributes[$tab->elementtype]['elementtype'][$tab->name] = $tab->elementtype;
  794. $this->attributes[$tab->elementtype]['default'][$tab->name] = $tab->fielddefault;
  795. $this->attributes[$tab->elementtype]['computed'][$tab->name] = $tab->fieldcomputed;
  796. $this->attributes[$tab->elementtype]['unique'][$tab->name] = $tab->fieldunique;
  797. $this->attributes[$tab->elementtype]['required'][$tab->name] = $tab->fieldrequired;
  798. $this->attributes[$tab->elementtype]['param'][$tab->name] = ($tab->param ? jsonOrUnserialize($tab->param) : '');
  799. $this->attributes[$tab->elementtype]['pos'][$tab->name] = $tab->pos;
  800. $this->attributes[$tab->elementtype]['alwayseditable'][$tab->name] = $tab->alwayseditable;
  801. $this->attributes[$tab->elementtype]['perms'][$tab->name] = ((is_null($tab->perms) || strlen($tab->perms) == 0) ? 1 : $tab->perms);
  802. $this->attributes[$tab->elementtype]['langfile'][$tab->name] = $tab->langs;
  803. $this->attributes[$tab->elementtype]['list'][$tab->name] = $tab->list;
  804. $this->attributes[$tab->elementtype]['printable'][$tab->name] = $tab->printable;
  805. $this->attributes[$tab->elementtype]['totalizable'][$tab->name] = ($tab->totalizable ? 1 : 0);
  806. $this->attributes[$tab->elementtype]['entityid'][$tab->name] = $tab->entity;
  807. $this->attributes[$tab->elementtype]['enabled'][$tab->name] = $tab->enabled;
  808. $this->attributes[$tab->elementtype]['help'][$tab->name] = $tab->help;
  809. $this->attributes[$tab->elementtype]['css'][$tab->name] = $tab->css;
  810. $this->attributes[$tab->elementtype]['cssview'][$tab->name] = $tab->cssview;
  811. $this->attributes[$tab->elementtype]['csslist'][$tab->name] = $tab->csslist;
  812. $this->attributes[$tab->elementtype]['loaded'] = 1;
  813. }
  814. }
  815. if ($elementtype) {
  816. $this->attributes[$elementtype]['loaded'] = 1; // If nothing found, we also save tag 'loaded'
  817. }
  818. } else {
  819. $this->error = $this->db->lasterror();
  820. dol_syslog(get_class($this)."::fetch_name_optionals_label ".$this->error, LOG_ERR);
  821. }
  822. return $array_name_label;
  823. }
  824. /**
  825. * Return HTML string to put an input field into a page
  826. * Code very similar with showInputField of common object
  827. *
  828. * @param string $key Key of attribute
  829. * @param string|array $value Preselected value to show (for date type it must be in timestamp format, for amount or price it must be a php numeric value); for dates in filter mode, a range array('start'=><timestamp>, 'end'=><timestamp>) should be provided
  830. * @param string $moreparam To add more parameters on html input tag
  831. * @param string $keysuffix Prefix string to add after name and id of field (can be used to avoid duplicate names)
  832. * @param string $keyprefix Suffix string to add before name and id of field (can be used to avoid duplicate names)
  833. * @param string $morecss More css (to defined size of field. Old behaviour: may also be a numeric)
  834. * @param int $objectid Current object id
  835. * @param string $extrafieldsobjectkey If defined (for example $object->table_element), use the new method to get extrafields data
  836. * @param string $mode 1=Used for search filters
  837. * @return string
  838. */
  839. public function showInputField($key, $value, $moreparam = '', $keysuffix = '', $keyprefix = '', $morecss = '', $objectid = 0, $extrafieldsobjectkey = '', $mode = 0)
  840. {
  841. global $conf, $langs, $form;
  842. if (!is_object($form)) {
  843. require_once DOL_DOCUMENT_ROOT.'/core/class/html.form.class.php';
  844. $form = new Form($this->db);
  845. }
  846. $out = '';
  847. if (!preg_match('/options_$/', $keyprefix)) { // Because we work on extrafields, we add 'options_' to prefix if not already added
  848. $keyprefix = $keyprefix.'options_';
  849. }
  850. if (!empty($extrafieldsobjectkey)) {
  851. $label = $this->attributes[$extrafieldsobjectkey]['label'][$key];
  852. $type = $this->attributes[$extrafieldsobjectkey]['type'][$key];
  853. $size = $this->attributes[$extrafieldsobjectkey]['size'][$key];
  854. $default = $this->attributes[$extrafieldsobjectkey]['default'][$key];
  855. $computed = $this->attributes[$extrafieldsobjectkey]['computed'][$key];
  856. $unique = $this->attributes[$extrafieldsobjectkey]['unique'][$key];
  857. $required = $this->attributes[$extrafieldsobjectkey]['required'][$key];
  858. $param = $this->attributes[$extrafieldsobjectkey]['param'][$key];
  859. $perms = dol_eval($this->attributes[$extrafieldsobjectkey]['perms'][$key], 1, 1, '1');
  860. $langfile = $this->attributes[$extrafieldsobjectkey]['langfile'][$key];
  861. $list = dol_eval($this->attributes[$extrafieldsobjectkey]['list'][$key], 1, 1, '1');
  862. $totalizable = $this->attributes[$extrafieldsobjectkey]['totalizable'][$key];
  863. $help = $this->attributes[$extrafieldsobjectkey]['help'][$key];
  864. $hidden = (empty($list) ? 1 : 0); // If empty, we are sure it is hidden, otherwise we show. If it depends on mode (view/create/edit form or list, this must be filtered by caller)
  865. } else {
  866. // Old usage
  867. $label = $this->attribute_label[$key];
  868. $type = $this->attribute_type[$key];
  869. $list = $this->attribute_list[$key];
  870. $hidden = (empty($list) ? 1 : 0); // If empty, we are sure it is hidden, otherwise we show. If it depends on mode (view/create/edit form or list, this must be filtered by caller)
  871. }
  872. if ($computed) {
  873. if (!preg_match('/^search_/', $keyprefix)) {
  874. return '<span class="opacitymedium">'.$langs->trans("AutomaticallyCalculated").'</span>';
  875. } else {
  876. return '';
  877. }
  878. }
  879. if (empty($morecss)) {
  880. if ($type == 'date') {
  881. $morecss = 'minwidth100imp';
  882. } elseif ($type == 'datetime' || $type == 'link') {
  883. $morecss = 'minwidth200imp';
  884. } elseif (in_array($type, array('int', 'integer', 'double', 'price'))) {
  885. $morecss = 'maxwidth75';
  886. } elseif ($type == 'password') {
  887. $morecss = 'maxwidth100';
  888. } elseif ($type == 'url') {
  889. $morecss = 'minwidth400';
  890. } elseif ($type == 'boolean') {
  891. $morecss = '';
  892. } elseif ($type == 'radio') {
  893. $morecss = 'width25';
  894. } else {
  895. if (empty($size) || round($size) < 12) {
  896. $morecss = 'minwidth100';
  897. } elseif (round($size) <= 48) {
  898. $morecss = 'minwidth200';
  899. } else {
  900. $morecss = 'minwidth400';
  901. }
  902. }
  903. }
  904. if (in_array($type, array('date'))) {
  905. $tmp = explode(',', $size);
  906. $newsize = $tmp[0];
  907. $showtime = 0;
  908. // Do not show current date when field not required (see selectDate() method)
  909. if (!$required && $value == '') {
  910. $value = '-1';
  911. }
  912. if ($mode == 1) {
  913. // search filter on a date extrafield shows two inputs to select a date range
  914. $prefill = array(
  915. 'start' => isset($value['start']) ? $value['start'] : '',
  916. 'end' => isset($value['end']) ? $value['end'] : ''
  917. );
  918. $out = '<div ' . ($moreparam ? $moreparam : '') . '><div class="nowrap">';
  919. $out .= $form->selectDate($prefill['start'], $keyprefix.$key.$keysuffix.'_start', 0, 0, 1, '', 1, 0, 0, '', '', '', '', 1, '', $langs->trans("From"));
  920. $out .= '</div><div class="nowrap">';
  921. $out .= $form->selectDate($prefill['end'], $keyprefix.$key.$keysuffix.'_end', 0, 0, 1, '', 1, 0, 0, '', '', '', '', 1, '', $langs->trans("to"));
  922. $out .= '</div></div>';
  923. } else {
  924. // TODO Must also support $moreparam
  925. $out = $form->selectDate($value, $keyprefix.$key.$keysuffix, $showtime, $showtime, $required, '', 1, (($keyprefix != 'search_' && $keyprefix != 'search_options_') ? 1 : 0), 0, 1);
  926. }
  927. } elseif (in_array($type, array('datetime'))) {
  928. $tmp = explode(',', $size);
  929. $newsize = $tmp[0];
  930. $showtime = 1;
  931. // Do not show current date when field not required (see selectDate() method)
  932. if (!$required && $value == '') {
  933. $value = '-1';
  934. }
  935. if ($mode == 1) {
  936. // search filter on a date extrafield shows two inputs to select a date range
  937. $prefill = array(
  938. 'start' => isset($value['start']) ? $value['start'] : '',
  939. 'end' => isset($value['end']) ? $value['end'] : ''
  940. );
  941. $out = '<div ' . ($moreparam ? $moreparam : '') . '><div class="nowrap">';
  942. $out .= $form->selectDate($prefill['start'], $keyprefix.$key.$keysuffix.'_start', 1, 1, 1, '', 1, 0, 0, '', '', '', '', 1, '', $langs->trans("From"), 'tzuserrel');
  943. $out .= '</div><div class="nowrap">';
  944. $out .= $form->selectDate($prefill['end'], $keyprefix.$key.$keysuffix.'_end', 1, 1, 1, '', 1, 0, 0, '', '', '', '', 1, '', $langs->trans("to"), 'tzuserrel');
  945. $out .= '</div></div>';
  946. } else {
  947. // TODO Must also support $moreparam
  948. $out = $form->selectDate($value, $keyprefix.$key.$keysuffix, $showtime, $showtime, $required, '', 1, (($keyprefix != 'search_' && $keyprefix != 'search_options_') ? 1 : 0), 0, 1, '', '', '', 1, '', '', 'tzuserrel');
  949. }
  950. } elseif (in_array($type, array('int', 'integer'))) {
  951. $tmp = explode(',', $size);
  952. $newsize = $tmp[0];
  953. $out = '<input type="text" class="flat '.$morecss.' maxwidthonsmartphone" name="'.$keyprefix.$key.$keysuffix.'" id="'.$keyprefix.$key.$keysuffix.'" maxlength="'.$newsize.'" value="'.dol_escape_htmltag($value).'"'.($moreparam ? $moreparam : '').'>';
  954. } elseif (preg_match('/varchar/', $type)) {
  955. $out = '<input type="text" class="flat '.$morecss.' maxwidthonsmartphone" name="'.$keyprefix.$key.$keysuffix.'" id="'.$keyprefix.$key.$keysuffix.'" maxlength="'.$size.'" value="'.dol_escape_htmltag($value).'"'.($moreparam ? $moreparam : '').'>';
  956. } elseif (in_array($type, array('mail', 'phone', 'url'))) {
  957. $out = '<input type="text" class="flat '.$morecss.' maxwidthonsmartphone" name="'.$keyprefix.$key.$keysuffix.'" id="'.$keyprefix.$key.$keysuffix.'" value="'.dol_escape_htmltag($value).'" '.($moreparam ? $moreparam : '').'>';
  958. } elseif ($type == 'text') {
  959. if (!preg_match('/search_/', $keyprefix)) { // If keyprefix is search_ or search_options_, we must just use a simple text field
  960. require_once DOL_DOCUMENT_ROOT.'/core/class/doleditor.class.php';
  961. $doleditor = new DolEditor($keyprefix.$key.$keysuffix, $value, '', 200, 'dolibarr_notes', 'In', false, false, false, ROWS_5, '90%');
  962. $out = $doleditor->Create(1);
  963. } else {
  964. $out = '<input type="text" class="flat '.$morecss.' maxwidthonsmartphone" name="'.$keyprefix.$key.$keysuffix.'" id="'.$keyprefix.$key.$keysuffix.'" value="'.dol_escape_htmltag($value).'" '.($moreparam ? $moreparam : '').'>';
  965. }
  966. } elseif ($type == 'html') {
  967. if (!preg_match('/search_/', $keyprefix)) { // If keyprefix is search_ or search_options_, we must just use a simple text field
  968. require_once DOL_DOCUMENT_ROOT.'/core/class/doleditor.class.php';
  969. $doleditor = new DolEditor($keyprefix.$key.$keysuffix, $value, '', 200, 'dolibarr_notes', 'In', false, false, !empty($conf->fckeditor->enabled) && $conf->global->FCKEDITOR_ENABLE_SOCIETE, ROWS_5, '90%');
  970. $out = $doleditor->Create(1);
  971. } else {
  972. $out = '<input type="text" class="flat '.$morecss.' maxwidthonsmartphone" name="'.$keyprefix.$key.$keysuffix.'" id="'.$keyprefix.$key.$keysuffix.'" value="'.dol_escape_htmltag($value).'" '.($moreparam ? $moreparam : '').'>';
  973. }
  974. } elseif ($type == 'boolean') {
  975. if (empty($mode)) {
  976. $checked = '';
  977. if (!empty($value)) {
  978. $checked = ' checked value="1" ';
  979. } else {
  980. $checked = ' value="1" ';
  981. }
  982. $out = '<input type="checkbox" class="flat valignmiddle'.($morecss ? ' '.$morecss : '').' maxwidthonsmartphone" name="'.$keyprefix.$key.$keysuffix.'" id="'.$keyprefix.$key.$keysuffix.'" '.$checked.' '.($moreparam ? $moreparam : '').'>';
  983. } else {
  984. $out .= $form->selectyesno($keyprefix.$key.$keysuffix, $value, 1, false, 1);
  985. }
  986. } elseif ($type == 'price') {
  987. if (!empty($value)) { // $value in memory is a php numeric, we format it into user number format.
  988. $value = price($value);
  989. }
  990. $out = '<input type="text" class="flat '.$morecss.' maxwidthonsmartphone" name="'.$keyprefix.$key.$keysuffix.'" id="'.$keyprefix.$key.$keysuffix.'" value="'.$value.'" '.($moreparam ? $moreparam : '').'> '.$langs->getCurrencySymbol($conf->currency);
  991. } elseif ($type == 'double') {
  992. if (!empty($value)) { // $value in memory is a php numeric, we format it into user number format.
  993. $value = price($value);
  994. }
  995. $out = '<input type="text" class="flat '.$morecss.' maxwidthonsmartphone" name="'.$keyprefix.$key.$keysuffix.'" id="'.$keyprefix.$key.$keysuffix.'" value="'.$value.'" '.($moreparam ? $moreparam : '').'> ';
  996. } elseif ($type == 'select') {
  997. $out = '';
  998. if ($mode) {
  999. $options = array();
  1000. foreach ($param['options'] as $okey => $val) {
  1001. if ((string) $okey == '') {
  1002. continue;
  1003. }
  1004. if ($langfile && $val) {
  1005. $options[$okey] = $langs->trans($val);
  1006. } else {
  1007. $options[$okey] = $val;
  1008. }
  1009. }
  1010. $selected = array();
  1011. if (!is_array($value)) {
  1012. $selected = explode(',', $value);
  1013. }
  1014. $out .= $form->multiselectarray($keyprefix.$key.$keysuffix, $options, $selected, 0, 0, $morecss, 0, 0, '', '', '', !empty($conf->use_javascript_ajax) && empty($conf->global->MAIN_EXTRAFIELDS_DISABLE_SELECT2));
  1015. } else {
  1016. if (!empty($conf->use_javascript_ajax) && empty($conf->global->MAIN_EXTRAFIELDS_DISABLE_SELECT2)) {
  1017. include_once DOL_DOCUMENT_ROOT.'/core/lib/ajax.lib.php';
  1018. $out .= ajax_combobox($keyprefix.$key.$keysuffix, array(), 0);
  1019. }
  1020. $out .= '<select class="flat '.$morecss.' maxwidthonsmartphone" name="'.$keyprefix.$key.$keysuffix.'" id="'.$keyprefix.$key.$keysuffix.'" '.($moreparam ? $moreparam : '').'>';
  1021. $out .= '<option value="0">&nbsp;</option>';
  1022. foreach ($param['options'] as $key => $val) {
  1023. if ((string) $key == '') {
  1024. continue;
  1025. }
  1026. $valarray = explode('|', $val);
  1027. $val = $valarray[0];
  1028. $parent = '';
  1029. if (!empty($valarray[1])) {
  1030. $parent = $valarray[1];
  1031. }
  1032. $out .= '<option value="'.$key.'"';
  1033. $out .= (((string) $value == (string) $key) ? ' selected' : '');
  1034. $out .= (!empty($parent) ? ' parent="'.$parent.'"' : '');
  1035. $out .= '>';
  1036. if ($langfile && $val) {
  1037. $out .= $langs->trans($val);
  1038. } else {
  1039. $out .= $val;
  1040. }
  1041. $out .= '</option>';
  1042. }
  1043. $out .= '</select>';
  1044. }
  1045. } elseif ($type == 'sellist') {
  1046. $out = '';
  1047. if (!empty($conf->use_javascript_ajax) && empty($conf->global->MAIN_EXTRAFIELDS_DISABLE_SELECT2)) {
  1048. include_once DOL_DOCUMENT_ROOT.'/core/lib/ajax.lib.php';
  1049. $out .= ajax_combobox($keyprefix.$key.$keysuffix, array(), 0);
  1050. }
  1051. $out .= '<select class="flat '.$morecss.' maxwidthonsmartphone" name="'.$keyprefix.$key.$keysuffix.'" id="'.$keyprefix.$key.$keysuffix.'" '.($moreparam ? $moreparam : '').'>';
  1052. if (is_array($param['options'])) {
  1053. $param_list = array_keys($param['options']);
  1054. $InfoFieldList = explode(":", $param_list[0]);
  1055. $parentName = '';
  1056. $parentField = '';
  1057. // 0 : tableName
  1058. // 1 : label field name
  1059. // 2 : key fields name (if differ of rowid)
  1060. // 3 : key field parent (for dependent lists)
  1061. // 4 : where clause filter on column or table extrafield, syntax field='value' or extra.field=value
  1062. // 5 : id category type
  1063. // 6 : ids categories list separated by comma for category root
  1064. $keyList = (empty($InfoFieldList[2]) ? 'rowid' : $InfoFieldList[2].' as rowid');
  1065. if (count($InfoFieldList) > 4 && !empty($InfoFieldList[4])) {
  1066. if (strpos($InfoFieldList[4], 'extra.') !== false) {
  1067. $keyList = 'main.'.$InfoFieldList[2].' as rowid';
  1068. } else {
  1069. $keyList = $InfoFieldList[2].' as rowid';
  1070. }
  1071. }
  1072. if (count($InfoFieldList) > 3 && !empty($InfoFieldList[3])) {
  1073. list($parentName, $parentField) = explode('|', $InfoFieldList[3]);
  1074. $keyList .= ', '.$parentField;
  1075. }
  1076. $filter_categorie = false;
  1077. if (count($InfoFieldList) > 5) {
  1078. if ($InfoFieldList[0] == 'categorie') {
  1079. $filter_categorie = true;
  1080. }
  1081. }
  1082. if ($filter_categorie === false) {
  1083. $fields_label = explode('|', $InfoFieldList[1]);
  1084. if (is_array($fields_label)) {
  1085. $keyList .= ', ';
  1086. $keyList .= implode(', ', $fields_label);
  1087. }
  1088. $sqlwhere = '';
  1089. $sql = "SELECT ".$keyList;
  1090. $sql .= ' FROM '.$this->db->prefix().$InfoFieldList[0];
  1091. if (!empty($InfoFieldList[4])) {
  1092. // can use current entity filter
  1093. if (strpos($InfoFieldList[4], '$ENTITY$') !== false) {
  1094. $InfoFieldList[4] = str_replace('$ENTITY$', $conf->entity, $InfoFieldList[4]);
  1095. }
  1096. // can use SELECT request
  1097. if (strpos($InfoFieldList[4], '$SEL$') !== false) {
  1098. $InfoFieldList[4] = str_replace('$SEL$', 'SELECT', $InfoFieldList[4]);
  1099. }
  1100. // current object id can be use into filter
  1101. if (strpos($InfoFieldList[4], '$ID$') !== false && !empty($objectid)) {
  1102. $InfoFieldList[4] = str_replace('$ID$', $objectid, $InfoFieldList[4]);
  1103. } else {
  1104. $InfoFieldList[4] = str_replace('$ID$', '0', $InfoFieldList[4]);
  1105. }
  1106. //We have to join on extrafield table
  1107. if (strpos($InfoFieldList[4], 'extra') !== false) {
  1108. $sql .= ' as main, '.$this->db->prefix().$InfoFieldList[0].'_extrafields as extra';
  1109. $sqlwhere .= " WHERE extra.fk_object=main.".$InfoFieldList[2]." AND ".$InfoFieldList[4];
  1110. } else {
  1111. $sqlwhere .= " WHERE ".$InfoFieldList[4];
  1112. }
  1113. if($moreparam != ''){
  1114. $sqlwhere .= $moreparam;
  1115. }
  1116. } else {
  1117. $sqlwhere .= ' WHERE 1=1';
  1118. }
  1119. // Some tables may have field, some other not. For the moment we disable it.
  1120. if (in_array($InfoFieldList[0], array('tablewithentity'))) {
  1121. $sqlwhere .= ' AND entity = '.((int) $conf->entity);
  1122. }
  1123. $sql .= $sqlwhere;
  1124. $sql .= ' ORDER BY '.implode(', ', $fields_label);
  1125. dol_syslog(get_class($this).'::showInputField type=sellist', LOG_DEBUG);
  1126. $resql = $this->db->query($sql);
  1127. if ($resql) {
  1128. $out .= '<option value="0">&nbsp;</option>';
  1129. $num = $this->db->num_rows($resql);
  1130. $i = 0;
  1131. while ($i < $num) {
  1132. $labeltoshow = '';
  1133. $obj = $this->db->fetch_object($resql);
  1134. // Several field into label (eq table:code|libelle:rowid)
  1135. $notrans = false;
  1136. $fields_label = explode('|', $InfoFieldList[1]);
  1137. if (is_array($fields_label) && count($fields_label) > 1) {
  1138. $notrans = true;
  1139. foreach ($fields_label as $field_toshow) {
  1140. $labeltoshow .= $obj->$field_toshow.' ';
  1141. }
  1142. } else {
  1143. $labeltoshow = $obj->{$InfoFieldList[1]};
  1144. }
  1145. $labeltoshow = $labeltoshow;
  1146. if ($value == $obj->rowid) {
  1147. if (!$notrans) {
  1148. foreach ($fields_label as $field_toshow) {
  1149. $translabel = $langs->trans($obj->$field_toshow);
  1150. $labeltoshow = $translabel.' ';
  1151. }
  1152. }
  1153. $out .= '<option value="'.$obj->rowid.'" selected>'.$labeltoshow.'</option>';
  1154. } else {
  1155. if (!$notrans) {
  1156. $translabel = $langs->trans($obj->{$InfoFieldList[1]});
  1157. $labeltoshow = $translabel;
  1158. }
  1159. if (empty($labeltoshow)) {
  1160. $labeltoshow = '(not defined)';
  1161. }
  1162. if (!empty($InfoFieldList[3]) && $parentField) {
  1163. $parent = $parentName.':'.$obj->{$parentField};
  1164. }
  1165. $out .= '<option value="'.$obj->rowid.'"';
  1166. $out .= ($value == $obj->rowid ? ' selected' : '');
  1167. $out .= (!empty($parent) ? ' parent="'.$parent.'"' : '');
  1168. $out .= '>'.$labeltoshow.'</option>';
  1169. }
  1170. $i++;
  1171. }
  1172. $this->db->free($resql);
  1173. } else {
  1174. print 'Error in request '.$sql.' '.$this->db->lasterror().'. Check setup of extra parameters.<br>';
  1175. }
  1176. } else {
  1177. require_once DOL_DOCUMENT_ROOT.'/categories/class/categorie.class.php';
  1178. $data = $form->select_all_categories(Categorie::$MAP_ID_TO_CODE[$InfoFieldList[5]], '', 'parent', 64, $InfoFieldList[6], 1, 1);
  1179. $out .= '<option value="0">&nbsp;</option>';
  1180. if (is_array($data)) {
  1181. foreach ($data as $data_key => $data_value) {
  1182. $out .= '<option value="'.$data_key.'"';
  1183. $out .= ($value == $data_key ? ' selected' : '');
  1184. $out .= '>'.$data_value.'</option>';
  1185. }
  1186. }
  1187. }
  1188. }
  1189. $out .= '</select>';
  1190. } elseif ($type == 'checkbox') {
  1191. $value_arr = $value;
  1192. if (!is_array($value)) {
  1193. $value_arr = explode(',', $value);
  1194. }
  1195. $out = $form->multiselectarray($keyprefix.$key.$keysuffix, (empty($param['options']) ?null:$param['options']), $value_arr, '', 0, '', 0, '100%');
  1196. } elseif ($type == 'radio') {
  1197. $out = '';
  1198. foreach ($param['options'] as $keyopt => $val) {
  1199. $out .= '<input class="flat '.$morecss.'" type="radio" name="'.$keyprefix.$key.$keysuffix.'" id="'.$keyprefix.$key.$keysuffix.'" '.($moreparam ? $moreparam : '');
  1200. $out .= ' value="'.$keyopt.'"';
  1201. $out .= ' id="'.$keyprefix.$key.$keysuffix.'_'.$keyopt.'"';
  1202. $out .= ($value == $keyopt ? 'checked' : '');
  1203. $out .= '/><label for="'.$keyprefix.$key.$keysuffix.'_'.$keyopt.'">'.$langs->trans($val).'</label><br>';
  1204. }
  1205. } elseif ($type == 'chkbxlst') {
  1206. if (is_array($value)) {
  1207. $value_arr = $value;
  1208. } else {
  1209. $value_arr = explode(',', $value);
  1210. }
  1211. if (is_array($param['options'])) {
  1212. $param_list = array_keys($param['options']);
  1213. $InfoFieldList = explode(":", $param_list[0]);
  1214. $parentName = '';
  1215. $parentField = '';
  1216. // 0 : tableName
  1217. // 1 : label field name
  1218. // 2 : key fields name (if differ of rowid)
  1219. // 3 : key field parent (for dependent lists)
  1220. // 4 : where clause filter on column or table extrafield, syntax field='value' or extra.field=value
  1221. // 5 : id category type
  1222. // 6 : ids categories list separated by comma for category root
  1223. $keyList = (empty($InfoFieldList[2]) ? 'rowid' : $InfoFieldList[2].' as rowid');
  1224. if (count($InfoFieldList) > 3 && !empty($InfoFieldList[3])) {
  1225. list ($parentName, $parentField) = explode('|', $InfoFieldList[3]);
  1226. $keyList .= ', '.$parentField;
  1227. }
  1228. if (count($InfoFieldList) > 4 && !empty($InfoFieldList[4])) {
  1229. if (strpos($InfoFieldList[4], 'extra.') !== false) {
  1230. $keyList = 'main.'.$InfoFieldList[2].' as rowid';
  1231. } else {
  1232. $keyList = $InfoFieldList[2].' as rowid';
  1233. }
  1234. }
  1235. $filter_categorie = false;
  1236. if (count($InfoFieldList) > 5) {
  1237. if ($InfoFieldList[0] == 'categorie') {
  1238. $filter_categorie = true;
  1239. }
  1240. }
  1241. if ($filter_categorie === false) {
  1242. $fields_label = explode('|', $InfoFieldList[1]);
  1243. if (is_array($fields_label)) {
  1244. $keyList .= ', ';
  1245. $keyList .= implode(', ', $fields_label);
  1246. }
  1247. $sqlwhere = '';
  1248. $sql = "SELECT ".$keyList;
  1249. $sql .= ' FROM '.$this->db->prefix().$InfoFieldList[0];
  1250. if (!empty($InfoFieldList[4])) {
  1251. // can use current entity filter
  1252. if (strpos($InfoFieldList[4], '$ENTITY$') !== false) {
  1253. $InfoFieldList[4] = str_replace('$ENTITY$', $conf->entity, $InfoFieldList[4]);
  1254. }
  1255. // can use SELECT request
  1256. if (strpos($InfoFieldList[4], '$SEL$') !== false) {
  1257. $InfoFieldList[4] = str_replace('$SEL$', 'SELECT', $InfoFieldList[4]);
  1258. }
  1259. // current object id can be use into filter
  1260. if (strpos($InfoFieldList[4], '$ID$') !== false && !empty($objectid)) {
  1261. $InfoFieldList[4] = str_replace('$ID$', $objectid, $InfoFieldList[4]);
  1262. } elseif (preg_match("#^.*list.php$#", $_SERVER["PHP_SELF"])) {
  1263. // Pattern for word=$ID$
  1264. $word = '\b[a-zA-Z0-9-\.-_]+\b=\$ID\$';
  1265. // Removing space arount =, ( and )
  1266. $InfoFieldList[4] = preg_replace('# *(=|\(|\)) *#', '$1', $InfoFieldList[4]);
  1267. $nbPreg = 1;
  1268. // While we have parenthesis
  1269. while ($nbPreg != 0) {
  1270. // Init des compteurs
  1271. $nbPregRepl = $nbPregSel = 0;
  1272. // On retire toutes les parenthèses sans = avant
  1273. $InfoFieldList[4] = preg_replace('#([^=])(\([^)^(]*('.$word.')[^)^(]*\))#', '$1 $3 ', $InfoFieldList[4], -1, $nbPregRepl);
  1274. // On retire les espaces autour des = et parenthèses
  1275. $InfoFieldList[4] = preg_replace('# *(=|\(|\)) *#', '$1', $InfoFieldList[4]);
  1276. // On retire toutes les parenthèses avec = avant
  1277. $InfoFieldList[4] = preg_replace('#\b[a-zA-Z0-9-\.-_]+\b=\([^)^(]*('.$word.')[^)^(]*\)#', '$1 ', $InfoFieldList[4], -1, $nbPregSel);
  1278. // On retire les espaces autour des = et parenthèses
  1279. $InfoFieldList[4] = preg_replace('# *(=|\(|\)) *#', '$1', $InfoFieldList[4]);
  1280. // Calcul du compteur général pour la boucle
  1281. $nbPreg = $nbPregRepl + $nbPregSel;
  1282. }
  1283. // Si l'on a un AND ou un OR, avant ou après
  1284. preg_match('#(AND|OR|) *('.$word.') *(AND|OR|)#', $InfoFieldList[4], $matchCondition);
  1285. while (!empty($matchCondition[0])) {
  1286. // If the two sides differ but are not empty
  1287. if (!empty($matchCondition[1]) && !empty($matchCondition[3]) && $matchCondition[1] != $matchCondition[3]) {
  1288. // Nobody sain would do that without parentheses
  1289. $InfoFieldList[4] = str_replace('$ID$', '0', $InfoFieldList[4]);
  1290. } else {
  1291. if (!empty($matchCondition[1])) {
  1292. $boolCond = (($matchCondition[1] == "AND") ? ' AND TRUE ' : ' OR FALSE ');
  1293. $InfoFieldList[4] = str_replace($matchCondition[0], $boolCond.$matchCondition[3], $InfoFieldList[4]);
  1294. } elseif (!empty($matchCondition[3])) {
  1295. $boolCond = (($matchCondition[3] == "AND") ? ' TRUE AND ' : ' FALSE OR');
  1296. $InfoFieldList[4] = str_replace($matchCondition[0], $boolCond, $InfoFieldList[4]);
  1297. } else {
  1298. $InfoFieldList[4] = " TRUE ";
  1299. }
  1300. }
  1301. // Si l'on a un AND ou un OR, avant ou après
  1302. preg_match('#(AND|OR|) *('.$word.') *(AND|OR|)#', $InfoFieldList[4], $matchCondition);
  1303. }
  1304. } else {
  1305. $InfoFieldList[4] = str_replace('$ID$', '0', $InfoFieldList[4]);
  1306. }
  1307. // We have to join on extrafield table
  1308. if (strpos($InfoFieldList[4], 'extra.') !== false) {
  1309. $sql .= ' as main, '.$this->db->prefix().$InfoFieldList[0].'_extrafields as extra';
  1310. $sqlwhere .= " WHERE extra.fk_object=main.".$InfoFieldList[2]." AND ".$InfoFieldList[4];
  1311. } else {
  1312. $sqlwhere .= " WHERE ".$InfoFieldList[4];
  1313. }
  1314. } else {
  1315. $sqlwhere .= ' WHERE 1=1';
  1316. }
  1317. // Some tables may have field, some other not. For the moment we disable it.
  1318. if (in_array($InfoFieldList[0], array('tablewithentity'))) {
  1319. $sqlwhere .= " AND entity = ".((int) $conf->entity);
  1320. }
  1321. // $sql.=preg_replace('/^ AND /','',$sqlwhere);
  1322. // print $sql;
  1323. $sql .= $sqlwhere;
  1324. dol_syslog(get_class($this).'::showInputField type=chkbxlst', LOG_DEBUG);
  1325. $resql = $this->db->query($sql);
  1326. if ($resql) {
  1327. $num = $this->db->num_rows($resql);
  1328. $i = 0;
  1329. $data = array();
  1330. while ($i < $num) {
  1331. $labeltoshow = '';
  1332. $obj = $this->db->fetch_object($resql);
  1333. $notrans = false;
  1334. // Several field into label (eq table:code|libelle:rowid)
  1335. $fields_label = explode('|', $InfoFieldList[1]);
  1336. if (is_array($fields_label)) {
  1337. $notrans = true;
  1338. foreach ($fields_label as $field_toshow) {
  1339. $labeltoshow .= $obj->$field_toshow.' ';
  1340. }
  1341. } else {
  1342. $labeltoshow = $obj->{$InfoFieldList[1]};
  1343. }
  1344. $labeltoshow = dol_trunc($labeltoshow, 45);
  1345. if (is_array($value_arr) && in_array($obj->rowid, $value_arr)) {
  1346. $labeltoshow = '';
  1347. foreach ($fields_label as $field_toshow) {
  1348. $translabel = $langs->trans($obj->$field_toshow);
  1349. if ($translabel != $obj->$field_toshow) {
  1350. $labeltoshow .= ' '.dol_trunc($translabel, 18).' ';
  1351. } else {
  1352. $labeltoshow .= ' '.dol_trunc($obj->$field_toshow, 18).' ';
  1353. }
  1354. }
  1355. $data[$obj->rowid] = $labeltoshow;
  1356. } else {
  1357. if (!$notrans) {
  1358. $translabel = $langs->trans($obj->{$InfoFieldList[1]});
  1359. if ($translabel != $obj->{$InfoFieldList[1]}) {
  1360. $labeltoshow = dol_trunc($translabel, 18);
  1361. } else {
  1362. $labeltoshow = dol_trunc($obj->{$InfoFieldList[1]}, 18);
  1363. }
  1364. }
  1365. if (empty($labeltoshow)) {
  1366. $labeltoshow = '(not defined)';
  1367. }
  1368. if (is_array($value_arr) && in_array($obj->rowid, $value_arr)) {
  1369. $data[$obj->rowid] = $labeltoshow;
  1370. }
  1371. if (!empty($InfoFieldList[3]) && $parentField) {
  1372. $parent = $parentName.':'.$obj->{$parentField};
  1373. }
  1374. $data[$obj->rowid] = $labeltoshow;
  1375. }
  1376. $i++;
  1377. }
  1378. $this->db->free($resql);
  1379. $out = $form->multiselectarray($keyprefix.$key.$keysuffix, $data, $value_arr, '', 0, '', 0, '100%');
  1380. } else {
  1381. print 'Error in request '.$sql.' '.$this->db->lasterror().'. Check setup of extra parameters.<br>';
  1382. }
  1383. } else {
  1384. require_once DOL_DOCUMENT_ROOT.'/categories/class/categorie.class.php';
  1385. $data = $form->select_all_categories(Categorie::$MAP_ID_TO_CODE[$InfoFieldList[5]], '', 'parent', 64, $InfoFieldList[6], 1, 1);
  1386. $out = $form->multiselectarray($keyprefix.$key.$keysuffix, $data, $value_arr, '', 0, '', 0, '100%');
  1387. }
  1388. }
  1389. } elseif ($type == 'link') {
  1390. $param_list = array_keys($param['options']); // $param_list='ObjectName:classPath'
  1391. $showempty = (($required && $default != '') ? 0 : 1);
  1392. $out = $form->selectForForms($param_list[0], $keyprefix.$key.$keysuffix, $value, $showempty, '', '', $morecss);
  1393. } elseif ($type == 'password') {
  1394. // If prefix is 'search_', field is used as a filter, we use a common text field.
  1395. $out = '<input style="display:none" type="text" name="fakeusernameremembered">'; // Hidden field to reduce impact of evil Google Chrome autopopulate bug.
  1396. $out .= '<input autocomplete="new-password" type="'.($keyprefix == 'search_' ? 'text' : 'password').'" class="flat '.$morecss.'" name="'.$keyprefix.$key.$keysuffix.'" id="'.$keyprefix.$key.$keysuffix.'" value="'.$value.'" '.($moreparam ? $moreparam : '').'>';
  1397. }
  1398. if (!empty($hidden)) {
  1399. $out = '<input type="hidden" value="'.$value.'" name="'.$keyprefix.$key.$keysuffix.'" id="'.$keyprefix.$key.$keysuffix.'"/>';
  1400. }
  1401. /* Add comments
  1402. if ($type == 'date') $out.=' (YYYY-MM-DD)';
  1403. elseif ($type == 'datetime') $out.=' (YYYY-MM-DD HH:MM:SS)';
  1404. */
  1405. /*if (! empty($help) && $keyprefix != 'search_options_') {
  1406. $out .= $form->textwithpicto('', $help, 1, 'help', '', 0, 3);
  1407. }*/
  1408. return $out;
  1409. }
  1410. /**
  1411. * Return HTML string to put an output field into a page
  1412. *
  1413. * @param string $key Key of attribute
  1414. * @param string $value Value to show
  1415. * @param string $moreparam To add more parameters on html input tag (only checkbox use html input for output rendering)
  1416. * @param string $extrafieldsobjectkey Required (for example $object->table_element).
  1417. * @return string Formated value
  1418. */
  1419. public function showOutputField($key, $value, $moreparam = '', $extrafieldsobjectkey = '')
  1420. {
  1421. global $conf, $langs;
  1422. if (!empty($extrafieldsobjectkey)) {
  1423. $label = $this->attributes[$extrafieldsobjectkey]['label'][$key];
  1424. $type = $this->attributes[$extrafieldsobjectkey]['type'][$key];
  1425. $size = $this->attributes[$extrafieldsobjectkey]['size'][$key]; // Can be '255', '24,8'...
  1426. $default = $this->attributes[$extrafieldsobjectkey]['default'][$key];
  1427. $computed = $this->attributes[$extrafieldsobjectkey]['computed'][$key];
  1428. $unique = $this->attributes[$extrafieldsobjectkey]['unique'][$key];
  1429. $required = $this->attributes[$extrafieldsobjectkey]['required'][$key];
  1430. $param = $this->attributes[$extrafieldsobjectkey]['param'][$key];
  1431. $perms = dol_eval($this->attributes[$extrafieldsobjectkey]['perms'][$key], 1, 1, '1');
  1432. $langfile = $this->attributes[$extrafieldsobjectkey]['langfile'][$key];
  1433. $list = dol_eval($this->attributes[$extrafieldsobjectkey]['list'][$key], 1, 1, '1');
  1434. $help = $this->attributes[$extrafieldsobjectkey]['help'][$key];
  1435. $hidden = (empty($list) ? 1 : 0); // If $list empty, we are sure it is hidden, otherwise we show. If it depends on mode (view/create/edit form or list, this must be filtered by caller)
  1436. } else {
  1437. // Old usage not allowed anymore
  1438. dol_syslog(get_class($this).'::showOutputField extrafieldsobjectkey required', LOG_WARNING);
  1439. return '';
  1440. }
  1441. if ($hidden) {
  1442. return ''; // This is a protection. If field is hidden, we should just not call this method.
  1443. }
  1444. //if ($computed) $value = // $value is already calculated into $value before calling this method
  1445. $showsize = 0;
  1446. if ($type == 'date') {
  1447. $showsize = 10;
  1448. if ($value !== '') {
  1449. $value = dol_print_date($value, 'day'); // For date without hour, date is always GMT for storage and output
  1450. }
  1451. } elseif ($type == 'datetime') {
  1452. $showsize = 19;
  1453. if ($value !== '') {
  1454. $value = dol_print_date($value, 'dayhour', 'tzuserrel');
  1455. }
  1456. } elseif ($type == 'int') {
  1457. $showsize = 10;
  1458. } elseif ($type == 'double') {
  1459. if (!empty($value)) {
  1460. //$value=price($value);
  1461. $sizeparts = explode(",", $size);
  1462. $number_decimals = array_key_exists(1, $sizeparts) ? $sizeparts[1] : 0;
  1463. $value = price($value, 0, $langs, 0, 0, $number_decimals, '');
  1464. }
  1465. } elseif ($type == 'boolean') {
  1466. $checked = '';
  1467. if (!empty($value)) {
  1468. $checked = ' checked ';
  1469. }
  1470. $value = '<input type="checkbox" '.$checked.' '.($moreparam ? $moreparam : '').' readonly disabled>';
  1471. } elseif ($type == 'mail') {
  1472. $value = dol_print_email($value, 0, 0, 0, 64, 1, 1);
  1473. } elseif ($type == 'url') {
  1474. $value = dol_print_url($value, '_blank', 32, 1);
  1475. } elseif ($type == 'phone') {
  1476. $value = dol_print_phone($value, '', 0, 0, '', '&nbsp;', 'phone');
  1477. } elseif ($type == 'price') {
  1478. //$value = price($value, 0, $langs, 0, 0, -1, $conf->currency);
  1479. if ($value || $value == '0') {
  1480. $value = price($value, 0, $langs, 0, $conf->global->MAIN_MAX_DECIMALS_TOT, -1).' '.$langs->getCurrencySymbol($conf->currency);
  1481. }
  1482. } elseif ($type == 'select') {
  1483. $valstr = (!empty($param['options'][$value]) ? $param['options'][$value] : '');
  1484. if (($pos = strpos($valstr, "|")) !== false) {
  1485. $valstr = substr($valstr, 0, $pos);
  1486. }
  1487. if ($langfile && $valstr) {
  1488. $value = $langs->trans($valstr);
  1489. } else {
  1490. $value = $valstr;
  1491. }
  1492. } elseif ($type == 'sellist') {
  1493. $param_list = array_keys($param['options']);
  1494. $InfoFieldList = explode(":", $param_list[0]);
  1495. $selectkey = "rowid";
  1496. $keyList = 'rowid';
  1497. if (count($InfoFieldList) >= 3) {
  1498. $selectkey = $InfoFieldList[2];
  1499. $keyList = $InfoFieldList[2].' as rowid';
  1500. }
  1501. $fields_label = explode('|', $InfoFieldList[1]);
  1502. if (is_array($fields_label)) {
  1503. $keyList .= ', ';
  1504. $keyList .= implode(', ', $fields_label);
  1505. }
  1506. $filter_categorie = false;
  1507. if (count($InfoFieldList) > 5) {
  1508. if ($InfoFieldList[0] == 'categorie') {
  1509. $filter_categorie = true;
  1510. }
  1511. }
  1512. $sql = "SELECT ".$keyList;
  1513. $sql .= ' FROM '.$this->db->prefix().$InfoFieldList[0];
  1514. if (!empty($InfoFieldList[4]) && strpos($InfoFieldList[4], 'extra') !== false) {
  1515. $sql .= ' as main';
  1516. }
  1517. if ($selectkey == 'rowid' && empty($value)) {
  1518. $sql .= " WHERE ".$selectkey." = 0";
  1519. } elseif ($selectkey == 'rowid') {
  1520. $sql .= " WHERE ".$selectkey." = ".((int) $value);
  1521. } else {
  1522. $sql .= " WHERE ".$selectkey." = '".$this->db->escape($value)."'";
  1523. }
  1524. //$sql.= ' AND entity = '.$conf->entity;
  1525. dol_syslog(get_class($this).':showOutputField:$type=sellist', LOG_DEBUG);
  1526. $resql = $this->db->query($sql);
  1527. if ($resql) {
  1528. if ($filter_categorie === false) {
  1529. $value = ''; // value was used, so now we reste it to use it to build final output
  1530. $obj = $this->db->fetch_object($resql);
  1531. // Several field into label (eq table:code|libelle:rowid)
  1532. $fields_label = explode('|', $InfoFieldList[1]);
  1533. if (is_array($fields_label) && count($fields_label) > 1) {
  1534. foreach ($fields_label as $field_toshow) {
  1535. $translabel = '';
  1536. if (!empty($obj->$field_toshow)) {
  1537. $translabel = $langs->trans($obj->$field_toshow);
  1538. }
  1539. if ($translabel != $field_toshow) {
  1540. $value .= dol_trunc($translabel, 18).' ';
  1541. } else {
  1542. $value .= $obj->$field_toshow.' ';
  1543. }
  1544. }
  1545. } else {
  1546. $translabel = '';
  1547. $tmppropname = $InfoFieldList[1];
  1548. //$obj->$tmppropname = '';
  1549. if (!empty(isset($obj->$tmppropname) ? $obj->$tmppropname : '')) {
  1550. $translabel = $langs->trans($obj->$tmppropname);
  1551. }
  1552. if ($translabel != (isset($obj->$tmppropname) ? $obj->$tmppropname : '')) {
  1553. $value = dol_trunc($translabel, 18);
  1554. } else {
  1555. $value = isset($obj->$tmppropname) ? $obj->$tmppropname : '';
  1556. }
  1557. }
  1558. } else {
  1559. $toprint = array();
  1560. $obj = $this->db->fetch_object($resql);
  1561. if ($obj->rowid) {
  1562. require_once DOL_DOCUMENT_ROOT . '/categories/class/categorie.class.php';
  1563. $c = new Categorie($this->db);
  1564. $result = $c->fetch($obj->rowid);
  1565. if ($result > 0) {
  1566. $ways = $c->print_all_ways(); // $ways[0] = "ccc2 >> ccc2a >> ccc2a1" with html formatted text
  1567. foreach ($ways as $way) {
  1568. $toprint[] = '<li class="select2-search-choice-dolibarr noborderoncategories"' . ($c->color ? ' style="background: #' . $c->color . ';"' : ' style="background: #bbb"') . '>' . img_object('', 'category') . ' ' . $way . '</li>';
  1569. }
  1570. }
  1571. }
  1572. $value = '<div class="select2-container-multi-dolibarr" style="width: 90%;"><ul class="select2-choices-dolibarr">'.implode(' ', $toprint).'</ul></div>';
  1573. }
  1574. } else {
  1575. dol_syslog(get_class($this).'::showOutputField error '.$this->db->lasterror(), LOG_WARNING);
  1576. }
  1577. } elseif ($type == 'radio') {
  1578. if (!isset($param['options'][$value])) {
  1579. $langs->load('errors');
  1580. $value = $langs->trans('ErrorNoValueForRadioType');
  1581. } else {
  1582. $value = $langs->trans($param['options'][$value]);
  1583. }
  1584. } elseif ($type == 'checkbox') {
  1585. $value_arr = explode(',', $value);
  1586. $value = '';
  1587. $toprint = array();
  1588. if (is_array($value_arr)) {
  1589. foreach ($value_arr as $keyval => $valueval) {
  1590. if (!empty($valueval)) {
  1591. $toprint[] = '<li class="select2-search-choice-dolibarr noborderoncategories" style="background: #bbb">'.$param['options'][$valueval].'</li>';
  1592. }
  1593. }
  1594. }
  1595. $value = '<div class="select2-container-multi-dolibarr" style="width: 90%;"><ul class="select2-choices-dolibarr">'.implode(' ', $toprint).'</ul></div>';
  1596. } elseif ($type == 'chkbxlst') {
  1597. $value_arr = explode(',', $value);
  1598. $param_list = array_keys($param['options']);
  1599. $InfoFieldList = explode(":", $param_list[0]);
  1600. $selectkey = "rowid";
  1601. $keyList = 'rowid';
  1602. if (count($InfoFieldList) >= 3) {
  1603. $selectkey = $InfoFieldList[2];
  1604. $keyList = $InfoFieldList[2].' as rowid';
  1605. }
  1606. $fields_label = explode('|', $InfoFieldList[1]);
  1607. if (is_array($fields_label)) {
  1608. $keyList .= ', ';
  1609. $keyList .= implode(', ', $fields_label);
  1610. }
  1611. $filter_categorie = false;
  1612. if (count($InfoFieldList) > 5) {
  1613. if ($InfoFieldList[0] == 'categorie') {
  1614. $filter_categorie = true;
  1615. }
  1616. }
  1617. $sql = "SELECT ".$keyList;
  1618. $sql .= " FROM ".$this->db->prefix().$InfoFieldList[0];
  1619. if (strpos($InfoFieldList[4], 'extra') !== false) {
  1620. $sql .= ' as main';
  1621. }
  1622. // $sql.= " WHERE ".$selectkey."='".$this->db->escape($value)."'";
  1623. // $sql.= ' AND entity = '.$conf->entity;
  1624. dol_syslog(get_class($this).':showOutputField:$type=chkbxlst', LOG_DEBUG);
  1625. $resql = $this->db->query($sql);
  1626. if ($resql) {
  1627. if ($filter_categorie === false) {
  1628. $value = ''; // value was used, so now we reste it to use it to build final output
  1629. $toprint = array();
  1630. while ($obj = $this->db->fetch_object($resql)) {
  1631. // Several field into label (eq table:code|libelle:rowid)
  1632. $fields_label = explode('|', $InfoFieldList[1]);
  1633. if (is_array($value_arr) && in_array($obj->rowid, $value_arr)) {
  1634. if (is_array($fields_label) && count($fields_label) > 1) {
  1635. $label = '<li class="select2-search-choice-dolibarr noborderoncategories" style="background: #bbb">';
  1636. foreach ($fields_label as $field_toshow) {
  1637. $translabel = '';
  1638. if (!empty($obj->$field_toshow)) {
  1639. $translabel = $langs->trans($obj->$field_toshow);
  1640. }
  1641. if ($translabel != $field_toshow) {
  1642. $label .= ' '.dol_trunc($translabel, 18);
  1643. } else {
  1644. $label .= ' '.$obj->$field_toshow;
  1645. }
  1646. }
  1647. $label .= '</li>';
  1648. $toprint[] = $label;
  1649. } else {
  1650. $translabel = '';
  1651. if (!empty($obj->{$InfoFieldList[1]})) {
  1652. $translabel = $langs->trans($obj->{$InfoFieldList[1]});
  1653. }
  1654. if ($translabel != $obj->{$InfoFieldList[1]}) {
  1655. $toprint[] = '<li class="select2-search-choice-dolibarr noborderoncategories" style="background: #bbb">'.dol_trunc($translabel, 18).'</li>';
  1656. } else {
  1657. $toprint[] = '<li class="select2-search-choice-dolibarr noborderoncategories" style="background: #bbb">'.$obj->{$InfoFieldList[1]}.'</li>';
  1658. }
  1659. }
  1660. }
  1661. }
  1662. } else {
  1663. require_once DOL_DOCUMENT_ROOT.'/categories/class/categorie.class.php';
  1664. $toprint = array();
  1665. while ($obj = $this->db->fetch_object($resql)) {
  1666. if (is_array($value_arr) && in_array($obj->rowid, $value_arr)) {
  1667. $c = new Categorie($this->db);
  1668. $c->fetch($obj->rowid);
  1669. $ways = $c->print_all_ways(); // $ways[0] = "ccc2 >> ccc2a >> ccc2a1" with html formatted text
  1670. foreach ($ways as $way) {
  1671. $toprint[] = '<li class="select2-search-choice-dolibarr noborderoncategories"'.($c->color ? ' style="background: #'.$c->color.';"' : ' style="background: #bbb"').'>'.img_object('', 'category').' '.$way.'</li>';
  1672. }
  1673. }
  1674. }
  1675. }
  1676. if (!empty($toprint)) $value = '<div class="select2-container-multi-dolibarr" style="width: 90%;"><ul class="select2-choices-dolibarr">'.implode(' ', $toprint).'</ul></div>';
  1677. } else {
  1678. dol_syslog(get_class($this).'::showOutputField error '.$this->db->lasterror(), LOG_WARNING);
  1679. }
  1680. } elseif ($type == 'link') {
  1681. $out = '';
  1682. // Only if something to display (perf)
  1683. if ($value) { // If we have -1 here, pb is into insert, not into ouptut (fix insert instead of changing code here to compensate)
  1684. $param_list = array_keys($param['options']); // $param_list='ObjectName:classPath'
  1685. $InfoFieldList = explode(":", $param_list[0]);
  1686. $classname = $InfoFieldList[0];
  1687. $classpath = $InfoFieldList[1];
  1688. if (!empty($classpath)) {
  1689. dol_include_once($InfoFieldList[1]);
  1690. if ($classname && class_exists($classname)) {
  1691. $object = new $classname($this->db);
  1692. $object->fetch($value);
  1693. $value = $object->getNomUrl(3);
  1694. }
  1695. } else {
  1696. dol_syslog('Error bad setup of extrafield', LOG_WARNING);
  1697. return 'Error bad setup of extrafield';
  1698. }
  1699. }
  1700. } elseif ($type == 'text') {
  1701. $value = dol_htmlentitiesbr($value);
  1702. } elseif ($type == 'html') {
  1703. $value = dol_htmlentitiesbr($value);
  1704. } elseif ($type == 'password') {
  1705. $value = dol_trunc(preg_replace('/./i', '*', $value), 8, 'right', 'UTF-8', 1);
  1706. } else {
  1707. $showsize = round((float) $size);
  1708. if ($showsize > 48) {
  1709. $showsize = 48;
  1710. }
  1711. }
  1712. //print $type.'-'.$size;
  1713. $out = $value;
  1714. return $out;
  1715. }
  1716. /**
  1717. * Return the CSS to use for this extrafield into list
  1718. *
  1719. * @param string $key Key of attribute
  1720. * @param string $extrafieldsobjectkey If defined, use the new method to get extrafields data
  1721. * @return string Formated value
  1722. */
  1723. public function getAlignFlag($key, $extrafieldsobjectkey = '')
  1724. {
  1725. global $conf, $langs;
  1726. if (!empty($extrafieldsobjectkey)) {
  1727. $type = $this->attributes[$extrafieldsobjectkey]['type'][$key];
  1728. } else {
  1729. $type = $this->attribute_type[$key];
  1730. }
  1731. $cssstring = '';
  1732. if ($type == 'date') {
  1733. $cssstring = "center";
  1734. } elseif ($type == 'datetime') {
  1735. $cssstring = "center";
  1736. } elseif ($type == 'int') {
  1737. $cssstring = "right";
  1738. } elseif ($type == 'price') {
  1739. $cssstring = "right";
  1740. } elseif ($type == 'double') {
  1741. $cssstring = "right";
  1742. } elseif ($type == 'boolean') {
  1743. $cssstring = "center";
  1744. } elseif ($type == 'radio') {
  1745. $cssstring = "center";
  1746. } elseif ($type == 'checkbox') {
  1747. $cssstring = "center";
  1748. } elseif ($type == 'price') {
  1749. $cssstring = "right";
  1750. }
  1751. if (!empty($this->attributes[$extrafieldsobjectkey]['csslist'][$key])) {
  1752. $cssstring .= ($cssstring ? ' ' : '').$this->attributes[$extrafieldsobjectkey]['csslist'][$key];
  1753. }
  1754. return $cssstring;
  1755. }
  1756. /**
  1757. * Return HTML string to print separator extrafield
  1758. *
  1759. * @param string $key Key of attribute
  1760. * @param string $object Object
  1761. * @param int $colspan Value of colspan to use (it must includes the first column with title)
  1762. * @param string $display_type "card" for form display, "line" for document line display (extrafields on propal line, order line, etc...)
  1763. * @param string $mode Show output ('view') or input ('create' or 'edit') for extrafield
  1764. * @return string HTML code with line for separator
  1765. */
  1766. public function showSeparator($key, $object, $colspan = 2, $display_type = 'card', $mode = '')
  1767. {
  1768. global $conf, $langs;
  1769. $tagtype='tr';
  1770. $tagtype_dyn='td';
  1771. if ($display_type=='line') {
  1772. $tagtype='div';
  1773. $tagtype_dyn='span';
  1774. $colspan=0;
  1775. }
  1776. $extrafield_param = $this->attributes[$object->table_element]['param'][$key];
  1777. $extrafield_param_list = array();
  1778. if (!empty($extrafield_param) && is_array($extrafield_param)) {
  1779. $extrafield_param_list = array_keys($extrafield_param['options']);
  1780. }
  1781. $extrafield_collapse_display_value = -1;
  1782. $expand_display = false;
  1783. if (is_array($extrafield_param_list) && count($extrafield_param_list) > 0) {
  1784. $extrafield_collapse_display_value = intval($extrafield_param_list[0]);
  1785. $expand_display = ((isset($_COOKIE['DOLCOLLAPSE_'.$object->table_element.'_extrafields_'.$key]) || GETPOST('ignorecollapsesetup', 'int')) ? ($_COOKIE['DOLCOLLAPSE_'.$object->table_element.'_extrafields_'.$key] ? true : false) : ($extrafield_collapse_display_value == 2 ? false : true));
  1786. }
  1787. if ($mode == 'create') {
  1788. $extrafield_collapse_display_value = 0;
  1789. }
  1790. $out = '<'.$tagtype.' id="trextrafieldseparator'.$key.(!empty($object->id)?'_'.$object->id:'').'" class="trextrafieldseparator trextrafieldseparator'.$key.(!empty($object->id)?'_'.$object->id:'').'">';
  1791. $out .= '<'.$tagtype_dyn.' '.(!empty($colspan)?'colspan="' . $colspan . '"':'').'>';
  1792. // Some js code will be injected here to manage the collapsing of extrafields
  1793. // Output the picto
  1794. $out .= '<span class="cursorpointer '.($extrafield_collapse_display_value == 0 ? 'fas fa-square opacitymedium' : 'far fa-'.(($expand_display ? 'minus' : 'plus').'-square')).'"></span>';
  1795. $out .= '&nbsp;';
  1796. $out .= '<strong>';
  1797. $out .= $langs->trans($this->attributes[$object->table_element]['label'][$key]);
  1798. $out .= '</strong>';
  1799. $out .= '</'.$tagtype_dyn.'>';
  1800. $out .= '</'.$tagtype.'>';
  1801. $collapse_group = $key.(!empty($object->id) ? '_'.$object->id : '');
  1802. //$extrafields_collapse_num = $this->attributes[$object->table_element]['pos'][$key].(!empty($object->id)?'_'.$object->id:'');
  1803. if ($extrafield_collapse_display_value == 1 || $extrafield_collapse_display_value == 2) {
  1804. // Set the collapse_display status to cookie in priority or if ignorecollapsesetup is 1, if cookie and ignorecollapsesetup not defined, use the setup.
  1805. $this->expand_display[$collapse_group] = $expand_display;
  1806. if (!empty($conf->use_javascript_ajax) && $mode != 'create') {
  1807. $out .= '<!-- Add js script to manage the collapse/uncollapse of extrafields separators '.$key.' -->'."\n";
  1808. $out .= '<script type="text/javascript">'."\n";
  1809. $out .= 'jQuery(document).ready(function(){'."\n";
  1810. if ($expand_display === false) {
  1811. $out .= ' console.log("Inject js for the collapsing of extrafield '.$key.' - hide");'."\n";
  1812. $out .= ' jQuery(".trextrafields_collapse'.$collapse_group.'").hide();'."\n";
  1813. } else {
  1814. $out .= ' console.log("Inject js for collapsing of extrafield '.$key.' - keep visible and set cookie");'."\n";
  1815. $out .= ' document.cookie = "DOLCOLLAPSE_'.$object->table_element.'_extrafields_'.$key.'=1; path='.$_SERVER["PHP_SELF"].'"'."\n";
  1816. }
  1817. $out .= ' jQuery("#trextrafieldseparator'.$key.(!empty($object->id)?'_'.$object->id:'').'").click(function(){'."\n";
  1818. $out .= ' console.log("We click on collapse/uncollapse .trextrafields_collapse'.$collapse_group.'");'."\n";
  1819. $out .= ' jQuery(".trextrafields_collapse'.$collapse_group.'").toggle(100, function(){'."\n";
  1820. $out .= ' if (jQuery(".trextrafields_collapse'.$collapse_group.'").is(":hidden")) {'."\n";
  1821. $out .= ' jQuery("#trextrafieldseparator'.$key.(!empty($object->id)?'_'.$object->id:'').' '.$tagtype_dyn.' span").addClass("fa-plus-square").removeClass("fa-minus-square");'."\n";
  1822. $out .= ' document.cookie = "DOLCOLLAPSE_'.$object->table_element.'_extrafields_'.$key.'=0; path='.$_SERVER["PHP_SELF"].'"'."\n";
  1823. $out .= ' } else {'."\n";
  1824. $out .= ' jQuery("#trextrafieldseparator'.$key.(!empty($object->id)?'_'.$object->id:'').' '.$tagtype_dyn.' span").addClass("fa-minus-square").removeClass("fa-plus-square");'."\n";
  1825. $out .= ' document.cookie = "DOLCOLLAPSE_'.$object->table_element.'_extrafields_'.$key.'=1; path='.$_SERVER["PHP_SELF"].'"'."\n";
  1826. $out .= ' }'."\n";
  1827. $out .= ' });'."\n";
  1828. $out .= ' });'."\n";
  1829. $out .= '});'."\n";
  1830. $out .= '</script>'."\n";
  1831. }
  1832. } else {
  1833. $this->expand_display[$collapse_group] = 1;
  1834. }
  1835. return $out;
  1836. }
  1837. /**
  1838. * Fill array_options property of object by extrafields value (using for data sent by forms)
  1839. *
  1840. * @param array $extralabels Deprecated (old $array of extrafields, now set this to null)
  1841. * @param object $object Object
  1842. * @param string $onlykey Only some keys are filled:
  1843. * 'string' => When we make update of only one extrafield ($action = 'update_extras'), calling page can set this to avoid to have other extrafields being reset.
  1844. * '@GETPOSTISSET' => When we make update of several extrafields ($action = 'update'), calling page can set this to avoid to have fields not into POST being reset.
  1845. * @param int $todefaultifmissing 1=Set value to the default value in database if value is mandatory and missing
  1846. * @return int 1 if array_options set, 0 if no value, -1 if error (field required missing for example)
  1847. */
  1848. public function setOptionalsFromPost($extralabels, &$object, $onlykey = '', $todefaultifmissing = 0)
  1849. {
  1850. global $_POST, $langs;
  1851. $nofillrequired = 0; // For error when required field left blank
  1852. $error_field_required = array();
  1853. if (isset($this->attributes[$object->table_element]['label']) && is_array($this->attributes[$object->table_element]['label'])) {
  1854. $extralabels = $this->attributes[$object->table_element]['label'];
  1855. }
  1856. if (is_array($extralabels)) {
  1857. // Get extra fields
  1858. foreach ($extralabels as $key => $value) {
  1859. if (!empty($onlykey) && $onlykey != '@GETPOSTISSET' && $key != $onlykey) {
  1860. continue;
  1861. }
  1862. if (!empty($onlykey) && $onlykey == '@GETPOSTISSET' && !GETPOSTISSET('options_'.$key) && (! in_array($this->attributes[$object->table_element]['type'][$key], array('boolean', 'chkbxlst')))) {
  1863. //when unticking boolean field, it's not set in POST
  1864. continue;
  1865. }
  1866. $key_type = $this->attributes[$object->table_element]['type'][$key];
  1867. if ($key_type == 'separate') {
  1868. continue;
  1869. }
  1870. $enabled = 1;
  1871. if (isset($this->attributes[$object->table_element]['enabled'][$key])) { // 'enabled' is often a condition on module enabled or not
  1872. $enabled = dol_eval($this->attributes[$object->table_element]['enabled'][$key], 1, 1, '1');
  1873. }
  1874. $visibility = 1;
  1875. if (isset($this->attributes[$object->table_element]['list'][$key])) { // 'list' is option for visibility
  1876. $visibility = intval(dol_eval($this->attributes[$object->table_element]['list'][$key], 1, 1, '1'));
  1877. }
  1878. $perms = 1;
  1879. if (isset($this->attributes[$object->table_element]['perms'][$key])) {
  1880. $perms = dol_eval($this->attributes[$object->table_element]['perms'][$key], 1, 1, '1');
  1881. }
  1882. if (empty($enabled)
  1883. || (
  1884. $onlykey === '@GETPOSTISSET'
  1885. && in_array($this->attributes[$object->table_element]['type'][$key], array('boolean', 'chkbxlst'))
  1886. && in_array(abs($enabled), array(2, 5))
  1887. && ! GETPOSTISSET('options_' . $key) // Update hidden checkboxes and multiselect only if they are provided
  1888. )
  1889. ) {
  1890. continue;
  1891. }
  1892. if (empty($visibility)) {
  1893. continue;
  1894. }
  1895. if (empty($perms)) {
  1896. continue;
  1897. }
  1898. if ($this->attributes[$object->table_element]['required'][$key]) { // Value is required
  1899. // Check if functionally empty without using GETPOST (depending on the type of extrafield, a
  1900. // technically non-empty value may be treated as empty functionally).
  1901. // value can be alpha, int, array, etc...
  1902. if ((!is_array($_POST["options_".$key]) && empty($_POST["options_".$key]) && $this->attributes[$object->table_element]['type'][$key] != 'select' && $_POST["options_".$key] != '0')
  1903. || (!is_array($_POST["options_".$key]) && empty($_POST["options_".$key]) && $this->attributes[$object->table_element]['type'][$key] == 'select')
  1904. || (!is_array($_POST["options_".$key]) && isset($_POST["options_".$key]) && $this->attributes[$object->table_element]['type'][$key] == 'sellist' && $_POST['options_'.$key] == '0')
  1905. || (is_array($_POST["options_".$key]) && empty($_POST["options_".$key]))) {
  1906. //print 'ccc'.$value.'-'.$this->attributes[$object->table_element]['required'][$key];
  1907. // Field is not defined. We mark this as a problem. We may fix it later if there is a default value and $todefaultifmissing is set.
  1908. $nofillrequired++;
  1909. $error_field_required[$key] = $langs->transnoentitiesnoconv($value);
  1910. }
  1911. }
  1912. if (in_array($key_type, array('date'))) {
  1913. // Clean parameters
  1914. $value_key = dol_mktime(12, 0, 0, GETPOST("options_".$key."month", 'int'), GETPOST("options_".$key."day", 'int'), GETPOST("options_".$key."year", 'int'));
  1915. } elseif (in_array($key_type, array('datetime'))) {
  1916. // Clean parameters
  1917. $value_key = dol_mktime(GETPOST("options_".$key."hour", 'int'), GETPOST("options_".$key."min", 'int'), GETPOST("options_".$key."sec", 'int'), GETPOST("options_".$key."month", 'int'), GETPOST("options_".$key."day", 'int'), GETPOST("options_".$key."year", 'int'), 'tzuserrel');
  1918. } elseif (in_array($key_type, array('checkbox', 'chkbxlst'))) {
  1919. $value_arr = GETPOST("options_".$key, 'array'); // check if an array
  1920. if (!empty($value_arr)) {
  1921. $value_key = implode(',', $value_arr);
  1922. } else {
  1923. $value_key = '';
  1924. }
  1925. } elseif (in_array($key_type, array('price', 'double'))) {
  1926. $value_arr = GETPOST("options_".$key, 'alpha');
  1927. $value_key = price2num($value_arr);
  1928. } elseif (in_array($key_type, array('html'))) {
  1929. $value_key = GETPOST("options_".$key, 'restricthtml');
  1930. } elseif (in_array($key_type, array('text'))) {
  1931. $value_key = GETPOST("options_".$key, 'alphanohtml');
  1932. } else {
  1933. $value_key = GETPOST("options_".$key);
  1934. if (in_array($key_type, array('link')) && $value_key == '-1') {
  1935. $value_key = '';
  1936. }
  1937. }
  1938. if (!empty($error_field_required[$key]) && $todefaultifmissing) {
  1939. // Value is required but we have a default value and we asked to set empty value to the default value
  1940. if (!empty($this->attributes[$object->table_element]['default']) && !is_null($this->attributes[$object->table_element]['default'][$key])) {
  1941. $value_key = $this->attributes[$object->table_element]['default'][$key];
  1942. unset($error_field_required[$key]);
  1943. $nofillrequired--;
  1944. }
  1945. }
  1946. $object->array_options["options_".$key] = $value_key;
  1947. }
  1948. if ($nofillrequired) {
  1949. $langs->load('errors');
  1950. $this->error = $langs->trans('ErrorFieldsRequired').' : '.implode(', ', $error_field_required);
  1951. setEventMessages($this->error, null, 'errors');
  1952. return -1;
  1953. } else {
  1954. return 1;
  1955. }
  1956. } else {
  1957. return 0;
  1958. }
  1959. }
  1960. /**
  1961. * return array_options array of data of extrafields value of object sent by a search form
  1962. *
  1963. * @param array|string $extrafieldsobjectkey array of extrafields (old usage) or value of object->table_element (new usage)
  1964. * @param string $keyprefix Prefix string to add into name and id of field (can be used to avoid duplicate names)
  1965. * @param string $keysuffix Suffix string to add into name and id of field (can be used to avoid duplicate names)
  1966. * @return array|int array_options set or 0 if no value
  1967. */
  1968. public function getOptionalsFromPost($extrafieldsobjectkey, $keyprefix = '', $keysuffix = '')
  1969. {
  1970. global $_POST;
  1971. if (is_string($extrafieldsobjectkey) && !empty($this->attributes[$extrafieldsobjectkey]['label']) && is_array($this->attributes[$extrafieldsobjectkey]['label'])) {
  1972. $extralabels = $this->attributes[$extrafieldsobjectkey]['label'];
  1973. } else {
  1974. $extralabels = $extrafieldsobjectkey;
  1975. }
  1976. if (is_array($extralabels)) {
  1977. $array_options = array();
  1978. // Get extra fields
  1979. foreach ($extralabels as $key => $value) {
  1980. $key_type = '';
  1981. if (is_string($extrafieldsobjectkey)) {
  1982. $key_type = $this->attributes[$extrafieldsobjectkey]['type'][$key];
  1983. }
  1984. if (in_array($key_type, array('date'))) {
  1985. $dateparamname_start = $keysuffix . 'options_' . $key . $keyprefix . '_start';
  1986. $dateparamname_end = $keysuffix . 'options_' . $key . $keyprefix . '_end';
  1987. if (GETPOSTISSET($dateparamname_start . 'year') && GETPOSTISSET($dateparamname_end . 'year')) {
  1988. // values provided as a date pair (start date + end date), each date being broken down as year, month, day, etc.
  1989. $value_key = array(
  1990. 'start' => dol_mktime(0, 0, 0, GETPOST($dateparamname_start . 'month', 'int'), GETPOST($dateparamname_start . 'day', 'int'), GETPOST($dateparamname_start . 'year', 'int')),
  1991. 'end' => dol_mktime(23, 59, 59, GETPOST($dateparamname_end . 'month', 'int'), GETPOST($dateparamname_end . 'day', 'int'), GETPOST($dateparamname_end . 'year', 'int'))
  1992. );
  1993. } elseif (GETPOSTISSET($keysuffix."options_".$key.$keyprefix."year")) {
  1994. // Clean parameters
  1995. $value_key = dol_mktime(12, 0, 0, GETPOST($keysuffix."options_".$key.$keyprefix."month", 'int'), GETPOST($keysuffix."options_".$key.$keyprefix."day", 'int'), GETPOST($keysuffix."options_".$key.$keyprefix."year", 'int'));
  1996. } else {
  1997. continue; // Value was not provided, we should not set it.
  1998. }
  1999. } elseif (in_array($key_type, array('datetime'))) {
  2000. $dateparamname_start = $keysuffix . 'options_' . $key . $keyprefix . '_start';
  2001. $dateparamname_end = $keysuffix . 'options_' . $key . $keyprefix . '_end';
  2002. if (GETPOSTISSET($dateparamname_start . 'year') && GETPOSTISSET($dateparamname_end . 'year')) {
  2003. // values provided as a date pair (start date + end date), each date being broken down as year, month, day, etc.
  2004. $dateparamname_end_hour = GETPOST($dateparamname_end . 'hour', 'int') !='-1' ? GETPOST($dateparamname_end . 'hour', 'int') : '23';
  2005. $dateparamname_end_min = GETPOST($dateparamname_end . 'min', 'int') !='-1' ? GETPOST($dateparamname_end . 'min', 'int') : '59';
  2006. $dateparamname_end_sec = GETPOST($dateparamname_end . 'sec', 'int') !='-1' ? GETPOST($dateparamname_end . 'sec', 'int') : '59';
  2007. $value_key = array(
  2008. 'start' => dol_mktime(GETPOST($dateparamname_start . 'hour', 'int'), GETPOST($dateparamname_start . 'min', 'int'), GETPOST($dateparamname_start . 'sec', 'int'), GETPOST($dateparamname_start . 'month', 'int'), GETPOST($dateparamname_start . 'day', 'int'), GETPOST($dateparamname_start . 'year', 'int'), 'tzuserrel'),
  2009. 'end' => dol_mktime($dateparamname_end_hour, $dateparamname_end_min, $dateparamname_end_sec, GETPOST($dateparamname_end . 'month', 'int'), GETPOST($dateparamname_end . 'day', 'int'), GETPOST($dateparamname_end . 'year', 'int'), 'tzuserrel')
  2010. );
  2011. } elseif (GETPOSTISSET($keysuffix."options_".$key.$keyprefix."year")) {
  2012. // Clean parameters
  2013. $value_key = dol_mktime(GETPOST($keysuffix."options_".$key.$keyprefix."hour", 'int'), GETPOST($keysuffix."options_".$key.$keyprefix."min", 'int'), GETPOST($keysuffix."options_".$key.$keyprefix."sec", 'int'), GETPOST($keysuffix."options_".$key.$keyprefix."month", 'int'), GETPOST($keysuffix."options_".$key.$keyprefix."day", 'int'), GETPOST($keysuffix."options_".$key.$keyprefix."year", 'int'), 'tzuserrel');
  2014. } else {
  2015. continue; // Value was not provided, we should not set it.
  2016. }
  2017. } elseif ($key_type == 'select') {
  2018. // to detect if we are in search context
  2019. if (GETPOSTISARRAY($keysuffix."options_".$key.$keyprefix)) {
  2020. $value_arr = GETPOST($keysuffix."options_".$key.$keyprefix, 'array:aZ09');
  2021. // Make sure we get an array even if there's only one selected
  2022. $value_arr = (array) $value_arr;
  2023. $value_key = implode(',', $value_arr);
  2024. } else {
  2025. $value_key = GETPOST($keysuffix."options_".$key.$keyprefix);
  2026. }
  2027. } elseif (in_array($key_type, array('checkbox', 'chkbxlst'))) {
  2028. if (!GETPOSTISSET($keysuffix."options_".$key.$keyprefix)) {
  2029. continue; // Value was not provided, we should not set it.
  2030. }
  2031. $value_arr = GETPOST($keysuffix."options_".$key.$keyprefix);
  2032. // Make sure we get an array even if there's only one checkbox
  2033. $value_arr = (array) $value_arr;
  2034. $value_key = implode(',', $value_arr);
  2035. } elseif (in_array($key_type, array('price', 'double', 'int'))) {
  2036. if (!GETPOSTISSET($keysuffix."options_".$key.$keyprefix)) {
  2037. continue; // Value was not provided, we should not set it.
  2038. }
  2039. $value_arr = GETPOST($keysuffix."options_".$key.$keyprefix);
  2040. if ($keysuffix != 'search_') { // If value is for a search, we must keep complex string like '>100 <=150'
  2041. $value_key = price2num($value_arr);
  2042. } else {
  2043. $value_key = $value_arr;
  2044. }
  2045. } elseif (in_array($key_type, array('boolean'))) {
  2046. if (!GETPOSTISSET($keysuffix."options_".$key.$keyprefix)) {
  2047. $value_key = '';
  2048. } else {
  2049. $value_arr = GETPOST($keysuffix."options_".$key.$keyprefix);
  2050. $value_key = $value_arr;
  2051. }
  2052. } else {
  2053. if (!GETPOSTISSET($keysuffix."options_".$key.$keyprefix)) {
  2054. continue; // Value was not provided, we should not set it.
  2055. }
  2056. $value_key = GETPOST($keysuffix."options_".$key.$keyprefix);
  2057. }
  2058. $array_options[$keysuffix."options_".$key] = $value_key; // No keyprefix here. keyprefix is used only for read.
  2059. }
  2060. return $array_options;
  2061. }
  2062. return 0;
  2063. }
  2064. }