Framework  3.9
composite_auto_form.inc
Go to the documentation of this file.
1 <?php
5 require_once realpath(dirname(__FILE__)."/auto_form.inc");
6 
30 {
31  var $forms;
32  var $buttons = array();
33  var $method;
34  var $action;
36  var $buttonAlignment = "left";
37  var $preset = array();
39  var $onSaveComplete = null;
40 
41 
48  function CompositeAutoForm($method = "POST", $action = "", $containerClass = "")
49  {
50  global $auto_form_defaults;
51 
52  foreach($auto_form_defaults as $field => $value)
53  {
54  $this->$field = $value;
55  }
56 
57  $this->forms = array();
58  $this->method = $method;
59  $this->action = $action;
60  $this->containerClass = $containerClass;
61  }
62 
67  function addForm($form, $enableValidation = false)
68  {
69  $form->makeSubordinate();
70  $this->forms[] = $form;
71  $form->getValidationEngine()->generateScript = $enableValidation;
72  }
73 
77  function writeScript()
78  {
79  $script = "";
80  foreach($this->forms as $form)
81  {
82  $s = $form->writeScript();
83  if ($form->getValidationEngine()->generateScript)
84  {
85  // Remap form control ids
86  $s= preg_replace("/\\bform\\[(['\"])([^'\"]*?)['\"]\\]/", "form[$1{$form->id}__$2$1]", $s);
87  }
88  $script .= $s;
89  }
90 
91  ob_start();
92 ?>
93 <script type="text/javascript">
94 function onCompositeFormSubmit(form)
95 {
96 <?
97  foreach($this->forms as $form)
98  {
99 ?>
100  if (!onSubmit<?echo $form->id?>(form)) return false;
101 <?
102  }
103  ?>
104  return true;
105 }
106 </script>
107 <?
108  $script .= ob_get_contents();
109  ob_end_clean();
110 
111  return $script;
112  }
113 
126  function preset()
127  {
128  foreach(func_get_args() as $preset)
129  {
130  $this->presetFields[$preset] = true;
131  }
132  }
133 
137  function drawForm()
138  {
139  if ($this->readOnlyForm) return $this->drawReadOnly();
140 
141  echo "<form id='composite_auto_form' method='{$this->method}' action='{$this->action}' enctype='multipart/form-data'";
142  echo " onsubmit='return onCompositeFormSubmit(this);'";
143  echo ">\n";
144 
145  if ($this->buttons_at_top)
146  {
147  $this->drawButtons();
148  }
149 
150  foreach($this->forms as $form)
151  {
152  ob_start();
153  $form->drawForm();
154  $output = ob_get_contents();
155  ob_end_clean();
156 
157  $output = preg_replace("/\\bname=(['\"])([^'\"]*?)['\"]/", "name=$1{$form->id}__$2$1", $output);
158 
159 ?>
160  <div id="<?echo $form->id?>_container" class="<?echo $this->containerClass?>">
161 <?
162  echo $output;
163 ?>
164  </div>
165 <?
166  }
167 
168  $this->drawButtons();
169 
170  echo "</form>\n";
171  }
172 
176  function drawReadOnly()
177  {
178  foreach($this->forms as $form)
179  {
180  ob_start();
181  $form->drawReadOnly();
182  $output = ob_get_contents();
183  ob_end_clean();
184 
185  $output = preg_replace("/\\bname=(['\"])([^'\"]*?)['\"]/", "name=$1{$form->id}__$2$1", $output);
186 
187 ?>
188  <div id="<?echo $form->id?>_container" class="<?echo $this->containerClass?>">
189 <?
190  echo $output;
191 ?>
192 
193  </div>
194 <?
195  }
196 
197  echo "<div style='clear:both'>&nbsp;</div><br/>";
198  }
199 
209  function button($text, $url, $confirm = null, $isScript = false)
210  {
211  $this->buttons[] = array('text' => $text, 'url' => $url, 'confirm' => $confirm, 'isScript' => $isScript);
212  }
213 
218  function drawButtons()
219  {
220 
221  $submitLabel = $this->submitLabel;
222  $obj = $this->forms[0]->getData();
223 
224  if ($submitLabel == "")
225  {
226  $submitLabel = "Save ".pluralize($obj->prettifyClassName());
227  }
228 
229  echo "<div style='clear: both; text-align: {$this->buttonAlignment}'><br/>";
230  if ($this->useLinkSubmit)
231  {
232  echo "<a class='{$this->buttonCSS}' name='submit' onclick='if (onSubmit{$this->id}(document.forms.{$this->id})) return document.forms.{$this->id}.submit(); else return false;'>$submitLabel</a>";
233  }
234  else
235  {
236  echo "<input type='submit' class='{$this->buttonCSS}' value='$submitLabel'/>";
237  }
238 
239  foreach($this->buttons as $button)
240  {
241  $url = ($button['isScript']) ? $button['url'] : "go('{$button['url']}');";
242 
243  if ($button['confirm'])
244  {
245  $link = "if (confirm('".jsSafe($button['confirm'])."')) $url; return false;";
246  }
247  else
248  {
249  $link = "$url; return false;";
250  }
251 
252  echo "&nbsp;&nbsp;&nbsp;&nbsp;<input type='button' class='{$this->buttonCSS}' onclick=\"$link\" value=\"{$button['text']}\"/>";
253  }
254 
255  echo "</div>";
256  }
257 
258 
259  function save()
260  {
261  global $method;
262 
263  // Do magic
264 
265  $valid = true;
266 
267  foreach($this->forms as $form)
268  {
269  foreach($_POST as $name => $value)
270  {
271  if (strpos($name, "__") === false)
272  {
273  unset($_POST[$name]);
274  }
275  }
276 
277  $prefix = $form->id."__";
278  $len = strlen($prefix);
279 
280  foreach($_POST as $name => $value)
281  {
282  if (!strncmp($name, $prefix, $len))
283  {
284  $_POST[substr($name, $len)] = $value;
285  }
286  }
287 
288  foreach($_FILES as $name => $value)
289  {
290  if (strpos($name, "__") === false)
291  {
292  unset($_FILES[$name]);
293  }
294  }
295 
296  $prefix = $form->id."__";
297  $len = strlen($prefix);
298 
299  foreach($_FILES as $name => $value)
300  {
301  if (!strncmp($name, $prefix, $len))
302  {
303  $_FILES[substr($name, $len)] = $value;
304  }
305  }
306 
307  if (!$form->save())
308  {
309  $valid = false;
310  }
311  }
312 
313  if ($valid)
314  {
315  // onComplete event is fired once all processing has been completed
316 
317  if ($this->onSaveComplete)
318  {
319  call_user_func_array($this->onSaveComplete, array($this));
320  }
321  }
322 
323  return $valid;
324  }
325 
326 }
327 
328 /*
329  * Creates a form that can be a subordinate to
330  * a CompositeAutoForm.
331  *
332  * @param parent - the instance of CompositeAutoForm
333  * this form is subordinate to
334  *
335  * @param form - the instance of AutoForm with all
336  * any custom settings needed (aliases, hidden fields, etc).
337  *
338  * @allowEmpty - whether a completely empty form, that
339  * will not be saved, should be considered an error
340  * condition. For spreadsheet forms, an empty row should
341  * not report an error.
342  *
343  */
345 {
346  var $id;
347  var $form;
348  var $parent;
349  var $msg;
350  var $allowEmpty; // whether we want to show an error message if entire subform is empty
351 
353  {
354  $this->parent = $parent;
355  $this->form = $form;
356  $this->id = $form->id;
357  $this->allowEmpty = $allowEmpty;
358 
359  $this->parent->addForm($this);
360  }
361 
362  /*
363  * For subordinates that require special handling,
364  * create a child class of SubordinateAutoForm
365  * and set the form's special characteristics here,
366  * then add to its Composite instance.
367  */
368  function createForm()
369  {
370  $this->form = new AutoForm($this->obj, "POST", "", $this->id);
371 
372  // set hidden fields, aliases, special renderers etc.
373  $this->parent->addForm($this);
374  }
375 
380  {
381  return $this->form->validator;
382  }
383 
384  function getData()
385  {
386  return $this->form->getData();
387  }
388 
389  function setDataSet($params)
390  {
391  $this->form->setDataSet($params);
392  }
393 
394  function writeScript()
395  {
396  return $this->form->writeScript();
397  }
398 
399  function drawForm()
400  {
401  $this->form->drawForm();
402  }
403 
404  function drawReadOnly()
405  {
406  $this->form->drawReadOnly();
407  }
408 
409  function makeSubordinate()
410  {
411  $this->form->makeSubordinate();
412  }
413 
414  /*
415  * If an empty subform should not produce an
416  * error message then return true to the
417  * parent composite form.
418  */
419  function save()
420  {
421  $rtn = $this->form->save();
422 
423  if($rtn == false && $this->allowEmpty && $this->isEmpty())
424  {
425  $rtn = true;
426  }
427  else
428  $this->msg = $this->form->msg;
429 
430  return $rtn;
431  }
432 
433  /*
434  * If we don't want to show an error message
435  * when an entire subform is empty then
436  * check if empty. This is the case for
437  * a spreadsheet that provides multiple empty
438  * rows and we won't save if empty but don't
439  * consider a blank row an error.
440  */
441  function isEmpty()
442  {
443  $empty = true;
444  $obj =& $this->form->getData();
445  $pk = $obj->getPrimaryKey();
446 
447  $fields = $obj->getFields();
448  $filter = $obj->getFilter();
449 
450  foreach($fields as $field => $type)
451  {
452  if ($field != $pk && !array_key_exists($field, $this->form->hidden) && !($filter && $filter->isExcluded($field)) && !array_key_exists($field, $this->parent->presetFields))
453  {
454  $value = $obj->$field;
455  if($value)
456  {
457  $empty = false;
458  break;
459  }
460  }
461  }
462  return $empty;
463  }
464 }
AutoForm automatically creates a form based on an underlying DataItem.
Definition: auto_form.inc:46
AutoForm($target, $method="POST", $action="", $id="")
Creates a new AutoForm, based on the supplied target DataItem.
Definition: auto_form.inc:166
$fields
Local field cache.
Definition: auto_form.inc:111
CompositeAutoForm is a container for situations where multiple AutoForms need to be managed on the sa...
drawButtons()
Draws any additional buttons specified in the calling script.
$onSaveComplete
Callback event handler that is fired after all the subordinate AutoForms have finished saving data to...
writeScript()
Write script for all the sub-forms.
addForm($form, $enableValidation=false)
Add a sub-form to this form.
$readOnlyForm
Specifies whether the entire form is read-only.
CompositeAutoForm($method="POST", $action="", $containerClass="")
Creates a new CompositeAutoForm.
drawReadOnly()
Draw the read-only sub-forms.
button($text, $url, $confirm=null, $isScript=false)
Adds a custom button to the form.
drawForm()
Draw the sub-forms, with a combined single set of submission buttons.
preset()
Array of fields to be ignored when determining if a record is empty in cases where empty records shou...
getData()
Returns the target data item for the form.
makeSubordinate()
Set this AutoForm to be a subordinate form within a CompositeAutoForm.
SubordinateAutoForm($parent, $form, $allowEmpty=false)
getValidationEngine()
Retrieve the validation engine for this AutoForm.
writeScript()
This method writes any Javascript code that will be required for the generated form to operate,...
drawReadOnly()
Draws the form in read-only mode.
save()
Saves the posted values to the database.
drawForm()
Renders the form to HTML.