1<?php
2/* Copyright (C) 2009-2010 Laurent Destailleur  <eldy@users.sourceforge.net>
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 3 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <https://www.gnu.org/licenses/>.
16 * or see https://www.gnu.org/
17 */
18
19/**
20 *  \file		htdocs/core/lib/memory.lib.php
21 *  \brief		Set of function for memory/cache management
22 */
23
24
25/**
26 * 	Regenerate files .class.php
27 *
28 *  @param	string      $destdir		Directory
29 * 	@param	string		$module			Module name
30 *  @param	string      $objectname		Name of object
31 * 	@param	string		$newmask		New mask
32 *  @param	string      $readdir		Directory source (use $destdir when not defined)
33 *  @param	string		$addfieldentry	Array of the field entry to add array('key'=>,'type'=>,''label'=>,'visible'=>,'enabled'=>,'position'=>,'notnull'=>','index'=>,'searchall'=>,'comment'=>,'help'=>,'isameasure')
34 *  @param	string		$delfieldentry	Id of field to remove
35 * 	@return	int|object					<=0 if KO, Object if OK
36 *  @see rebuildObjectSql()
37 */
38function rebuildObjectClass($destdir, $module, $objectname, $newmask, $readdir = '', $addfieldentry = array(), $delfieldentry = '')
39{
40	global $db, $langs;
41
42	if (empty($objectname)) {
43		return -1;
44	}
45	if (empty($readdir)) {
46		$readdir = $destdir;
47	}
48
49	if (!empty($addfieldentry['arrayofkeyval']) && !is_array($addfieldentry['arrayofkeyval'])) {
50		dol_print_error('', 'Bad parameter addfieldentry with a property arrayofkeyval defined but that is not an array.');
51		return -1;
52	}
53
54	// Check parameters
55	if (is_array($addfieldentry) && count($addfieldentry) > 0) {
56		if (empty($addfieldentry['name'])) {
57			setEventMessages($langs->trans('ErrorFieldRequired', $langs->transnoentitiesnoconv("Name")), null, 'errors');
58			return -2;
59		}
60		if (empty($addfieldentry['label'])) {
61			setEventMessages($langs->trans('ErrorFieldRequired', $langs->transnoentitiesnoconv("Label")), null, 'errors');
62			return -2;
63		}
64		if (!preg_match('/^(integer|price|sellist|varchar|double|text|html|duration)/', $addfieldentry['type'])
65			&& !preg_match('/^(boolean|real|date|datetime|timestamp)$/', $addfieldentry['type'])) {
66			setEventMessages($langs->trans('BadValueForType', $objectname), null, 'errors');
67			return -2;
68		}
69	}
70
71	$pathoffiletoeditsrc = $readdir.'/class/'.strtolower($objectname).'.class.php';
72	$pathoffiletoedittarget = $destdir.'/class/'.strtolower($objectname).'.class.php'.($readdir != $destdir ? '.new' : '');
73	if (!dol_is_file($pathoffiletoeditsrc)) {
74		$langs->load("errors");
75		setEventMessages($langs->trans("ErrorFileNotFound", $pathoffiletoeditsrc), null, 'errors');
76		return -3;
77	}
78
79	//$pathoffiletoedittmp=$destdir.'/class/'.strtolower($objectname).'.class.php.tmp';
80	//dol_delete_file($pathoffiletoedittmp, 0, 1, 1);
81
82	try {
83		include_once $pathoffiletoeditsrc;
84		if (class_exists($objectname)) {
85			$object = new $objectname($db);
86		} else {
87			return -4;
88		}
89
90		// Backup old file
91		dol_copy($pathoffiletoedittarget, $pathoffiletoedittarget.'.back', $newmask, 1);
92
93		// Edit class files
94		$contentclass = file_get_contents(dol_osencode($pathoffiletoeditsrc), 'r');
95
96		// Update ->fields (add or remove entries)
97		if (count($object->fields)) {
98			if (is_array($addfieldentry) && count($addfieldentry)) {
99				$name = $addfieldentry['name'];
100				unset($addfieldentry['name']);
101
102				$object->fields[$name] = $addfieldentry;
103			}
104			if (!empty($delfieldentry)) {
105				$name = $delfieldentry;
106				unset($object->fields[$name]);
107			}
108		}
109
110		dol_sort_array($object->fields, 'position');
111
112		$i = 0;
113		$texttoinsert = '// BEGIN MODULEBUILDER PROPERTIES'."\n";
114		$texttoinsert .= "\t".'/**'."\n";
115		$texttoinsert .= "\t".' * @var array  Array with all fields and their property. Do not use it as a static var. It may be modified by constructor.'."\n";
116		$texttoinsert .= "\t".' */'."\n";
117		$texttoinsert .= "\t".'public $fields=array('."\n";
118
119		if (count($object->fields)) {
120			foreach ($object->fields as $key => $val) {
121				$i++;
122				$texttoinsert .= "\t\t'".$key."' => array('type'=>'".$val['type']."',";
123				$texttoinsert .= " 'label'=>'".$val['label']."',";
124				$texttoinsert .= " 'enabled'=>'".($val['enabled'] !== '' ? $val['enabled'] : 1)."',";
125				$texttoinsert .= " 'position'=>".($val['position'] !== '' ? $val['position'] : 50).",";
126				$texttoinsert .= " 'notnull'=>".(empty($val['notnull']) ? 0 : $val['notnull']).",";
127				$texttoinsert .= " 'visible'=>".($val['visible'] !== '' ? $val['visible'] : -1).",";
128				if ($val['noteditable']) {
129					$texttoinsert .= " 'noteditable'=>'".$val['noteditable']."',";
130				}
131				if ($val['default'] || $val['default'] === '0') {
132					$texttoinsert .= " 'default'=>'".$val['default']."',";
133				}
134				if ($val['index']) {
135					$texttoinsert .= " 'index'=>".$val['index'].",";
136				}
137				if ($val['foreignkey']) {
138					$texttoinsert .= " 'foreignkey'=>'".$val['foreignkey']."',";
139				}
140				if ($val['searchall']) {
141					$texttoinsert .= " 'searchall'=>".$val['searchall'].",";
142				}
143				if ($val['isameasure']) {
144					$texttoinsert .= " 'isameasure'=>'".$val['isameasure']."',";
145				}
146				if ($val['css']) {
147					$texttoinsert .= " 'css'=>'".$val['css']."',";
148				}
149				if ($val['cssview']) {
150					$texttoinsert .= " 'cssview'=>'".$val['cssview']."',";
151				}
152				if ($val['csslist']) {
153					$texttoinsert .= " 'csslist'=>'".$val['csslist']."',";
154				}
155				if ($val['help']) {
156					$texttoinsert .= " 'help'=>\"".preg_replace('/"/', '', $val['help'])."\",";
157				}
158				if ($val['showoncombobox']) {
159					$texttoinsert .= " 'showoncombobox'=>'".$val['showoncombobox']."',";
160				}
161				if ($val['disabled']) {
162					$texttoinsert .= " 'disabled'=>'".$val['disabled']."',";
163				}
164				if ($val['autofocusoncreate']) {
165					$texttoinsert .= " 'autofocusoncreate'=>'".$val['autofocusoncreate']."',";
166				}
167				if ($val['arrayofkeyval']) {
168					$texttoinsert .= " 'arrayofkeyval'=>array(";
169					$i = 0;
170					foreach ($val['arrayofkeyval'] as $key2 => $val2) {
171						if ($i) {
172							$texttoinsert .= ", ";
173						}
174						$texttoinsert .= "'".$key2."'=>'".$val2."'";
175						$i++;
176					}
177					$texttoinsert .= "),";
178				}
179				if ($val['comment']) {
180					$texttoinsert .= " 'comment'=>\"".preg_replace('/"/', '', $val['comment'])."\"";
181				}
182
183				$texttoinsert .= "),\n";
184			}
185		}
186
187		$texttoinsert .= "\t".');'."\n";
188		//print ($texttoinsert);exit;
189
190		if (count($object->fields)) {
191			//$typetotypephp=array('integer'=>'integer', 'duration'=>'integer', 'varchar'=>'string');
192
193			foreach ($object->fields as $key => $val) {
194				$i++;
195				//$typephp=$typetotypephp[$val['type']];
196				$texttoinsert .= "\t".'public $'.$key.";";
197				//if ($key == 'rowid')  $texttoinsert.= ' AUTO_INCREMENT PRIMARY KEY';
198				//if ($key == 'entity') $texttoinsert.= ' DEFAULT 1';
199				//$texttoinsert.= ($val['notnull']?' NOT NULL':'');
200				//if ($i < count($object->fields)) $texttoinsert.=";";
201				$texttoinsert .= "\n";
202			}
203		}
204
205		$texttoinsert .= "\t".'// END MODULEBUILDER PROPERTIES';
206
207		//print($texttoinsert);exit;
208
209		$contentclass = preg_replace('/\/\/ BEGIN MODULEBUILDER PROPERTIES.*END MODULEBUILDER PROPERTIES/ims', $texttoinsert, $contentclass);
210
211		dol_mkdir(dirname($pathoffiletoedittarget));
212
213		//file_put_contents($pathoffiletoedittmp, $contentclass);
214		file_put_contents(dol_osencode($pathoffiletoedittarget), $contentclass);
215		@chmod($pathoffiletoedittarget, octdec($newmask));
216
217		return $object;
218	} catch (Exception $e) {
219		print $e->getMessage();
220		return -5;
221	}
222}
223
224/**
225 * 	Save data into a memory area shared by all users, all sessions on server
226 *
227 *  @param	string      $destdir		Directory
228 * 	@param	string		$module			Module name
229 *  @param	string      $objectname		Name of object
230 * 	@param	string		$newmask		New mask
231 *  @param	string      $readdir		Directory source (use $destdir when not defined)
232 *  @param	Object		$object			If object was already loaded/known, it is pass to avoid another include and new.
233 *  @param	string		$moduletype		'external' or 'internal'
234 * 	@return	int							<=0 if KO, >0 if OK
235 *  @see rebuildObjectClass()
236 */
237function rebuildObjectSql($destdir, $module, $objectname, $newmask, $readdir = '', $object = null, $moduletype = 'external')
238{
239	global $db, $langs;
240
241	$error = 0;
242
243	if (empty($objectname)) {
244		return -1;
245	}
246	if (empty($readdir)) {
247		$readdir = $destdir;
248	}
249
250	$pathoffiletoclasssrc = $readdir.'/class/'.strtolower($objectname).'.class.php';
251
252	// Edit .sql file
253	if ($moduletype == 'internal') {
254		$pathoffiletoeditsrc = $readdir.'/../install/mysql/tables/llx_'.strtolower($module).'_'.strtolower($objectname).'.sql';
255		$pathoffiletoedittarget = $destdir.'/../install/mysql/tables/llx_'.strtolower($module).'_'.strtolower($objectname).'.sql'.($readdir != $destdir ? '.new' : '');
256	} else {
257		$pathoffiletoeditsrc = $readdir.'/sql/llx_'.strtolower($module).'_'.strtolower($objectname).'.sql';
258		$pathoffiletoedittarget = $destdir.'/sql/llx_'.strtolower($module).'_'.strtolower($objectname).'.sql'.($readdir != $destdir ? '.new' : '');
259	}
260
261	if (!dol_is_file($pathoffiletoeditsrc)) {
262		$langs->load("errors");
263		setEventMessages($langs->trans("ErrorFileNotFound", $pathoffiletoeditsrc), null, 'errors');
264		return -1;
265	}
266
267	// Load object from myobject.class.php
268	try {
269		if (!is_object($object)) {
270			include_once $pathoffiletoclasssrc;
271			if (class_exists($objectname)) {
272				$object = new $objectname($db);
273			} else {
274				return -1;
275			}
276		}
277	} catch (Exception $e) {
278		print $e->getMessage();
279	}
280
281	// Backup old file
282	dol_copy($pathoffiletoedittarget, $pathoffiletoedittarget.'.back', $newmask, 1);
283
284	$contentsql = file_get_contents(dol_osencode($pathoffiletoeditsrc), 'r');
285
286	$i = 0;
287	$texttoinsert = '-- BEGIN MODULEBUILDER FIELDS'."\n";
288	if (count($object->fields)) {
289		foreach ($object->fields as $key => $val) {
290			$i++;
291
292			$type = $val['type'];
293			$type = preg_replace('/:.*$/', '', $type); // For case type = 'integer:Societe:societe/class/societe.class.php'
294
295			if ($type == 'html') {
296				$type = 'text'; // html modulebuilder type is a text type in database
297			} elseif ($type == 'price') {
298				$type = 'double'; // html modulebuilder type is a text type in database
299			} elseif (in_array($type, array('link', 'sellist', 'duration'))) {
300				$type = 'integer';
301			}
302			$texttoinsert .= "\t".$key." ".$type;
303			if ($key == 'rowid') {
304				$texttoinsert .= ' AUTO_INCREMENT PRIMARY KEY';
305			}
306			if ($key == 'entity') {
307				$texttoinsert .= ' DEFAULT 1';
308			} else {
309				if ($val['default'] != '') {
310					if (preg_match('/^null$/i', $val['default'])) {
311						$texttoinsert .= " DEFAULT NULL";
312					} elseif (preg_match('/varchar/', $type)) {
313						$texttoinsert .= " DEFAULT '".$db->escape($val['default'])."'";
314					} else {
315						$texttoinsert .= (($val['default'] > 0) ? ' DEFAULT '.$val['default'] : '');
316					}
317				}
318			}
319			$texttoinsert .= (($val['notnull'] > 0) ? ' NOT NULL' : '');
320			if ($i < count($object->fields)) {
321				$texttoinsert .= ", ";
322			}
323			$texttoinsert .= "\n";
324		}
325	}
326	$texttoinsert .= "\t".'-- END MODULEBUILDER FIELDS';
327
328	$contentsql = preg_replace('/-- BEGIN MODULEBUILDER FIELDS.*END MODULEBUILDER FIELDS/ims', $texttoinsert, $contentsql);
329
330	$result = file_put_contents($pathoffiletoedittarget, $contentsql);
331	if ($result) {
332		@chmod($pathoffiletoedittarget, octdec($newmask));
333	} else {
334		$error++;
335	}
336
337	// Edit .key.sql file
338	if ($moduletype == 'internal') {
339		$pathoffiletoeditsrc = $readdir.'/../install/mysql/tables/llx_'.strtolower($module).'_'.strtolower($objectname).'.key.sql';
340		$pathoffiletoedittarget = $destdir.'/../install/mysql/tables/llx_'.strtolower($module).'_'.strtolower($objectname).'.key.sql'.($readdir != $destdir ? '.new' : '');
341	} else {
342		$pathoffiletoeditsrc = $destdir.'/sql/llx_'.strtolower($module).'_'.strtolower($objectname).'.key.sql';
343		$pathoffiletoedittarget = $destdir.'/sql/llx_'.strtolower($module).'_'.strtolower($objectname).'.key.sql'.($readdir != $destdir ? '.new' : '');
344	}
345
346	$contentsql = file_get_contents(dol_osencode($pathoffiletoeditsrc), 'r');
347
348	$i = 0;
349	$texttoinsert = '-- BEGIN MODULEBUILDER INDEXES'."\n";
350	if (count($object->fields)) {
351		foreach ($object->fields as $key => $val) {
352			$i++;
353			if (!empty($val['index'])) {
354				$texttoinsert .= "ALTER TABLE llx_".strtolower($module).'_'.strtolower($objectname)." ADD INDEX idx_".strtolower($module).'_'.strtolower($objectname)."_".$key." (".$key.");";
355				$texttoinsert .= "\n";
356			}
357			if (!empty($val['foreignkey'])) {
358				$tmp = explode('.', $val['foreignkey']);
359				if (!empty($tmp[0]) && !empty($tmp[1])) {
360					$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].");";
361					$texttoinsert .= "\n";
362				}
363			}
364		}
365	}
366	$texttoinsert .= '-- END MODULEBUILDER INDEXES';
367
368	$contentsql = preg_replace('/-- BEGIN MODULEBUILDER INDEXES.*END MODULEBUILDER INDEXES/ims', $texttoinsert, $contentsql);
369
370	dol_mkdir(dirname($pathoffiletoedittarget));
371
372	$result2 = file_put_contents($pathoffiletoedittarget, $contentsql);
373	if ($result) {
374		@chmod($pathoffiletoedittarget, octdec($newmask));
375	} else {
376		$error++;
377	}
378
379	return $error ? -1 : 1;
380}
381