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