dolibarr 24.0.0-beta
modulebuilder.lib.php
Go to the documentation of this file.
1<?php
2/* Copyright (C) 2009-2010 Laurent Destailleur <eldy@users.sourceforge.net>
3 * Copyright (C) 2024-2025 MDW <mdeweerd@users.noreply.github.com>
4 * Copyright (C) 2024 Frédéric France <frederic.france@free.fr>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 3 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <https://www.gnu.org/licenses/>.
18 * or see https://www.gnu.org/
19 */
20
26require_once DOL_DOCUMENT_ROOT . '/modulebuilder/class/NamingContract.class.php';
27
41function rebuildObjectClass($destdir, $module, $objectname, $newmask, $readdir = '', $addfieldentry = array(), $delfieldentry = '')
42{
43 global $db, $langs;
44
45 if (empty($objectname)) {
46 return -6;
47 }
48 if (empty($readdir)) {
49 $readdir = $destdir;
50 }
51
52 if (!empty($addfieldentry['arrayofkeyval']) && !is_array($addfieldentry['arrayofkeyval'])) {
53 dol_print_error(null, 'Bad parameter addfieldentry with a property arrayofkeyval defined but that is not an array.');
54 return -7;
55 }
56
57 $error = 0;
58
59 // Check parameters into $addfieldentry (this provided array is filled by modulebuilder/index.php)
60 if (is_array($addfieldentry) && count($addfieldentry) > 0) {
61 if (empty($addfieldentry['name'])) {
62 setEventMessages($langs->trans('ErrorFieldRequired', $langs->transnoentitiesnoconv("Name")), null, 'errors');
63 return -2;
64 }
65 if (empty($addfieldentry['label'])) {
66 setEventMessages($langs->trans('ErrorFieldRequired', $langs->transnoentitiesnoconv("Label")), null, 'errors');
67 return -2;
68 }
69 if (!preg_match('/^(integer|price|sellist|varchar|double|text|html|duration|stars)/', $addfieldentry['type'])
70 && !preg_match('/^(boolean|smallint|real|date|datetime|timestamp|phone|email|url|ip|password)$/', $addfieldentry['type'])) { // Use email for email, mail is kept for compatibility
71 setEventMessages($langs->trans('BadValueForType', $addfieldentry['type']), null, 'errors');
72 return -2;
73 }
74 // Check for type stars(NumberOfStars), NumberOfStars must be an integer between 1 and 10
75 $matches = array();
76 if (preg_match('/^stars\‍((.+)\‍)$/', $addfieldentry['type'], $matches)) {
77 if (!ctype_digit($matches[1]) || $matches[1] < 1 || $matches[1] > 10) {
78 setEventMessages($langs->trans('BadValueForType', $addfieldentry['type']), null, 'errors');
79 return -2;
80 }
81 }
82 }
83
84 $pathoffiletoeditsrc = $readdir.'/class/'.strtolower($objectname).'.class.php';
85 $pathoffiletoedittarget = $destdir.'/class/'.strtolower($objectname).'.class.php'.($readdir != $destdir ? '.new' : '');
86 if (!dol_is_file($pathoffiletoeditsrc)) {
87 $langs->load("errors");
88 setEventMessages($langs->trans("ErrorFileNotFound", $pathoffiletoeditsrc), null, 'errors');
89 return -3;
90 }
91
92 //$pathoffiletoedittmp = $destdir.'/class/'.strtolower($objectname).'.class.php.tmp';
93 //dol_delete_file($pathoffiletoedittmp, 0, 1, 1);
94
95 try {
96 include_once $pathoffiletoeditsrc;
97 if (class_exists($objectname)) {
98 $object = new $objectname($db);
99 } else {
100 return -4;
101 }
102 '@phan-var-force CommonObject $object';
103
104 // Backup old file
105 dol_copy($pathoffiletoedittarget, $pathoffiletoedittarget.'.back', $newmask, 1);
106
107 // Edit class files
108 $contentclass = file_get_contents(dol_osencode($pathoffiletoeditsrc));
109
110 // Update ->fields (to add or remove entries defined into $addfieldentry)
111 if (count($object->fields)) {
112 if (is_array($addfieldentry) && count($addfieldentry)) {
113 $name = $addfieldentry['name'];
114 unset($addfieldentry['name']);
115
116 $object->fields[$name] = $addfieldentry;
117 }
118 if (!empty($delfieldentry)) {
119 $name = $delfieldentry;
120 unset($object->fields[$name]);
121 }
122 }
123
124 dol_sort_array($object->fields, 'position');
125
126 $i = 0;
127 $texttoinsert = '// BEGIN MODULEBUILDER PROPERTIES'."\n";
128 $texttoinsert .= "\t".'
131'."\n";
132 $texttoinsert .= "\t".'public $fields = array('."\n";
133
134 if (count($object->fields)) {
135 foreach ($object->fields as $key => $val) {
136 $i++;
137 $texttoinsert .= "\t\t".'"'.$key.'" => array(';
138 $texttoinsert .= '"type" => "'.dol_escape_php($val['type']).'",';
139 $texttoinsert .= ' "label" => "'.dol_escape_php($val['label']).'",';
140 if (!empty($val['picto'])) {
141 $texttoinsert .= ' "picto" => "'.dol_escape_php($val['picto']).'",';
142 }
143 $texttoinsert .= ' "enabled" => "'.($val['enabled'] !== '' ? dol_escape_php($val['enabled']) : 1).'",';
144 $texttoinsert .= " 'position' => ".($val['position'] !== '' ? (int) $val['position'] : 50).",";
145 $texttoinsert .= " 'notnull' => ".(empty($val['notnull']) ? 0 : (int) $val['notnull']).",";
146 $texttoinsert .= ' "visible" => "'.($val['visible'] !== '' ? dol_escape_js($val['visible']) : -1).'",';
147 if (!empty($val['noteditable'])) {
148 $texttoinsert .= ' "noteditable" => "'.dol_escape_php((string) $val['noteditable']).'",';
149 }
150 if (!empty($val['alwayseditable'])) {
151 $texttoinsert .= ' "alwayseditable" => "'.dol_escape_php((string) $val['alwayseditable']).'",';
152 }
153 if (array_key_exists('default', $val) && (!empty($val['default']) || $val['default'] === '0')) {
154 $texttoinsert .= ' "default" => "'.dol_escape_php($val['default']).'",';
155 }
156 if (!empty($val['index'])) {
157 $texttoinsert .= ' "index" => "'.(int) $val['index'].'",';
158 }
159 if (!empty($val['foreignkey'])) {
160 $texttoinsert .= ' "foreignkey" => "'.(int) $val['foreignkey'].'",';
161 }
162 if (!empty($val['searchall'])) {
163 $texttoinsert .= ' "searchall" => "'.(int) $val['searchall'].'",';
164 }
165 if (!empty($val['isameasure'])) {
166 $texttoinsert .= ' "isameasure" => "'.(int) $val['isameasure'].'",';
167 }
168 if (!empty($val['css'])) {
169 $texttoinsert .= ' "css" => "'.dol_escape_php($val['css']).'",';
170 }
171 if (!empty($val['cssview'])) {
172 $texttoinsert .= ' "cssview" => "'.dol_escape_php($val['cssview']).'",';
173 }
174 if (!empty($val['csslist'])) {
175 $texttoinsert .= ' "csslist" => "'.dol_escape_php($val['csslist']).'",';
176 }
177 if (!empty($val['help'])) {
178 $texttoinsert .= ' "help" => "'.dol_escape_php($val['help']).'",';
179 }
180 if (!empty($val['showoncombobox'])) {
181 $texttoinsert .= ' "showoncombobox" => "'.(int) $val['showoncombobox'].'",';
182 }
183 if (!empty($val['disabled'])) {
184 $texttoinsert .= ' "disabled" => "'.(int) $val['disabled'].'",';
185 }
186 if (!empty($val['autofocusoncreate'])) {
187 $texttoinsert .= ' "autofocusoncreate" => "'.(int) $val['autofocusoncreate'].'",';
188 }
189 if (!empty($val['arrayofkeyval'])) {
190 $texttoinsert .= ' "arrayofkeyval" => array(';
191 $i = 0;
192 foreach ($val['arrayofkeyval'] as $key2 => $val2) {
193 if ($i) {
194 $texttoinsert .= ", ";
195 }
196 $texttoinsert .= '"'.dol_escape_php($key2).'" => "'.dol_escape_php($val2).'"';
197 $i++;
198 }
199 $texttoinsert .= '),';
200 }
201 if (!empty($val['validate'])) {
202 $texttoinsert .= ' "validate" => "'.(int) $val['validate'].'",';
203 }
204 if (!empty($val['comment'])) {
205 $texttoinsert .= ' "comment" => "'.dol_escape_php($val['comment']).'"';
206 }
207
208 $texttoinsert .= "),\n";
209 //print $texttoinsert;
210 }
211 }
212
213 $texttoinsert .= "\t".');'."\n";
214 //print ($texttoinsert);exit;
215
216 if (count($object->fields)) {
217 //$typetotypephp = array('integer' => 'integer', 'duration' => 'integer', 'varchar' => 'string');
218
219 foreach ($object->fields as $key => $val) {
220 $i++;
221 //$typephp = $typetotypephp[$val['type']];
222 $texttoinsert .= "\t".'public $'.$key.";";
223 //if ($key == 'rowid') $texttoinsert.= ' AUTO_INCREMENT PRIMARY KEY';
224 //if ($key == 'entity') $texttoinsert.= ' DEFAULT 1';
225 //$texttoinsert.= ($val['notnull']?' NOT NULL':'');
226 //if ($i < count($object->fields)) $texttoinsert. = ";";
227 $texttoinsert .= "\n";
228 }
229 }
230
231 $texttoinsert .= "\t".'// END MODULEBUILDER PROPERTIES';
232
233 //print($texttoinsert);
234
235 $contentclass = preg_replace('/\/\/ BEGIN MODULEBUILDER PROPERTIES.*END MODULEBUILDER PROPERTIES/ims', $texttoinsert, $contentclass);
236 //print $contentclass;
237
238 dol_mkdir(dirname($pathoffiletoedittarget));
239
240 //file_put_contents($pathoffiletoedittmp, $contentclass);
241 $result = file_put_contents(dol_osencode($pathoffiletoedittarget), $contentclass);
242
243 if ($result) {
244 dolChmod($pathoffiletoedittarget, $newmask);
245 } else {
246 $error++;
247 }
248
249 return $error ? -1 : $object;
250 } catch (Exception $e) {
251 print $e->getMessage();
252 return -5;
253 }
254}
255
269function rebuildObjectSql($destdir, $module, $objectname, $newmask, $readdir = '', $object = null, $moduletype = 'external')
270{
271 global $db, $langs;
272
273 $error = 0;
274
275 if (empty($objectname)) {
276 return -1;
277 }
278 if (empty($readdir)) {
279 $readdir = $destdir;
280 }
281
282 $pathoffiletoclasssrc = $readdir.'/class/'.strtolower($objectname).'.class.php';
283
284 // Edit .sql file
285 if ($moduletype == 'internal') {
286 $pathoffiletoeditsrc = '/../install/mysql/tables/llx_'.strtolower($module).'_'.strtolower($objectname).'.sql';
287 if (! dol_is_file($readdir.$pathoffiletoeditsrc)) {
288 $pathoffiletoeditsrc = '/../install/mysql/tables/llx_'.strtolower($module).'_'.strtolower($objectname).'-'.strtolower($module).'.sql';
289 if (! dol_is_file($readdir.$pathoffiletoeditsrc)) {
290 $pathoffiletoeditsrc = '/../install/mysql/tables/llx_'.strtolower($module).'-'.strtolower($module).'.sql';
291 if (! dol_is_file($readdir.$pathoffiletoeditsrc)) {
292 $pathoffiletoeditsrc = '/../install/mysql/tables/llx_'.strtolower($module).'.sql';
293 }
294 }
295 }
296 } else {
297 $pathoffiletoeditsrc = '/sql/llx_'.strtolower($module).'_'.strtolower($objectname).'.sql';
298 if (! dol_is_file($readdir.$pathoffiletoeditsrc)) {
299 $pathoffiletoeditsrc = '/sql/llx_'.strtolower($module).'_'.strtolower($objectname).'-'.strtolower($module).'.sql';
300 if (! dol_is_file($readdir.$pathoffiletoeditsrc)) {
301 $pathoffiletoeditsrc = '/sql/llx_'.strtolower($module).'-'.strtolower($module).'.sql';
302 if (! dol_is_file($readdir.$pathoffiletoeditsrc)) {
303 $pathoffiletoeditsrc = '/sql/llx_'.strtolower($module).'.sql';
304 }
305 }
306 }
307 }
308
309 // Complete path to be full path
310 $pathoffiletoedittarget = $destdir.$pathoffiletoeditsrc.($readdir != $destdir ? '.new' : '');
311 $pathoffiletoeditsrc = $readdir.$pathoffiletoeditsrc;
312
313 if (!dol_is_file($pathoffiletoeditsrc)) {
314 $langs->load("errors");
315 setEventMessages($langs->trans("ErrorFileNotFound", $pathoffiletoeditsrc), null, 'errors');
316 return -1;
317 }
318
319 // Load object from myobject.class.php
320 try {
321 if (!is_object($object)) {
322 include_once $pathoffiletoclasssrc;
323 if (class_exists($objectname)) {
324 $object = new $objectname($db);
325 } else {
326 return -1;
327 }
328 }
329 } catch (Exception $e) {
330 print $e->getMessage();
331 }
332
333 // Backup old file
334 dol_copy($pathoffiletoedittarget, $pathoffiletoedittarget.'.back', $newmask, 1);
335
336 $contentsql = file_get_contents(dol_osencode($pathoffiletoeditsrc));
337
338 $i = 0;
339 $texttoinsert = '-- BEGIN MODULEBUILDER FIELDS'."\n";
340 if (count($object->fields)) {
341 foreach ($object->fields as $key => $val) {
342 $i++;
343
344 $type = $val['type'];
345 $type = preg_replace('/:.*$/', '', $type); // For case type = 'integer:Societe:societe/class/societe.class.php'
346
347 if ($type == 'html') {
348 $type = 'text'; // html modulebuilder type is a text type in database
349 } elseif ($type == 'price') {
350 $type = 'double'; // html modulebuilder type is a text type in database
351 } elseif (in_array($type, array('link', 'sellist', 'duration'))) {
352 $type = 'integer';
353 } elseif ($type == 'chkbxlst') {
354 $type = 'varchar(128)';
355 } elseif ($type == 'mail' || $type == 'email') { // Prefer to use 'email'
356 $type = 'varchar(128)';
357 } elseif (strpos($type, 'stars(') === 0) {
358 $type = 'integer';
359 } elseif ($type == 'phone') {
360 $type = 'varchar(20)';
361 } elseif ($type == 'ip') {
362 $type = 'varchar(32)';
363 } elseif ($type == 'url') {
364 $type = 'varchar(255)';
365 }
366
367 $texttoinsert .= "\t".$key." ".$type;
368 if ($key == 'rowid') {
369 $texttoinsert .= ' AUTO_INCREMENT PRIMARY KEY';
370 } elseif ($type == 'timestamp') {
371 $texttoinsert .= ' DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP';
372 }
373 if ($key == 'entity') {
374 $texttoinsert .= ' DEFAULT 1';
375 } else {
376 if (!empty($val['default'])) {
377 if (preg_match('/^null$/i', $val['default'])) {
378 $texttoinsert .= " DEFAULT NULL";
379 } elseif (preg_match('/varchar/', $type)) {
380 $texttoinsert .= " DEFAULT '".$db->escape($val['default'])."'";
381 } else {
382 $texttoinsert .= (($val['default'] > 0) ? ' DEFAULT '.$val['default'] : '');
383 }
384 }
385 }
386 $texttoinsert .= ((!empty($val['notnull']) && $val['notnull'] > 0) ? ' NOT NULL' : '');
387 if ($i < count($object->fields)) {
388 $texttoinsert .= ", ";
389 }
390 $texttoinsert .= "\n";
391 }
392 }
393 $texttoinsert .= "\t".'-- END MODULEBUILDER FIELDS';
394
395 $contentsql = preg_replace('/-- BEGIN MODULEBUILDER FIELDS.*END MODULEBUILDER FIELDS/ims', $texttoinsert, $contentsql);
396
397 $result = file_put_contents($pathoffiletoedittarget, $contentsql);
398 if ($result) {
399 dolChmod($pathoffiletoedittarget, $newmask);
400 } else {
401 $error++;
402 setEventMessages($langs->trans("ErrorFailToCreateFile", $pathoffiletoedittarget), null, 'errors');
403 }
404
405 // Edit .key.sql file
406 $pathoffiletoeditsrc = preg_replace('/\.sql$/', '.key.sql', $pathoffiletoeditsrc);
407 $pathoffiletoedittarget = preg_replace('/\.sql$/', '.key.sql', $pathoffiletoedittarget);
408 $pathoffiletoedittarget = preg_replace('/\.sql.new$/', '.key.sql.new', $pathoffiletoedittarget);
409
410 $contentsql = file_get_contents(dol_osencode($pathoffiletoeditsrc));
411
412 $i = 0;
413 $texttoinsert = '-- BEGIN MODULEBUILDER INDEXES'."\n";
414 if (count($object->fields)) {
415 foreach ($object->fields as $key => $val) {
416 $i++;
417 if (!empty($val['index'])) {
418 $texttoinsert .= "ALTER TABLE llx_".strtolower($module).'_'.strtolower($objectname)." ADD ".($key == 'ref' ? "UNIQUE INDEX uk_" : "INDEX idx_").strtolower($module).'_'.strtolower($objectname)."_".$key." (".$key.($key == 'ref' && array_key_exists('entity', $object->fields) ? ", entity" : "").");";
419 $texttoinsert .= "\n";
420 }
421 if (!empty($val['foreignkey'])) {
422 $tmp = explode('.', $val['foreignkey']);
423 if (!empty($tmp[0]) && !empty($tmp[1])) {
424 $texttoinsert .= "ALTER TABLE llx_".strtolower($module).'_'.strtolower($objectname)." ADD CONSTRAINT llx_".strtolower($module).'_'.strtolower($objectname)."_".$key." FOREIGN KEY (".$key.") REFERENCES llx_".preg_replace('/^llx_/', '', $tmp[0])."(".$tmp[1].");";
425 $texttoinsert .= "\n";
426 }
427 }
428 }
429 }
430 $texttoinsert .= '-- END MODULEBUILDER INDEXES';
431
432 $contentsql = preg_replace('/-- BEGIN MODULEBUILDER INDEXES.*END MODULEBUILDER INDEXES/ims', $texttoinsert, $contentsql);
433
434 dol_mkdir(dirname($pathoffiletoedittarget));
435
436 $result2 = file_put_contents($pathoffiletoedittarget, $contentsql);
437 if ($result2) {
438 dolChmod($pathoffiletoedittarget, $newmask);
439 } else {
440 $error++;
441 setEventMessages($langs->trans("ErrorFailToCreateFile", $pathoffiletoedittarget), null, 'errors');
442 }
443
444 return $error ? -1 : 1;
445}
446
454{
455 $objects = array();
456 $listofobject = dol_dir_list($destdir.'/class', 'files', 0, '\.class\.php$');
457 foreach ($listofobject as $fileobj) {
458 if (preg_match('/^api_/', $fileobj['name'])) {
459 continue;
460 }
461 if (preg_match('/^actions_/', $fileobj['name'])) {
462 continue;
463 }
464
465 $tmpcontent = file_get_contents($fileobj['fullname']);
466 $reg = array();
467 if (preg_match('/class\s+([^\s]*)\s+extends\s+CommonObject/ims', $tmpcontent, $reg)) {
468 $objectnameloop = $reg[1];
469 $objects[$fileobj['fullname']] = $objectnameloop;
470 }
471 }
472 if (count($objects) > 0) {
473 return $objects;
474 }
475
476 return -1;
477}
478
486function checkExistComment($file, $number)
487{
488 if (!file_exists($file)) {
489 return -1;
490 }
491
492 $content = file_get_contents($file);
493 if ($number === 0) {
494 $ret = 0;
495 if (strpos($content, '/* BEGIN MODULEBUILDER TOPMENU MYOBJECT */') !== false
496 || strpos($content, '/* BEGIN MODULEBUILDER TOPMENU */') !== false) {
497 $ret++;
498 }
499 if (strpos($content, '/* END MODULEBUILDER TOPMENU MYOBJECT */') !== false
500 || strpos($content, '/* END MODULEBUILDER TOPMENU */') !== false) {
501 $ret++;
502 }
503 if (strpos($content, '/* BEGIN MODULEBUILDER LEFTMENU MYOBJECT */') !== false) {
504 $ret++;
505 }
506 if (strpos($content, '/* END MODULEBUILDER LEFTMENU MYOBJECT */') !== false) {
507 $ret++;
508 }
509
510 if ($ret == 4) {
511 return 1;
512 }
513 } elseif ($number === 1) {
514 if (strpos($content, '/* BEGIN MODULEBUILDER PERMISSIONS */') !== false && strpos($content, '/* END MODULEBUILDER PERMISSIONS */') !== false) {
515 return 1;
516 }
517 } elseif ($number == 2) {
518 if (strpos($content, '/* BEGIN MODULEBUILDER DICTIONARIES */') !== false && strpos($content, '/* END MODULEBUILDER DICTIONARIES */') !== false) {
519 return 1;
520 }
521 }
522 return -1;
523}
530function deletePerms($file)
531{
532 $start = "/* BEGIN MODULEBUILDER PERMISSIONS */";
533 $end = "/* END MODULEBUILDER PERMISSIONS */";
534 $i = 1;
535 $array = array();
536 $lines = file($file);
537 // Search for start and end lines
538 foreach ($lines as $i => $line) {
539 if (strpos($line, $start) !== false) {
540 $start_line = $i + 1;
541
542 // Copy lines until the end on array
543 while (($line = $lines[++$i]) !== false) {
544 if (strpos($line, $end) !== false) {
545 $end_line = $i + 1;
546 break;
547 }
548 $array[] = $line;
549 }
550 break;
551 }
552 }
553 $allContent = implode("", $array);
554 dolReplaceInFile($file, array($allContent => ''));
555}
556
563function compareFirstValue($a, $b)
564{
565 return strcmp($a[0], $b[0]);
566}
578function reWriteAllPermissions($file, $permissions, $key, $right, $objectname, $module, $action)
579{
580 $error = 0;
581 $rights = array();
582 if ($action == 0 && $key !== null) {
583 // delete right from permissions array
584 array_splice($permissions, array_search($permissions[$key], $permissions), 1);
585 } elseif ($action == 1) {
586 array_push($permissions, $right);
587 } elseif ($action == 2 && !empty($right) && $key !== null) {
588 // update right from permissions array
589 array_splice($permissions, array_search($permissions[$key], $permissions), 1, $right);
590 } elseif ($action == -1 && !empty($objectname)) {
591 // when delete object
592 $key = null;
593 $right = null;
594 foreach ($permissions as $perms) {
595 if ($perms[4] === strtolower($objectname)) {
596 array_splice($permissions, array_search($perms, $permissions), 1);
597 }
598 }
599 } elseif ($action == -2 && !empty($objectname) && !empty($module)) {
600 $key = null;
601 $right = null;
602 $objectOfRights = array();
603 //check if object already declared in rights file
604 foreach ($permissions as $right) {
605 $objectOfRights[] = $right[4];
606 }
607 if (in_array(strtolower($objectname), $objectOfRights)) {
608 $error++;
609 } else {
610 $permsToadd = array();
611 $perms = array(
612 'read' => 'Read '.$objectname.' object of '.ucfirst($module),
613 'write' => 'Create/Update '.$objectname.' object of '.ucfirst($module),
614 'delete' => 'Delete '.$objectname.' object of '.ucfirst($module)
615 );
616 $i = 0;
617 foreach ($perms as $index => $value) {
618 $permsToadd[$i][0] = '';
619 $permsToadd[$i][1] = $value;
620 $permsToadd[$i][4] = strtolower($objectname);
621 $permsToadd[$i][5] = $index;
622 array_push($permissions, $permsToadd[$i]);
623 $i++;
624 }
625 }
626 } else {
627 $error++;
628 }
629 '@phan-var-force array<int,string[]> $permissions';
630 if (!$error) {
631 // prepare permissions array
632 foreach (array_keys($permissions) as $i) {
633 $permissions[$i][0] = "\$this->rights[\$r][0] = \$this->numero . sprintf('%02d', \$r + 1)";
634 $permissions[$i][1] = "\$this->rights[\$r][1] = '".$permissions[$i][1]."'";
635 $permissions[$i][4] = "\$this->rights[\$r][4] = '".$permissions[$i][4]."'";
636 $permissions[$i][5] = "\$this->rights[\$r][5] = '".$permissions[$i][5]."';\n\t\t";
637 }
638 // for group permissions by object
639 $perms_grouped = array();
640 foreach ($permissions as $perms) {
641 $object = $perms[4];
642 if (!isset($perms_grouped[$object])) {
643 $perms_grouped[$object] = array();
644 }
645 $perms_grouped[$object][] = $perms;
646 }
647 //$perms_grouped = array_values($perms_grouped);
648 $permissions = $perms_grouped;
649
650
651 // parcourir les objects
652 $o = 0;
653 foreach ($permissions as &$object) {
654 // récupérer la permission de l'objet
655 $p = 1;
656 foreach ($object as &$obj) {
657 if (str_contains($obj[5], 'read')) {
658 $obj[0] = "\$this->rights[\$r][0] = \$this->numero . sprintf('%02d', (".$o." * 10) + 0 + 1)";
659 } elseif (str_contains($obj[5], 'write')) {
660 $obj[0] = "\$this->rights[\$r][0] = \$this->numero . sprintf('%02d', (".$o." * 10) + 1 + 1)";
661 } elseif (str_contains($obj[5], 'delete')) {
662 $obj[0] = "\$this->rights[\$r][0] = \$this->numero . sprintf('%02d', (".$o." * 10) + 2 + 1)";
663 } else {
664 $obj[0] = "\$this->rights[\$r][0] = \$this->numero . sprintf('%02d', (".$o." * 10) + ".$p." + 1)";
665 $p++;
666 }
667 }
668 usort($object, 'compareFirstValue');
669 $o++;
670 }
671
672 //convert to string
673 foreach ($permissions as $perms) {
674 foreach ($perms as $per) {
675 $rights[] = implode(";\n\t\t", $per)."\$r++;\n";
676 }
677 }
678 $rights_str = implode("\t\t", $rights);
679 // delete all permissions from file
680 deletePerms($file);
681 // rewrite all permissions again
682 dolReplaceInFile($file, array('/* BEGIN MODULEBUILDER PERMISSIONS */' => '/* BEGIN MODULEBUILDER PERMISSIONS */'."\n\t\t".$rights_str));
683 return 1;
684 } else {
685 return -1;
686 }
687}
688
695function parsePropertyString($string)
696{
697 $string = str_replace("'", '', $string);
698
699 // Uses a regular expression to capture keys and values
700 preg_match_all('/\s*([^\s=>]+)\s*=>\s*([^,]+),?/', $string, $matches, PREG_SET_ORDER);
701 $propertyArray = array();
702
703 foreach ($matches as $match) {
704 $key = trim($match[1]);
705 $value = trim($match[2]);
706
707 if (strpos($value, 'array(') === 0) {
708 $nestedArray = substr($value, 6);
709 $nestedArray = parsePropertyString($nestedArray);
710 $value = $nestedArray;
711 } elseif (strpos($value, '"Id")') !== false) {
712 $value = str_replace(')', '', $value);
713 } else {
714 if (is_numeric($value)) {
715 if (strpos($value, '.') !== false) {
716 $value = (float) $value;
717 } else {
718 $value = (int) $value;
719 }
720 } else {
721 if ($value === 'true') {
722 $value = true;
723 } elseif ($value === 'false') {
724 $value = false;
725 }
726 }
727 }
728 $propertyArray[$key] = $value;
729 }
730
731 return $propertyArray;
732}
733
741function writePropsInAsciiDoc($file, $objectname, $destfile)
742{
743
744 // stock all properties in array
745 $attributesUnique = array('type','label', 'enabled', 'position', 'notnull', 'visible', 'noteditable', 'index', 'default' , 'foreignkey', 'arrayofkeyval', 'alwayseditable','validate', 'searchall','comment', 'isameasure', 'css', 'cssview','csslist', 'help', 'showoncombobox','picto' );
746
747 $start = "public \$fields = array(";
748 $end = ");";
749 $i = 1;
750 $keys = array();
751 $lines = file($file);
752 // Search for start and end lines
753 foreach ($lines as $i => $line) {
754 if (strpos($line, $start) !== false) {
755 // Copy lines until the end on array
756 while (($line = $lines[++$i]) !== false) {
757 if (strpos($line, $end) !== false) {
758 break;
759 }
760 $keys[] = $line;
761 }
762 break;
763 }
764 }
765 // write the begin of table with specifics options
766 $table = "== DATA SPECIFICATIONS\n";
767 $table .= "=== Table of fields with properties for object *$objectname* : \n";
768 $table .= "[options='header',grid=rows,frame=topbot,width=100%,caption=Organisation]\n";
769 $table .= "|===\n";
770 $table .= "|code";
771 // write all properties in the header of the table
772 foreach ($attributesUnique as $attUnique) {
773 $table .= "|".$attUnique;
774 }
775 $table .= "\n";
776 $valuesModif = array();
777 foreach ($keys as $string) {
778 $string = trim($string, "'");
779 $string = rtrim($string, ",");
780
781 $array = parsePropertyString($string);
782
783 // Iterate through the array to merge all key to one array
784 $code = '';
785 foreach ($array as $key => $value) {
786 if (is_array($value)) {
787 $code = $key;
788 continue;
789 } else {
790 $array[$code][$key] = $value;
791 unset($array[$key]);
792 }
793 }
794 // check if is array after parsing the string
795 if (!is_array($array)) {
796 return -1;
797 }
798 $field = array_keys($array);
799 if ($field[0] === '') {
800 $field[0] = 'label';
801 }
802 $values = array_values($array)[0];
803
804 // check each field has all properties and add it if missed
805 foreach ($attributesUnique as $attUnique) {
806 if ($attUnique == 'type' && $field[0] === 'label') {
807 $values[$attUnique] = 'varchar(255)';
808 }
809 if (!array_key_exists($attUnique, $values)) {
810 $valuesModif[$attUnique] = '';
811 } else {
812 $valuesModif[$attUnique] = $values[$attUnique];
813 }
814 }
815 $table .= "|*" . $field[0] . "*|";
816 $table .= implode("|", $valuesModif) . "\n";
817 }
818
819 // end table
820 $table .= "|===\n";
821 $table .= "__ end table for object $objectname\n";
822
823 //write in file @phan-suppress-next-line PhanPluginSuspiciousParamPosition
824 $writeInFile = dolReplaceInFile($destfile, array('== DATA SPECIFICATIONS' => $table));
825 if ($writeInFile < 0) {
826 return -1;
827 }
828 return 1;
829}
830
831
839function deletePropsAndPermsFromDoc($file, $objectname)
840{
841 if (dol_is_file($file)) {
842 $start = "== Table of fields and their properties for object *".ucfirst($objectname)."* : ";
843 $end = "__ end table for object ".ucfirst($objectname);
844
845 $str = file_get_contents($file);
846
847 $search = '/' . preg_quote($start, '/') . '(.*?)' . preg_quote($end, '/') . '/s';
848 $new_contents = preg_replace($search, '', $str);
849 file_put_contents($file, $new_contents);
850 dolChmod($file);
851
852 //perms If Exist
853 $perms = "|*".strtolower($objectname)."*|";
854 $search_pattern_perms = '/' . preg_quote($perms, '/') . '.*?\n/';
855 $new_contents = preg_replace($search_pattern_perms, '', $new_contents);
856 file_put_contents($file, $new_contents);
857 dolChmod($file);
858 }
859}
860
861
862
873function getFromFile($file, $start, $end, $excludestart = '', $includese = 0)
874{
875 $keys = array();
876
877 //$lines = file(dol_osencode($file));
878 $fhandle = fopen(dol_osencode($file), 'r');
879 if ($fhandle) {
880 // Search for start and end lines
881 //foreach ($lines as $i => $line) {
882 while ($line = fgets($fhandle)) {
883 if (strpos($line, $start) !== false && (empty($excludestart) || strpos($line, $excludestart) === false)) {
884 if ($includese) {
885 $keys[] = $line;
886 }
887 // Copy lines until we reach the end
888 while (($line = fgets($fhandle)) !== false) {
889 if (strpos($line, $end) !== false) {
890 if ($includese) {
891 $keys[] = $line;
892 }
893 break;
894 }
895 $keys[] = $line;
896 }
897 break;
898 }
899 }
900 }
901 fclose($fhandle);
902
903 $content = implode("", $keys);
904 return $content;
905}
906
913function writePermsInAsciiDoc($file, $destfile)
914{
915 global $langs;
916 //search and get all permissions in string
917 $start = '/* BEGIN MODULEBUILDER PERMISSIONS */';
918 $end = '/* END MODULEBUILDER PERMISSIONS */';
919 $content = getFromFile($file, $start, $end);
920 if (empty($content)) {
921 return -1;
922 }
923 //prepare table
924 $string = "[options='header',grid=rows,width=60%,caption=Organisation]\n";
925 $string .= "|===\n";
926 // header for table
927 $header = array($langs->trans('Objects'),$langs->trans('Permission'));
928 foreach ($header as $h) {
929 $string .= "|".$h;
930 }
931 $string .= "\n";
932 //content table
933 $array = explode(";", $content);
934 $permissions = array_filter($array);
935 // delete occurrences "$r++" and ID
936 $permissions = str_replace('$r++', '1', $permissions);
937
938 $permsN = array();
939 foreach ($permissions as $i => $element) {
940 if ($element == 1) {
941 unset($permissions[$i]);
942 }
943 if (str_contains($element, '$this->numero')) {
944 unset($permissions[$i]);
945 }
946 if (str_contains($element, '$this->rights[$r][5]')) {
947 unset($permissions[$i]);
948 }
949 }
950 // cleaning the string on each element
951 foreach ($permissions as $key => $element) {
952 $element = str_replace(" '", '', $element);
953 $element = trim($element, "'");
954 $permsN[] = substr($element, strpos($element, "=") + 1);
955 }
956 array_pop($permsN);
957
958 // Group permissions by Object and add it to string
959 $final_array = array();
960 $index = 0;
961 while ($index < count($permsN)) {
962 $temp_array = array($permsN[$index], $permsN[$index + 1]);
963 $final_array[] = $temp_array;
964 $index += 2;
965 }
966
967 $result = array();
968 foreach ($final_array as $subarray) {
969 // found object
970 $key = $subarray[1];
971 // add sub array to object
972 $result[$key][] = $subarray;
973 }
974 foreach ($result as $i => $pems) {
975 $string .= "|*".$i."*|";
976 foreach ($pems as $tab) {
977 $string .= $tab[0]." , ";
978 }
979 $string .= "\n";
980 }
981 // end table
982 $string .= "\n|===\n";
983 // @phan-suppress-next-line PhanPluginSuspiciousParamPosition
984 $write = dolReplaceInFile($destfile, array('__DATA_PERMISSIONS__' => $string));
985 if ($write < 0) {
986 return -1;
987 }
988 return 1;
989}
990
1000function addObjectsToApiFile($srcfile, $file, $objects, $modulename)
1001{
1002 global $langs, $user;
1003
1004 if (!file_exists($file)) {
1005 return -1;
1006 }
1007
1008 $now = dol_now();
1009 $content = file($file); // $content is an array
1010
1011 $includeClass = "dol_include_once\‍(\'\/\w+\/class\/\w+\.class\.php\'\‍);";
1012 $props = 'public\s+\$\w+;';
1013 $varcommented = '@var\s+\w+\s+\$\w+\s+{@type\s+\w+}';
1014 $constructObj = '\$this->\w+\s+=\s+new\s+\w+\‍(\$this->db\‍);';
1015
1016 // add properties and declare them in constructor
1017 foreach ($content as $lineNumber => &$lineContent) {
1018 if (preg_match('/'.$varcommented.'/', $lineContent)) {
1019 $lineContent = '';
1020 foreach ($objects as $objectname) {
1021 $lineContent .= "\t * @var ".$objectname." \$".strtolower($objectname)." {@type ".$objectname."}". PHP_EOL;
1022 }
1023 //var_dump($lineContent);exit;
1024 } elseif (preg_match('/'.$props.'/', $lineContent)) {
1025 $lineContent = '';
1026 foreach ($objects as $objectname) {
1027 $lineContent .= "\t/*".PHP_EOL."\t * @var mixed TODO: set type".PHP_EOL."\t */".PHP_EOL."\tpublic \$".strtolower($objectname).";". PHP_EOL;
1028 }
1029 } elseif (preg_match('/'.$constructObj.'/', $lineContent)) {
1030 $lineContent = '';
1031 foreach ($objects as $objectname) {
1032 $lineContent .= "\t\t\$this->".strtolower($objectname)." = new ".$objectname."(\$this->db);". PHP_EOL;
1033 }
1034 } elseif (preg_match('/'.$includeClass.'/', $lineContent)) {
1035 $lineContent = '';
1036 foreach ($objects as $objectname) {
1037 $lineContent .= "dol_include_once('/".strtolower($modulename)."/class/".strtolower($objectname).".class.php');". PHP_EOL;
1038 }
1039 }
1040 }
1041
1042 $allContent = implode("", $content);
1043 file_put_contents($file, $allContent);
1044 dolChmod($file);
1045
1046 // Add methods for each object
1047 $allContent = getFromFile($srcfile, '/* BEGIN MODULEBUILDER API MYOBJECT */', '/* END MODULEBUILDER API MYOBJECT */');
1048 foreach ($objects as $objectname) {
1049 if (strtolower($modulename) === strtolower($objectname)) {
1050 dol_syslog('addObjectsToApiFile: skipping object "' . $objectname . '" — name collides with module "' . $modulename . '"', LOG_WARNING);
1051 continue;
1052 }
1053 $nc = new NamingContract($modulename, $objectname);
1054 $extraMap = [
1055 'htdocs/modulebuilder/template' => $nc->moduleNameLower,
1056 '---Replace with your own copyright and developer email---' => dol_print_date($now, '%Y') . ' ' . $user->getFullName($langs) . ($user->email ? ' <' . $user->email . '>' : ''),
1057 ];
1058 $fullMap = array_merge($nc->getSubstitutionMap(), $extraMap);
1059 $contentReplaced = str_replace(array_keys($fullMap), array_values($fullMap), $allContent);
1060
1061 dolReplaceInFile($file, array(
1062 '/* BEGIN MODULEBUILDER API MYOBJECT */' => '/* BEGIN MODULEBUILDER API '.strtoupper($objectname).' */'.$contentReplaced."\t".'/* END MODULEBUILDER API '.strtoupper($objectname).' */'."\n\n\n\t".'/* BEGIN MODULEBUILDER API MYOBJECT */'
1063 ));
1064 }
1065
1066 // Remove the block $allContent found in src file
1067 // TODO Replace with a replacement of all text including into /* BEGIN MODULEBUILDER API MYOBJECT */ and /* END MODULEBUILDER API MYOBJECT */
1068 dolReplaceInFile($file, array($allContent => ''));
1069
1070 return 1;
1071}
1072
1081function removeObjectFromApiFile($file, $objects, $objectname)
1082{
1083 if (!file_exists($file)) {
1084 return -1;
1085 }
1086
1087 $content = file($file); // $content is an array
1088
1089 $includeClass = "dol_include_once\‍(\'\/\w+\/class\/".strtolower($objectname)."\.class\.php\'\‍);";
1090 $props = 'public\s+\$'.strtolower($objectname);
1091 $varcommented = '@var\s+\w+\s+\$'.strtolower($objectname).'\s+{@type\s+\w+}';
1092 $constructObj = '\$this->'.strtolower($objectname).'\s+=\s+new\s+\w+\‍(\$this->db\‍);';
1093
1094 // add properties and declare them in constructor
1095 foreach ($content as $lineNumber => &$lineContent) {
1096 if (preg_match('/'.$varcommented.'/i', $lineContent)) {
1097 $lineContent = '';
1098 } elseif (preg_match('/'.$props.'/i', $lineContent)) {
1099 $lineContent = '';
1100 } elseif (preg_match('/'.$constructObj.'/i', $lineContent)) {
1101 $lineContent = '';
1102 } elseif (preg_match('/'.$includeClass.'/i', $lineContent)) {
1103 $lineContent = '';
1104 }
1105 }
1106
1107 $allContent = implode("", $content);
1108 file_put_contents($file, $allContent);
1109 dolChmod($file);
1110
1111 // for delete methods of object
1112 $begin = '/* BEGIN MODULEBUILDER API '.strtoupper($objectname).' */';
1113 $end = '/* END MODULEBUILDER API '.strtoupper($objectname).' */';
1114 $allContent = getFromFile($file, $begin, $end);
1115 $check = dolReplaceInFile($file, array($allContent => ''));
1116 if ($check) {
1117 dolReplaceInFile($file, array($begin => '', $end => ''));
1118 }
1119
1120 return 1;
1121}
1122
1123
1132function reWriteAllMenus($file, $menus, $menuWantTo, $key, $action)
1133{
1134 $errors = 0;
1135 $counter = 0;
1136 if (!file_exists($file)) {
1137 return -1;
1138 }
1139
1140 if ($action == 0 && !empty($key)) {
1141 // delete menu manually
1142 array_splice($menus, array_search($menus[$key], $menus), 1);
1143 } elseif ($action == 1) {
1144 // add menu manually
1145 array_push($menus, $menuWantTo);
1146 } elseif ($action == 2 && !empty($key) && !empty($menuWantTo)) {
1147 // update right from permissions array
1148 $urlCounter = 0;
1149 // check if the values already exists
1150 foreach ($menus as $index => $menu) {
1151 if ($index !== $key) {
1152 if ($menu['type'] === $menuWantTo['type']) {
1153 if (strcasecmp(str_replace(' ', '', $menu['titre']), str_replace(' ', '', $menuWantTo['titre'])) === 0) {
1154 $counter++;
1155 }
1156 if (strcasecmp(str_replace(' ', '', $menu['url']), str_replace(' ', '', $menuWantTo['url'])) === 0) {
1157 $urlCounter++;
1158 }
1159 }
1160 }
1161 }
1162 if (!$counter && $urlCounter < 2) {
1163 $menus[$key] = $menuWantTo;
1164 } else {
1165 $errors++;
1166 }
1167 } elseif ($action == -1 && !empty($menuWantTo) && is_string($menuWantTo)) {
1168 // delete menus when delete Object
1169 foreach ($menus as $index => $menu) {
1170 if ((strpos(strtolower($menu['fk_menu']), strtolower($menuWantTo)) !== false) || (strpos(strtolower($menu['leftmenu']), strtolower($menuWantTo)) !== false)) {
1171 array_splice($menus, array_search($menu, $menus), 1);
1172 }
1173 }
1174 } else {
1175 $errors++;
1176 }
1177 if (!$errors) {
1178 // delete All LEFT Menus (except for commented template MYOBJECT)
1179 $beginMenu = '/* BEGIN MODULEBUILDER LEFTMENU';
1180 $excludeBeginMenu = '/* BEGIN MODULEBUILDER LEFTMENU MYOBJECT';
1181 $endMenu = '/* END MODULEBUILDER LEFTMENU';
1182 $protection = 0;
1183 while ($protection <= 1000 && $allMenus = getFromFile($file, $beginMenu, $endMenu, $excludeBeginMenu, 1)) {
1184 $protection++;
1185 dolReplaceInFile($file, array($allMenus => ''));
1186 }
1187
1188 // forge the menu code in a string
1189 $str_menu = "";
1190 foreach ($menus as $index => $menu) {
1191 $menu['position'] = "1000 + \$r";
1192 if ($menu['type'] === 'left') {
1193 $start = "\t\t".'/* BEGIN MODULEBUILDER LEFTMENU '.strtoupper(empty($menu['object']) ? $menu['titre'] : $menu['object']).' */';
1194 $end = "\t\t".'/* END MODULEBUILDER LEFTMENU '.strtoupper(empty($menu['object']) ? $menu['titre'] : $menu['object']).' */';
1195
1196 $val_actuel = $menu;
1197 $next_val = empty($menus[$index + 1]) ? null : $menus[$index + 1];
1198 //var_dump(dol_escape_php($menu['perms'], 1)); exit;
1199
1200 $str_menu .= $start."\n";
1201 $str_menu .= "\t\t\$this->menu[\$r++] = array(\n";
1202 $str_menu .= "\t\t\t'fk_menu' => '".dol_escape_php($menu['fk_menu'], 1)."',\n";
1203 $str_menu .= "\t\t\t'type' => '".dol_escape_php($menu['type'], 1)."',\n";
1204 $str_menu .= "\t\t\t'titre' => '".dol_escape_php($menu['titre'], 1)."',\n";
1205 $str_menu .= "\t\t\t'mainmenu' => '".dol_escape_php($menu['mainmenu'], 1)."',\n";
1206 $str_menu .= "\t\t\t'leftmenu' => '".dol_escape_php($menu['leftmenu'], 1)."',\n";
1207 $str_menu .= "\t\t\t'url' => '".dol_escape_php($menu['url'], 1)."',\n";
1208 $str_menu .= "\t\t\t'langs' => '".dol_escape_php($menu['langs'], 1)."',\n";
1209 $str_menu .= "\t\t\t'position' => ".((int) $menu['position']).",\n";
1210 $str_menu .= "\t\t\t'enabled' => '".dol_escape_php((string) $menu['enabled'], 1)."',\n";
1211 $str_menu .= "\t\t\t'perms' => '".dol_escape_php($menu['perms'], 1)."',\n";
1212 $str_menu .= "\t\t\t'target' => '".dol_escape_php($menu['target'], 1)."',\n";
1213 $str_menu .= "\t\t\t'user' => ".((int) $menu['user']).",\n";
1214 $str_menu .= "\t\t\t'object' => '".dol_escape_php($menu['object'], 1)."',\n";
1215 $str_menu .= "\t\t);\n";
1216
1217 if (is_null($next_val) || $val_actuel['leftmenu'] !== $next_val['leftmenu']) {
1218 $str_menu .= $end."\n";
1219 }
1220 }
1221 }
1222
1223 dolReplaceInFile($file, array('/* BEGIN MODULEBUILDER LEFTMENU MYOBJECT */' => $str_menu."\n\t\t/* BEGIN MODULEBUILDER LEFTMENU MYOBJECT */"));
1224 return 1;
1225 }
1226 return -1;
1227}
1228
1237function updateDictionaryInFile($module, $file, $dicts)
1238{
1239 $isEmpty = false;
1240 $dicData = "\t\t\$this->dictionaries = array(\n";
1241 $module = strtolower($module);
1242 foreach ($dicts as $key => $value) {
1243 if (empty($value)) {
1244 $isEmpty = true;
1245 $dicData = "\t\t\$this->dictionaries = array();";
1246 break;
1247 }
1248
1249 $dicData .= "\t\t\t'$key' => ";
1250
1251 if ($key === 'tabcond') {
1252 $conditions = array_map(
1257 static function ($val) use ($module) {
1258 return is_bool($val) ? "isModEnabled('$module')" : $val;
1259 },
1260 $value
1261 );
1262 $dicData .= "array(" . implode(", ", $conditions) . ")";
1263 } elseif ($key === 'tabhelp') {
1264 $helpItems = array();
1265 foreach ($value as $helpValue) {
1266 $helpItems[] = "array('code' => \$langs->trans('".$helpValue['code']."'), 'field2' => 'field2tooltip')";
1267 }
1268 $dicData .= "array(" . implode(",", $helpItems) . ")";
1269 } else {
1270 if (is_array($value)) {
1271 $dicData .= "array(" . implode(
1272 ",",
1273 array_map(
1278 static function ($val) {
1279 return "'$val'";
1280 },
1281 $value
1282 )
1283 ) . ")";
1284 } else {
1285 $dicData .= "'$value'";
1286 }
1287 }
1288 $dicData .= ",\n";
1289 }
1290 $dicData .= (!$isEmpty ? "\t\t);" : '');
1291
1292 $stringDic = getFromFile($file, '/* BEGIN MODULEBUILDER DICTIONARIES */', '/* END MODULEBUILDER DICTIONARIES */');
1293 $writeInfile = dolReplaceInFile($file, array($stringDic => $dicData."\n"));
1294
1295 return $writeInfile;
1296}
1297
1310function createNewDictionnary($modulename, $file, $namedic, $dictionnaires = null)
1311{
1312 global $db, $langs;
1313
1314 if (empty($namedic)) {
1315 setEventMessages($langs->trans("ErrorEmptyNameDic"), null, 'errors');
1316 return -1;
1317 }
1318 if (!file_exists($file)) {
1319 return -1;
1320 }
1321 $modulename = strtolower($modulename);
1322
1323 if (empty($dictionnaires)) {
1324 $dictionnaires = array('langs' => '', 'tabname' => array(), 'tablib' => array(), 'tabsql' => array(), 'tabsqlsort' => array(), 'tabfield' => array(), 'tabfieldvalue' => array(), 'tabfieldinsert' => array(), 'tabrowid' => array(), 'tabcond' => array(), 'tabhelp' => array());
1325 }
1326
1327 $columns = array(
1328 'rowid' => array('type' => 'integer', 'value' => 11, 'extra' => 'AUTO_INCREMENT'),
1329 'code' => array('type' => 'varchar', 'value' => 255, 'null' => 'NOT NULL'),
1330 'label' => array('type' => 'varchar', 'value' => 255, 'null' => 'NOT NULL'),
1331 'position' => array('type' => 'integer', 'value' => 11, 'null' => 'NULL'),
1332 'use_default' => array('type' => 'varchar', 'value' => 11, 'default' => '1'),
1333 'active' => array('type' => 'integer', 'value' => 3)
1334 );
1335
1336 $primaryKey = 'rowid';
1337 foreach ($columns as $key => $value) {
1338 if ($key === 'rowid') {
1339 $primaryKey = 'rowid';
1340 break;
1341 }
1342 if (!array_key_exists('rowid', $columns)) {
1343 $primaryKey = array_key_first($columns);
1344 break;
1345 }
1346 }
1347
1348 // check if tablename exist in Database and create it if not
1349 $checkTable = $db->DDLDescTable(MAIN_DB_PREFIX.strtolower($namedic));
1350 if ($checkTable && $db->num_rows($checkTable) > 0) {
1351 setEventMessages($langs->trans("ErrorTableExist", $namedic), null, 'errors');
1352 return -1;
1353 } else {
1354 $_results = $db->DDLCreateTable(MAIN_DB_PREFIX.strtolower($namedic), $columns, $primaryKey, "");
1355 if ($_results < 0) {
1357 $langs->load("errors");
1358 setEventMessages($langs->trans("ErrorTableNotFound", $namedic), null, 'errors');
1359 }
1360 }
1361
1362 // rewrite dictionary if
1363 $dictionnaires['langs'] = $modulename.'@'.$modulename;
1364 $dictionnaires['tabname'][] = strtolower($namedic);
1365 $dictionnaires['tablib'][] = ucfirst(substr($namedic, 2));
1366 $dictionnaires['tabsql'][] = 'SELECT t.rowid as rowid, t.code, t.label, t.active FROM '.MAIN_DB_PREFIX.strtolower($namedic).' as t';
1367 $dictionnaires['tabsqlsort'][] = (array_key_exists('label', $columns) ? 'label ASC' : '');
1368 $dictionnaires['tabfield'][] = (array_key_exists('code', $columns) && array_key_exists('label', $columns) ? 'code,label' : '');
1369 $dictionnaires['tabfieldvalue'][] = (array_key_exists('code', $columns) && array_key_exists('label', $columns) ? 'code,label' : '');
1370 $dictionnaires['tabfieldinsert'][] = (array_key_exists('code', $columns) && array_key_exists('label', $columns) ? 'code,label' : '');
1371 $dictionnaires['tabrowid'][] = $primaryKey;
1372 $dictionnaires['tabcond'][] = isModEnabled('$modulename'); // @phan-suppress-current-line UnknownModuleName
1373 $dictionnaires['tabhelp'][] = (array_key_exists('code', $columns) ? array('code' => $langs->trans('CodeTooltipHelp'), 'field2' => 'field2tooltip') : '');
1374
1375 // Build the dictionary string
1376 $writeInfile = updateDictionaryInFile($modulename, $file, $dictionnaires);
1377 if ($writeInfile > 0) {
1378 setEventMessages($langs->trans("DictionariesCreated", ucfirst(substr($namedic, 2))), null);
1379 }
1380
1381 return -1;
1382}
1383
1391function writeApiUrlsInDoc($file_api, $file_doc)
1392{
1393 $error = 0;
1394 if (!dol_is_file($file_api) || !dol_is_file($file_doc)) {
1395 $error++;
1396 }
1397 $string = getFromFile($file_api, '/*begin methods CRUD*/', '/*end methods CRUD*/');
1398 $extractUrls = explode("\n", $string);
1399
1400 // extract urls from file
1401 $urlValues = array();
1402 foreach ($extractUrls as $key => $line) {
1403 $lineWithoutTabsSpaces = preg_replace('/^[\t\s]+/', '', $line);
1404 if (strpos($lineWithoutTabsSpaces, '* @url') === 0) {
1405 $urlValue = trim(substr($lineWithoutTabsSpaces, strlen('* @url')));
1406 $urlValues[] = $urlValue;
1407 }
1408 }
1409
1410 // get urls by object
1411 $str = $_SERVER['HTTP_HOST'].'/api/index.php/';
1412 $groupedUrls = array();
1413 foreach ($urlValues as $url) {
1414 if (preg_match('/(?:GET|POST|PUT|DELETE) (\w+)s/', $url, $matches)) {
1415 $objectName = $matches[1];
1416 $url = $str.trim(strstr($url, ' '));
1417 $groupedUrls[$objectName][] = $url;
1418 }
1419 }
1420 if (empty($groupedUrls)) {
1421 $error++;
1422 }
1423
1424 // build format asciidoc for urls in table
1425 if (!$error) {
1426 $asciiDocTable = "[options=\"header\"]\n|===\n|Object | URLs\n"; // phpcs:ignore
1427 foreach ($groupedUrls as $objectName => $urls) {
1428 $urlsList = implode(" +\n*", $urls);
1429 $asciiDocTable .= "|$objectName | \n*$urlsList +\n";
1430 }
1431 $asciiDocTable .= "|===\n";
1432 $file_write = dolReplaceInFile($file_doc, array('__API_DOC__' => '__API_DOC__'."\n".$asciiDocTable));
1433 if ($file_write < 0) {
1434 return -1;
1435 }
1436 return 1;
1437 }
1438 return -1;
1439}
1440
1441
1448function countItemsInDirectory($path, $type = 1)
1449{
1450 if (!is_dir($path)) {
1451 return false;
1452 }
1453
1454 $allFilesAndDirs = scandir($path);
1455 $count = 0;
1456
1457 foreach ($allFilesAndDirs as $item) {
1458 if ($item != '.' && $item != '..') {
1459 if ($type == 1 && is_file($path . DIRECTORY_SEPARATOR . $item) && strpos($item, '.back') === false) {
1460 $count++;
1461 } elseif ($type == 2 && is_dir($path . DIRECTORY_SEPARATOR . $item)) {
1462 $count++;
1463 }
1464 }
1465 }
1466 return $count;
1467}
1468
1477{
1478 return array(
1479 'contact' => array('file' => 'myobject_contact.php', 'var' => 'showtabofpagecontact', 'marker' => 'CONTACT', 'label' => 'Contacts'),
1480 'note' => array('file' => 'myobject_note.php', 'var' => 'showtabofpagenote', 'marker' => 'NOTE', 'label' => 'Notes'),
1481 'document' => array('file' => 'myobject_document.php', 'var' => 'showtabofpagedocument', 'marker' => 'DOCUMENT', 'label' => 'Documents'),
1482 'agenda' => array('file' => 'myobject_agenda.php', 'var' => 'showtabofpageagenda', 'marker' => 'AGENDA', 'label' => 'Events'),
1483 );
1484}
1485
1494function filterEnabledTabs($requested, $map)
1495{
1496 $valid = array();
1497 if (!is_array($requested) || empty($requested)) {
1498 return $valid;
1499 }
1500 foreach (array_keys($map) as $tabkey) {
1501 if (in_array($tabkey, $requested, true)) {
1502 $valid[] = $tabkey;
1503 }
1504 }
1505 return $valid;
1506}
1507
1518function dolReplaceInFilePreservingModuleBuilderMarkers($file, $arrayreplacement)
1519{
1520 if (!file_exists($file)) {
1521 return -1;
1522 }
1523 $content = file_get_contents($file);
1524 if ($content === false) {
1525 return -1;
1526 }
1527
1528 // Hide every "/* BEGIN|END MODULEBUILDER ... */" marker behind a sentinel before substituting
1529 $foundmarkers = array();
1530 preg_match_all('/\/\*\s*(?:BEGIN|END) MODULEBUILDER [^*]*\*\//', $content, $foundmarkers);
1531 $sentinels = array();
1532 foreach (array_values(array_unique($foundmarkers[0])) as $index => $marker) {
1533 $key = "\0MODULEBUILDERMARKER".$index."\0";
1534 $sentinels[$key] = $marker;
1535 $content = str_replace($marker, $key, $content);
1536 }
1537
1538 $content = str_replace(array_keys($arrayreplacement), array_values($arrayreplacement), $content);
1539
1540 // Restore the protected markers untouched
1541 if (!empty($sentinels)) {
1542 $content = strtr($content, $sentinels);
1543 }
1544
1545 if (file_put_contents($file, $content) === false) {
1546 return -1;
1547 }
1548 return 1;
1549}
if(! $sortfield) if(! $sortorder) $object
Definition account.php:100
Immutable value object holding all case variants of a module/object pair.
if(!isModEnabled('ai')||!getDolGlobalString('AI_ASSISTANT_ENABLED')) global $db
API class for accounts.
dol_copy($srcfile, $destfile, $newmask='0', $overwriteifexists=1, $testvirus=0, $indexdatabase=0)
Copy a file to another file.
dol_is_file($pathoffile)
Return if path is a file.
dol_dir_list($utf8_path, $types="all", $recursive=0, $filter="", $excludefilter=null, $sortcriteria="name", $sortorder=SORT_ASC, $mode=0, $nohook=0, $relativename="", $donotfollowsymlinks=0, $nbsecondsold=0)
Scan a directory and return a list of files/directories.
Definition files.lib.php:64
dolReplaceInFile($srcfile, $arrayreplacement, $destfile='', $newmask='0', $indexdatabase=0, $arrayreplacementisregex=0)
Make replacement of strings into a file.
dol_now($mode='gmt')
Return date for now.
setEventMessages($mesg, $mesgs, $style='mesgs', $messagekey='', $noduplicate=0, $attop=0)
Set event messages in dol_events session object.
dol_osencode($str)
Return a string encoded into OS filesystem encoding.
dolChmod($filepath, $newmask='')
Change mod of a file.
dol_escape_php($stringtoescape, $stringforquotes=2)
Returns text escaped for inclusion into a php string, build with double quotes " or '.
dol_escape_js($stringtoescape, $mode=0, $noescapebackslashn=0)
Returns text escaped for inclusion into JavaScript code.
dol_sort_array(&$array, $index, $order='asc', $natsort=0, $case_sensitive=0, $keepindex=0)
Advanced sort array by the value of a given key, which produces ascending (default) or descending out...
dol_print_date($time, $format='', $tzoutput='auto', $outputlangs=null, $encodetooutput=false, $decorate=0)
Output date in a string format according to outputlangs (or langs if not defined).
dol_print_error($db=null, $error='', $errors=null)
Displays error message system with all the information to facilitate the diagnosis and the escalation...
isModEnabled($module)
Is Dolibarr module enabled.
dol_syslog($message, $level=LOG_INFO, $ident=0, $suffixinfilename='', $restricttologhandler='', $logcontext=null)
Write log message into outputs.
dol_mkdir($dir, $dataroot='', $newmask='')
Creation of a directory (this can create recursive subdir)
updateDictionaryInFile($module, $file, $dicts)
Updates a dictionary in a module descriptor file.
deletePropsAndPermsFromDoc($file, $objectname)
Delete property and permissions from documentation ascii file if we delete an object.
filterEnabledTabs($requested, $map)
Filter a list of requested tab keys against the known optional tabs map.
createNewDictionnary($modulename, $file, $namedic, $dictionnaires=null)
Create a new dictionary table.
countItemsInDirectory($path, $type=1)
count directories or files in modulebuilder folder
writePermsInAsciiDoc($file, $destfile)
Write all permissions of each object in AsciiDoc format.
reWriteAllMenus($file, $menus, $menuWantTo, $key, $action)
parsePropertyString($string)
Converts a formatted properties string into an associative array.
rebuildObjectSql($destdir, $module, $objectname, $newmask, $readdir='', $object=null, $moduletype='external')
Save data into a memory area shared by all users, all sessions on server.
writeApiUrlsInDoc($file_api, $file_doc)
Generate Urls and add them to documentation module.
getFromFile($file, $start, $end, $excludestart='', $includese=0)
Search a string and return all lines needed from file.
dolGetListOfObjectClasses($destdir)
Get list of existing objects from a directory.
deletePerms($file)
Delete all permissions.
writePropsInAsciiDoc($file, $objectname, $destfile)
Write all properties of the object in AsciiDoc format.
compareFirstValue($a, $b)
Compare two values.
removeObjectFromApiFile($file, $objects, $objectname)
Remove Object variables and methods from API_Module File.
dolReplaceInFilePreservingModuleBuilderMarkers($file, $arrayreplacement)
Apply substitutions to a module descriptor file while preserving the MODULEBUILDER comment markers.
rebuildObjectClass($destdir, $module, $objectname, $newmask, $readdir='', $addfieldentry=array(), $delfieldentry='')
Regenerate files .class.php.
reWriteAllPermissions($file, $permissions, $key, $right, $objectname, $module, $action)
Rewriting all permissions after any actions.
checkExistComment($file, $number)
Function to check if comment BEGIN and END exists in modMyModule class.
getModuleBuilderObjectTabs()
Return the map of optional tabs that can be generated for a ModuleBuilder object.
addObjectsToApiFile($srcfile, $file, $objects, $modulename)
Add Object in ModuleApi File.