1<?php
2	/**
3	* SQL Generator ENTITY - helps to construct queries statements
4	* @author Edgar Antonio Luna Diaz <eald@co.com.mx>
5	* @author Alejadro Borges
6	* @author Jonathan Alberto Rivera Gomez
7	* @copyright Copyright (C) 2003,2004 Free Software Foundation, Inc. http://www.fsf.org/
8	* @license http://www.fsf.org/licenses/gpl.html GNU General Public License
9	* @package phpgwapi
10	* @subpackage database
11	* @version $Id: class.sql_entity.inc.php 21045 2010-03-25 22:41:38Z Caeies $
12	* @internal Development of this application was funded by http://www.sogrp.com
13	* @link http://www.sogrp.com/
14	*/
15
16	/**
17	* SQL entity alias substitution string EASS
18	*/
19	define (PHPGW_SQL_EASS, '|%-');
20	/**
21	* SQL default method
22	*/
23	define (PHPGW_SQL_DEFAULT_METHOD, -1);
24	/**
25	* SQL lazy key
26	*/
27	define (PHPGW_SQL_LAZY_KEY, 1);
28	/**
29	* SQL required key
30	*/
31	define (PHPGW_SQL_REQUIRED_KEY, 2);
32	/**
33	* SQL all match
34	*/
35	define (PHPGW_SQL_ALL_MATCH, 1);
36	/**
37	* SQL exclusive match
38	*/
39	define (PHPGW_SQL_EXCLUSIVE_MATCH, 2);
40	/**
41	* SQL return records
42	*/
43	define (PHPGW_SQL_RETURN_RECORDS, 1);
44	/**
45	* SQL run SQL
46	*/
47	define (PHPGW_SQL_RUN_SQL, 1);
48	/**
49	* SQL return SQL
50	*/
51	define (PHPGW_SQL_RETURN_SQL, 2);
52
53
54	/**
55	* SQL Generator ENTITY - helps to construct queries statements
56	*
57	* This class provide common methods to create transaction sql queries.
58	* Isolates an entity.
59	* @package phpgwapi
60	* @subpackage database
61	*/
62	class sql_entity
63	{
64		/* List of fields to mantain in each query, it morph if select,
65		 *  if insert, if update.
66		 */
67		var $fields;
68		var $inserts;
69		var $insert_index;
70		var $operation;
71		var $criteria;
72		// need in list form, for easy search
73		var $field_list;
74		// var $field_array;
75		var $alias;
76		// Just INSERT (update?)
77		var $values;
78		// Imported links
79		var $ilink = array();
80		// Exported links
81		var $elink = array();
82		var $ondebug;
83		var $table;
84
85		function sql_entity()
86		{
87		}
88
89		/*************************************************************\
90		* Entity, class and general section                           *
91		\*************************************************************/
92
93		function _constructor($table='', $alias='')
94		{
95			$this->table = $table;
96			// Temp alias name, just if not empty
97			$this->alias = ($alias)? $alias: $alias;
98			$this->ldebug('_constructor', array('Table' => $table,
99							    'Alias' => $alias));
100		}
101
102		/**
103		* Set the alias for the table
104		*
105		* @param string $alias The alias name
106		* @return The alias name which will be used for SELECT.
107		*/
108		function set_identity($alias)
109		{
110			$this->alias = ($alias)? $alias : get_class($this);
111			$this->table = ($this->table)? $this->table :
112				get_class($this);
113			$this->ldebug('set_identity', array('Alias' => $this->alias,
114							    'Table' => $this->table));
115		}
116
117		function set_table_name($table)
118		{
119			$this->table = $table;
120		}
121
122		function set_alias($alias)
123		{
124			$this->alias = $alias;
125		}
126
127		/**
128		* Get the list of false fields from instance.
129		*
130		* @return Array List of false fields.
131		*/
132
133		function get_false_fields()
134		{
135			return array_keys($this->map);
136		}
137
138		/**
139		* Determines whether if operation must be changed or not.
140		*
141		* Operation is used to decide if alias is attached to fields names or not
142		* @param string $opertation Actual action that is proposed to be the operation.
143		*/
144		function set_operation($operation)
145		{
146			if (empty($this->operation) && $operation != 'criteria' && !empty($operation))
147			{
148				$this->operation = $operation;
149			}
150		}
151
152		/**
153		* Forced change of actual operation
154		*
155		* Operation is used to decide if alias is attached to fields names or not
156		* @param string $operation action to be set.
157		*/
158		function change_operation($operation)
159		{
160			if (!empty($operation) && $operation != 'criteria')
161			{
162				$this->operation = $operation;
163			}
164		}
165
166		/*************************************************************\
167		* Alias section                                               *
168		\*************************************************************/
169		/**
170		* Replace the alias string with the one true alias name
171		*
172		* @return Tow string, fields and criteria with the correct alias name.
173		*/
174		function run_alias()
175		{
176			if ($this->alias)
177			{
178				$this->field_alias();
179				$this->fields = str_replace(PHPGW_SQL_EASS, $this->alias,
180							    $this->fields);
181				$this->criteria = str_replace(PHPGW_SQL_EASS, $this->alias,
182							      $this->criteria);
183				$this->ldebug('run_alias',
184					      array('Fields' => $this->fields,
185						    'Criteria' => $this->criteria,
186						    'Alias' => $this->alias));
187			}
188		}
189
190		/**
191		* Set a alias to the table if is required
192		*
193		* @return string with the table name, with alias if is required.
194		*/
195		function get_identity()
196		{
197			return ($this->alias != $this->table)? $this->table
198				.' AS '.$this->alias : $this->table;
199		}
200
201		function get_alias()
202		{
203			return $this->alias;
204		}
205
206		/**
207		* @param string $field Name of the field.
208		* @return the string ready for replace s/EASS/alias/
209		*/
210		function put_alias($field)
211		{
212			return ($this->operation == 'select')? PHPGW_SQL_EASS.'.'.$field : $field;
213		}
214
215		/**
216		* Set the alias to a any field
217		* @param string $field Name of the field.
218		* @return the string ready for replace s/EASS/alias/
219		*/
220		function put_real_alias($field)
221		{
222			return ($this->operation == 'select')? $this->alias.'.'.$field : $field;
223		}
224		/*************************************************************\
225		* Select section                                              *
226		\*************************************************************/
227
228		/**
229		* Add the field to list, with alias $alias
230		*
231		* @param string $field Any sql instruction like count(field_name)
232		* @param string $alias Alias for $field
233		*/
234		function add_field($alias, $field)
235		{
236			$this->field_list[$alias] = $field;
237		}
238
239		/**
240		* Add the field to list
241		*
242		* @param array $element with real_field and false field (field)
243		* @access private
244		*/
245		function _add_field($element)
246		{
247			$this->add_field($element['field'],
248					$this->put_alias($element['real_field']));
249			$this->ldebug('_add_field',
250				      array('Field_list' => $this->field_list),
251				      'dump');
252		}
253
254		/**
255		* Set the alias for the select query
256		*
257		* @param string $real_field The real name of the field
258		* @param string $alias_field the alias that field will take
259		* @access private
260		*/
261		function set_field_alias($real_field, $alias_field)
262		{
263			$this->ldebug('set_field_alias',
264				      array('Field list' => $this->field_list),
265				      'dump');
266			$this->fields .= ', '.$real_field.' AS '.$alias_field;
267		}
268
269		function field_alias()
270		{
271			$this->ldebug('field_alias',
272				      array('Field list' => $this->field_list),
273				      'dump');
274			if($this->field_list)
275			{
276				$alias_field = key($this->field_list);
277				$field = array_shift($this->field_list);
278				$this->fields = $field.' AS '.$alias_field;
279				array_walk($this->field_list, array(&$this,'set_field_alias'));
280			}
281		}
282
283		/**
284		* local select, if I'm the only one? or for catalog entities?
285		*
286		* @return string A select easy to use.
287		*/
288		function select()
289		{
290			$this->run_alias();
291			$sql_select = 'SELECT ' . $this->fields.
292				' FROM ' . $this->get_identity() .
293				($this->get_criteria()?' WHERE ' . $this->get_criteria():'');
294			return $sql_select;
295		}
296
297		/**
298		* @return array (field, identity, alias, criteria) for:
299		* SELECT <field> FROM <identity> WHERE <criteria> and <alias> for the on construction depending on identity
300		*/
301		function get_select()
302		{
303			$this->run_alias();
304			$select_value = array($this->fields,
305					      $this->get_identity(),
306					      $this->alias,
307					      $this->get_criteria());
308			$this->ldebug('get_select', array('Criteria' => $select_value[4]));
309			return $select_value;
310		}
311
312		/*************************************************************\
313		* Criteria section                                            *
314		\*************************************************************/
315		/**
316		* Get the criteria
317		*
318		* @return string with the criteria which was autogenerate.
319		*/
320		function get_criteria()
321		{
322			return $this->criteria;
323		}
324
325		/**
326		* When no special method defined for $elemnent['field'] this is the method that will run. And add to the criteria list
327		*
328		* @param string $element['real_field'] The associated field.
329		* @param string $element['value'] Criteria for this field.
330		*/
331		function default_criteria($element)
332		{
333			$this->ldebug('default_criteria',
334				     array('Element' => $element), 'dump');
335			$field = (($this->operation == 'select') ?
336				  $this->put_alias($element['real_field']) :
337				  $element['real_field']);
338			$this->ldebug('default_criteria',
339				      array('Field' => $field));
340
341			$new_criteria = sql_criteria::has($field,
342							  $element['value']);
343			$this->ldebug('default_criteria',
344				      array('New Criteria' => $new_criteria));
345			$this->_add_criteria($new_criteria);
346		}
347
348		/**
349		* Add criteria to list
350		*
351		* @param string $new_criteria with the new criteria which was autegenerate.
352		* @return string with the criteria.
353		*/
354		function _add_criteria($new_criteria)
355		{
356			$this->ldebug('_add_criteria',
357				      array('New Criteria' => $new_criteria,
358					    'All Criteria Prev' => $this->criteria));
359			$this->criteria = sql_criteria::append_and(array($new_criteria,
360									 $this->criteria));
361			$this->ldebug('_add_criteria',
362				      array('All Criteria Post' => $this->criteria));
363		}
364
365		/**
366		* Especial criteria for index or id, it decides if must call equal or in operator
367		*
368		* @param array $element with field, value, real_name
369		* @return string with a usefull criteria to use for many (a in clause) or just one id (equal).
370		*/
371		function index_criteria($element)
372		{
373			$field = $this->put_alias($element['real_field']);
374			if(is_array($element['value']))
375			{
376				if(count($element['value']) == 1)
377				{
378					$value = $this->cast(current($element['value']), $element['field']);
379					return sql_criteria::equal($field, $value);
380				}
381				elseif(count($element['value']) > 1)
382				{
383					return sql_criteria::in($field, $element['value'], $this->get_datatype($field));
384				}
385			}
386			else
387			{
388				$value = $this->cast($element['value'], $element['field']);
389				return sql_criteria::equal($field, $value);
390			}
391		}
392
393		/**
394		* Analize a criteria created by tokens and create a string that represent it, useful for any kind of operation that use criteria I guess.
395		*
396		* @param $token_criteria array Array with all the criteria in tokens, generated with sql_criteria
397		* @return string Criteria string (All that goes in WHERE clause)
398		* @see sql_criteria
399		*/
400
401		function entity_criteria($token_criteria)
402		{
403			/*
404			Things to care about:
405			- `_append_and', `_append_or' arrays have two elements: 1. array with criterias, 2. token
406			- `in' is a three element: 1. field name, 2. array with values, 3. token
407			*/
408
409			$num_elements = count($token_criteria);
410			switch($num_elements)
411			{
412			case 0:
413			case 1:
414				$local_criteria = $token_criteria;
415				break;
416			case 2:
417			case 3:
418				$operator = array_pop($token_criteria);
419				$left = array_shift($token_criteria);
420				$right = array_shift($token_criteria);
421
422				if(is_array($left) && $operator != 'in')
423				{
424					$left = $this->entity_criteria($left);
425				}
426				else
427				{
428					$left = $this->real_field($left);
429				}
430				if(is_array($right))
431				{
432					$right = $this->entity_criteria($right);
433				}
434				$local_criteria = sql_criteria::operate($operator,$left,$right);
435				break;
436			default:
437				$operator = array_pop($token_criteria);
438				$local_criteria = sql_criteria::operate($operator,$token_criteria);
439			}
440			return $local_criteria;
441		}
442
443		/*************************************************************\
444		* Insert (input data) section                                 *
445		\*************************************************************/
446
447		/**
448		* Wrapper for calling add_insert_element, when we have $element ready.
449		*
450		* @param array $element Form: ('field', 'real_field', 'value').
451		*/
452		function set_insert_data($element)
453		{
454			$this->add_insert_element($element['field'],$element['real_field'],$element['value']);
455		}
456
457		/**
458		* Genarete two string with fields and values list
459		*
460		* @param string $false_field Field in map.
461		* @param string $field BD field and  which use in insert.
462		* @param string $value Value for use in insert.
463		*/
464		function add_insert_element($false_field,$field,$value)
465		{
466			$this->inserts[$this->insert_index]['data'][$false_field] = array('field' => $field, 'value' => $value);
467			$this->ldebug('add_insert_element',
468				      array('False Field' => $false_field,
469					    'DB Field' => $field,
470					    'Value' => $value_insert));
471		}
472
473		/*************************************************************\
474		* Insert (return data) section                                *
475		\*************************************************************/
476
477		/**
478		* Definitive interfase for get the array of inserts sql queries
479		*
480		* @param array $entities with the list of entity that are present in the transaction
481		* @return Array with the sql insert, just with imported keys missing
482		*/
483		function get_multiple_insert($entities)
484		{
485			foreach ($entities as $entity_name)
486			{
487				$link = $this-get_ilink($entity_name);
488				$field = $this->real_field($link['lfield']);
489				$fields_to_prototype[$field] = '{'.$link['lfield'].'}';
490			}
491
492			foreach ($this->inserts as $index => $insert)
493			{
494				// First element, the only one than don't begin with `,'
495				$false_field = key($this->inserts[$index]['data']);
496				$this->inserts[$index]['fields'] = $insert['data'][$false_field]['field'];
497				$this->inserts[$index]['values'] = $insert['data'][$false_field]['value'];
498				// Go for next elements
499				array_walk($this->inserts[$index]['data'],array(&$this,'set_fields_insert'),$index);
500				reset($this->inserts[$index]['data']);
501				array_walk($field_to_prototype,array(&$this,'set_field_inserts_prototyped'),$index);
502				$inserts[$index] = $this->insert($idx);
503			}
504			return $inserts;
505		}
506
507		function insert($data, $action=PHPGW_SQL_RETURN_SQL)
508		{
509			$this->_insert($data, 0);
510			$sql = $this->get_single_insert(0);
511			switch($action)
512			{
513			case PHPGW_SQL_RETURN_RECORDS:
514			case PHPGW_SQL_RUN_SQL:
515				$GLOBALS['phpgw']->db->query($sql, __LINE__, __FILE__);
516				$this->ldebug('insert', $sql, 'msg');
517				break;
518			case PHPGW_SQL_RETURN_SQL:
519				return $sql;
520			}
521		}
522
523		function _insert($data, $index = 0)
524		{
525			foreach($data as $field => $value)
526			{
527				$this->add_insert($field, $value, $index);
528			}
529		}
530
531		/**
532		* Get the insert sql statement for one entry
533		*
534		* @param int $index with the index of data which we want to insert
535		* @return string Corresponding sql insert.
536		*/
537		function get_single_insert($index = 0)
538		{
539			// First element, the only one than don't begin with `,'
540			$false_field = key($this->inserts[$index]['data']);
541			$this->inserts[$index]['fields'] = $this->inserts[$index]['data'][$false_field]['field'];
542			$this->inserts[$index]['values'] = $this->cast($this->inserts[$index]['data'][$false_field]['value'], $false_field);
543			// Go for next elements
544			while(next($this->inserts[$index]['data']))
545			{
546				$false_field = key($this->inserts[$index]['data']);
547				$this->ldebug('get_single_insert', array('data for index '.$index => $this->inserts[$index]['data']), 'dump');
548				$this->inserts[$index]['fields'] .= ', '.$this->inserts[$index]['data'][$false_field]['field'];
549				$this->inserts[$index]['values'] .= ', '.$this->cast($this->inserts[$index]['data'][$false_field]['value'], $false_field);
550			}
551			return $this->_single_insert($index);
552		}
553
554		/**
555		* Get the right value for the datatype of the false field
556		*
557		* @param mixed $data value that want to cast.
558		* @param string $false_field Field for search datatype
559		* @return string Corresponding string with sql for datatype
560		*/
561		function cast($data, $false_field)
562		{
563			if(is_array($data))
564			{
565				return $this->index_criteria($data);
566
567			}
568			$type = $this->get_datatype($false_field);
569			return ($data == sql::null())? sql::null() : sql::$type($data);
570		}
571
572		/**
573		* Genarete the insert string
574		*
575		* @return The string which will be use for insert query.
576		*/
577		function _single_insert($index)
578		{
579			$sql_insert = 'INSERT INTO ' . $this->table .
580				' ('. $this->get_insert_fields($index).
581				') VALUES ('.$this->get_insert_values($index).')';
582			return $sql_insert;
583		}
584
585		function set_fields_insert_prototyped($field, $value, $index)
586		{
587			if(!array_key_exist($field, $this->inserts[$index]['data']))
588			{
589				$this->inserts[$index]['fields'] .= ', '.$field;
590				$this->inserts[$index]['values'] .= ', '.$value;
591			}
592		}
593
594		function get_insert_fields($index)
595		{
596			return $this->inserts[$index]['fields'];
597		}
598
599		function get_insert_values($index)
600		{
601			return $this->inserts[$index]['values'];
602		}
603
604		/*************************************************************\
605		* Update section                                              *
606		\*************************************************************/
607
608		/**
609		* Create an update query for this entity
610		*
611		* @param Array $data Fields that want change value and their values
612		* @param Array $criteria With criterias that set the rows to edit
613		* @param integer action
614		* @return string SQL update string
615		*/
616		function update($data,$criteria, $action=PHPGW_SQL_RETURN_SQL)
617		{
618			if(is_array($data) && count($data) > 0)
619			{
620				array_walk($data, array(&$this,'add_update'));
621			}
622			else
623			{
624				list($field,$value) = explode('=',$data);
625				$this->add_update($field, $value);
626			}
627			if (is_string($criteria))
628			{
629				$this->set_criteria($criteria);
630			}
631			else
632			{
633				$this->set_criteria(sql_criteria::criteria($criteria));
634			}
635
636			if(!empty($this->values))
637			{
638				switch($action)
639				{
640				case PHPGW_SQL_RETURN_RECORDS:
641				case PHPGW_SQL_RUN_SQL:
642					$sql = $this->return_update();
643					$GLOBALS['phpgw']->db->query($sql, __LINE__, __FILE__);
644					$this->ldebug('update', $sql, 'msg');
645					return;
646				case PHPGW_SQL_RETURN_SQL:
647					return $this->return_update();
648				}
649			}
650		}
651
652		function set_criteria($criteria)
653		{
654			$this->criteria = $criteria;
655
656		}
657
658		/**
659		* Genarete the update string
660		*
661		* @return The string which will be used for update query.
662		*/
663		function return_update()
664		{
665			$sql_update = 'UPDATE ' . $this->table .
666				' SET ' . $this->values;
667			if ($this->criteria)
668			{
669				$sql_update .=' WHERE ' . $this->criteria;
670			}
671			$this->values = '';
672			$this->criteria = '';
673			return $sql_update;
674		}
675
676		function get_update()
677		{
678			return (array('fields'	=> $this->get_update_data(),
679				      'criteria'=> $this->get_criteria(),
680				      'identity'=> $this->get_identity()));
681		}
682
683		/**
684		* Genarete a string with field = value to use in update
685		*
686		* @param string $fields
687		* @param string $values
688		* @return string with field=value list.
689		*/
690		function set_update_data($element)
691		{
692			$value = ($element['value'] || $element['value'] == 0) ? $this->cast($element['value'], $element['field']) : sql::null();
693			$this->values .= (($this->values)?', ':'').$element['real_field'].' = '.$value;
694		}
695
696		/**
697		* Get the complete field=value listo to use in the update
698		*
699		* @return string with field=value comma separate.
700		*/
701		function get_update_data()
702		{
703			return $this->values;
704		}
705
706		/**
707		* Genarete the delete string
708		*
709		* @param string $criteria the criteria for select the rows to delete
710		* @param integer $action PHPGW_SQL_RETURN_SQL | PHPGW_SQL_RUN_SQL
711		* @return string which will be used for delete query.
712		*/
713		function delete($criteria, $action)
714		{
715			if($criteria)
716			{
717				$sql = 'DELETE FROM '.$this->table.' WHERE '.$criteria;
718
719				$this->set_criteria('');
720				switch($action)
721				{
722				case PHPGW_SQL_RETURN_RECORDS:
723				case PHPGW_SQL_RUN_SQL:
724					$GLOBALS['phpgw']->db->query($sql, __LINE__, __FILE__);
725					return;
726				case PHPGW_SQL_RETURN_SQL:
727					return $sql;
728				}
729			}
730		}
731
732		/**
733		* Get the complete fields list to use in the insert or select
734		*
735		* @return string with fields comma separate.
736		*/
737		function get_fields()
738		{
739			return $this->fields;
740		}
741
742		/*************************************************************\
743		* Links and keys section                                      *
744		\*************************************************************/
745		/**
746		* Genarete an array with all imported links
747		*
748		* @param string $fl with local field
749		* @param string $t with table
750		* @param string $ff with foreign field
751		* @param int $key_type PHPGW_SQL_LAZY_KEY if want that this link be joined via OUTER (LEFT o RIGHT); PHPGW_SQL_REQUIRED_KEY
752		* if want that be joined with INNER LINK. This is the setting by default, and could be changed per query execution.
753		*/
754		function set_ilinks($fl,$t,$ff,$key_type = PHPGW_SQL_LAZY_KEY)
755		{
756			$this->ilink[$t] = array('lfield' => $fl,
757						 'ffield' => $ff,
758						 'type'   => $key_type);
759		}
760
761		/**
762		* Genarete an array with all exported links
763		*
764		* @param string $fl with local field
765		* @param string $t with table
766		* @param string $ff with foreign field
767		*/
768		function set_elinks($fl,$t,$ff)
769		{
770			$this->elink[$t] = array('lfield' => $fl,
771						 'ffield' => $ff);
772		}
773
774		/**
775		* Get the lfield and ffield from any of elink or ilink according to $entity.
776		*
777		* @param string $entity Name of entity to search link with.
778		* @return Array $lfield that is the local field of the link, and $ffield that is the foreign field.
779		*/
780		function get_link($entity = '')
781		{
782			if ($entity != '')
783			{
784				if(array_key_exists($entity, (isset($this->ilink)? $this->ilink : array())))
785				{
786					return $this->ilink[$entity];
787				}
788				elseif (array_key_exists($entity, (isset($this->elink)? $this->elink : array())))
789				{
790					return $this->elink[$entity];
791				}
792			}
793			// Must raise error
794			return '';
795		}
796
797		/**
798		* Get the lfield and ffield from any of ilink according to $entity.
799		*
800		* @param strnig $entity Name of entity to search link with.
801		* @return Array $lfield that is the local field of the link, and $ffield that is the foreign field.
802
803		*/
804		function get_ilink($entity = '')
805		{
806			$this->ldebug('get_ilink', array('entity' => $entity));
807			$this->ldebug('get_ilink', array('ilinks' => $this->ilink), 'dump');
808			if ($entity != '')
809			{
810				if(array_key_exists($entity, (isset($this->ilink)? $this->ilink : array())))
811				{
812					return $this->ilink[$entity];
813				}
814			}
815			// Must raise error
816			return ;
817		}
818
819		/**
820		* Get the lfield and ffield from any of elink according to $entity.
821		*
822		* @param string $entity Name of entity to search link with.
823		* @return Array $lfield that is the local field of the link, and $ffield that is the foreign field.
824		*/
825		function get_elink($entity = '')
826		{
827			if ($entity != '')
828			{
829				if (array_key_exists($entity, (isset($this->elink)? $this->elink : array())))
830				{
831					return $this->elink[$entity];
832				}
833			}
834			return ;
835		}
836
837		/**
838		* Set an array with all imported or exported links
839		*
840		* @return array with imported or exported links.
841		*/
842		function get_ilinks()
843		{
844			return $this->ilink;
845		}
846
847		/**
848		* Set an array with all exported links
849		*
850		* @return array with imported or exported links.
851		*/
852		function get_elinks()
853		{
854			return $this->elink;
855		}
856
857		function get_fields_links($entities)
858		{
859			foreach ($entities as $entity_name)
860			{
861				$link = get_ilink($entity_name);
862				$fields_return[] = $link['ffalse'];
863			}
864			return $fields_return;
865		}
866
867		/*************************************************************\
868		* add_element `Sniper' section                                *
869		\*************************************************************/
870
871		function add_element($action, $element)
872		{
873			$this->set_operation($action);
874			$method = $this->get_method($action,$element['field']);
875			$element['real_field'] = $this->real_field($element['field']);
876			switch($action)
877			{
878			case 'select':
879				$method_default = '_add_field';
880				break;
881			case 'insert':
882			case 'delete':
883			case 'update':
884				$method_default = 'set_'.$action.'_data';
885				break;
886			case 'criteria':
887				$method_default = 'default_criteria';
888				break;
889			default:
890				$this->dont_exist($action);
891			}
892			$this->ldebug('add_element', array('Element' => $element),
893				      'dump');
894			if($method == PHPGW_SQL_DEFAULT_METHOD)
895			{
896				$this->ldebug('add_element',
897					      array('Method_Default DEF' => $method_default,
898						    'Method DEF' => $default));
899				$this->$method_default($element);
900			}
901			elseif ($method)
902			{
903				$this->ldebug('add_element',
904					      array('Method_Default' => $method_default,
905						    'Method' => $default));
906				$this->$method($element);
907			}
908			else
909			{
910				$this->ldebug('add_element', 'Never be here, hope', 'msg');
911				$this->dont_exist($element);
912			}
913		}
914
915		function get_method($action, $field)
916		{
917			if(isset($this->map[$field]))
918			{
919				$method = $this->map[$field][$action];
920				if(isset($this->map[$field][$action])
921				   && method_exists($this, $method))
922				{
923					return $method;
924				}
925				elseif(method_exists($this, $action.'_'.$field))
926				{
927					return $action.'_'.$field;
928				}
929				else
930				{
931					return PHPGW_SQL_DEFAULT_METHOD;
932				}
933			}
934			// this is an error :/ not $field in map
935			return;
936		}
937
938		function real_field($field)
939		{
940			if(isset($this->map[$field]))
941			{
942				if(isset($this->map[$field]['field'])
943				   && !empty($this->map[$field]['field']))
944				{
945					return $this->map[$field]['field'];
946				}
947				else
948				{
949					return $field;
950				}
951			}
952			// this is an error :/ not $field in map
953			return;
954		}
955
956		/**
957		* Get the real field name with alias of table. (Used in criteria).
958		*
959		* @param string $field False field name.
960		* @return string alias.real_name
961		*/
962		function alias_field($field)
963		{
964			return $this->get_alias().'.'.$this->real_field($field);
965		}
966
967
968		function get_datatype($field)
969		{
970			if(isset($this->map[$field]))
971			{
972				if(isset($this->map[$field]['type'])
973				   && !empty($this->map[$field]['type']))
974				{
975					return $this->map[$field]['type'];
976				}
977				else
978				{
979					return 'string';
980				}
981			}
982			// this is an error :/ not $field in map
983			return;
984		}
985
986		function make_pair($field, $value)
987		{
988			return array('field' => $field,
989				     'value' => $value);
990		}
991
992		/*************************************************************\
993		* sql_builder API section                                     *
994		\*************************************************************/
995
996		function add_select($field)
997		{
998			$this->add_element('select',$this->make_pair($field,''));
999			$this->ldebug('add_select', array('Field' => $field));
1000		}
1001
1002		function add_criteria($field, $value)
1003		{
1004			$this->add_element('criteria',$this->make_pair($field,
1005								       $value));
1006			$this->ldebug('add_criteria', array('Field' => $field));
1007
1008		}
1009		function add_update($value, $field)
1010		{
1011			$this->add_element('update',$this->make_pair($field,
1012								     $value));
1013		}
1014
1015		function add_delete($field, $value)
1016		{
1017			$this->add_element('delete',$this->make_pair($field,
1018								     $value));
1019		}
1020
1021		function add_insert($field, $value, $idx = 0)
1022		{
1023			$this->insert_index = $idx;
1024			$this->add_element('insert',$this->make_pair($field,
1025								      $value));
1026		}
1027
1028		/**
1029		* Must raise errors for this class, don't know if phpgw have anything already, if yes, net call it
1030		*
1031		* @param mixed $data What dont exist
1032		*/
1033		function dont_exist($data)
1034		{
1035		}
1036
1037		/**
1038		* Get the field name which correspond to sort
1039		*
1040		* @param strngi $field The field
1041		* @return The alias and real name for field.
1042		*/
1043		function get_order($field)
1044		{
1045			if($this->map[$field]['sort'])
1046			{
1047				return $this->alias.'.'.$this->map[$field]['sort'];
1048			}
1049		}
1050
1051		function ldebug($myfoo, $data, $type = 'string', $err = '')
1052		{
1053// 			if (!((($myfoo != '') xor
1054// 			       ($myfoo != 'default_criteria')) xor
1055// 			      ($myfoo == '')) xor
1056// 			    ($myfoo == ''))
1057// 			{
1058				return;
1059// 			}
1060
1061			$classname = '<strong>Class: '.get_class($this)."<br />Function: $myfoo<br /></strong>";
1062
1063			switch($type)
1064			{
1065			case 'string':
1066				foreach($data as $vari => $value)
1067				{
1068					if (is_array($value))
1069					{
1070						$this->ldebug($myfoo.' recursivecall',
1071							      array('&nbsp;&nbsp;-$vari: ' => $value),
1072							      'dump');
1073					}
1074					else
1075					{
1076						$output .= "&nbsp;&nbsp;-$vari = $value <br />";
1077					}
1078				}
1079				break;
1080			case 'dump':
1081				foreach($data as $vari => $value)
1082				{
1083					$output .= "&nbsp;&nbsp;-$vari = ";
1084					$output .= var_dump($value)."<br />";
1085				}
1086				break;
1087			default:
1088				$output .= "<br />$data<br />";
1089			}
1090			if ($err != '')
1091			{
1092				$output = $classname.'Error: '.$output.'<br />';
1093			}
1094			else
1095			{
1096				$output = $classname.$output.'<br />';
1097			}
1098			echo $output;
1099		}
1100	}
1101?>
1102