Framework  3.9
cross_reference_select_field_renderer.inc
Go to the documentation of this file.
1 <?php
6 /**************************************************************
7 
8  Copyright (c) 2007-2010 Sonjara, Inc
9 
10  Permission is hereby granted, free of charge, to any person
11  obtaining a copy of this software and associated documentation
12  files (the "Software"), to deal in the Software without
13  restriction, including without limitation the rights to use,
14  copy, modify, merge, publish, distribute, sublicense, and/or sell
15  copies of the Software, and to permit persons to whom the
16  Software is furnished to do so, subject to the following
17  conditions:
18 
19  The above copyright notice and this permission notice shall be
20  included in all copies or substantial portions of the Software.
21 
22  Except as contained in this notice, the name(s) of the above
23  copyright holders shall not be used in advertising or otherwise
24  to promote the sale, use or other dealings in this Software
25  without prior written authorization.
26 
27  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
28  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
29  OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
30  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
31  HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
32  WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
33  FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
34  OTHER DEALINGS IN THE SOFTWARE.
35 
36 *****************************************************************/
37 
38 require_once realpath(dirname(__FILE__))."/../field_renderers.inc";
39 
46 class CrossReferenceSelectFieldRenderer extends FieldRenderer
47 {
48  var $relatedClass;
49  var $constraint;
50  var $xrefClass;
51  var $xrefField;
52  var $nameField;
53  var $field;
54  var $label;
55  var $options;
56  var $groupBy;
57  var $groupByFormat;
58  var $resizable = false;
59  var $dropdown;
60  var $dropdownMaxWidth = "340px";
61  var $dropdownMessage = "Click to Select Terms";
62  var $showSelectAll = false;
63  var $disable = false;
64  var $columns = 1;
65 
66  function CrossReferenceSelectFieldRenderer(&$form, $field, $label, $options, $nameField, $xrefClass, $xrefField = null)
67  {
68  $this->field = $field;
69  $this->label = ($label) ? $label : $form->overrides[$field]['label'];
70 
71  $this->options = $options;
72  $this->nameField = $nameField;
73  $this->xrefClass = $xrefClass;
74  $this->xrefField = $xrefField;
75  $this->showSelectAll = false;
76 
77  $this->FieldRenderer($form);
78 
79  // JDG 7/31/2011 - allow override
80  if ($form->data->hasField($field))
81  {
82  $form->override($field, $label, $this);
83  }
84  else
85  {
86  $form->add($this, $field);
87  $form->overrides[$field]['label'] = $label;
88  }
89 
90  if ($form instanceof SearchForm)
91  {
92  if (count($options))
93  {
94  $foreignKey = $this->xrefField ? $this->xrefField : $options[0]->getPrimaryKey();
95 
96  $class = get_class($form->data);
97 
98  trace("## Adding CrossReferenceSearchParameterHandler for $class via $xrefClass", 3);
99 
100  $form->params->setHandler($field, new CrossReferenceSearchParameterHandler($class, $xrefClass, $foreignKey));
101  $form->setMatchingMode("member", $field);
102  }
103  }
104  }
105 
106  function setSize($width, $height)
107  {
108  $this->width = $width;
109  $this->height = $height;
110  }
111 
112  function groupBy($groupBy, $format = "")
113  {
114  $this->groupBy = $groupBy;
115  $this->groupByFormat = $format;
116  }
117 
118  function renderScript($field)
119  {
120  if ($this->showSelectAll)
121  {
122 ?>
123 <script type="text/javascript">
124 
125 function <?echo $this->field ?>_toggleSelectAll(link)
126 {
127  var value = (link.innerHTML == "Select All");
128 
129  var inputs = document.getElementsByTagName("INPUT");
130 
131  for(var i = 0; i < inputs.length; ++i)
132  {
133  var input = inputs[i];
134  if (input.attributes['id'] && input.attributes['id'].value.indexOf('<?php echo $this->parent->id?>_checkbox_<?echo $this->field?>') == 0)
135  {
136  input.checked = value;
137  }
138  }
139 
140 <?
141  if ($this->dropdown)
142  {
143 ?>
144  document.id('<?echo $this->parent->id?>_<?echo $field?>_container').multiSelect.selectionChanged();
145 <?
146  }
147 ?>
148  link.innerHTML = (value) ? "Deselect All" : "Select All";
149  return false;
150 }
151 
152 </script>
153 <?
154  }
155 
156 
157  if ($this->dropdown)
158  {
159  ?>
160  <script type='text/javascript'>
161  window.addEvent('domready', function()
162  {
163  new MultiSelect('<?echo $this->parent->id?>_<?echo $field?>_container', {maxWidth: '<?echo $this->dropdownMaxWidth?>', message: '<?echo jsSafe($this->dropdownMessage)?>'});
164  });
165  </script>
166  <?
167  }
168 
169  }
170 
171 
172  function renderSearchScript($field, $mode)
173  {
174 
175  if ($this->dropdown)
176  {
177  ?>
178  <script type='text/javascript'>
179  window.addEvent('domready', function()
180  {
181  new MultiSelect('<?echo $this->parent->id?>_<?echo $this->field?>_container', {maxWidth: '<?echo $this->dropdownMaxWidth?>', message: '<?echo jsSafe($this->dropdownMessage)?>'});
182  });
183  </script>
184  <?
185  }
186  }
187 
188  function getMatchingPK($xref, $obj)
189  {
190  $pks = $obj->getPrimaryKeyList();
191  foreach($pks as $pk)
192  {
193  if ($xref->hasField($pk)) return $pk;
194  }
195 
196  throw new DataItemException("No matching foreign key in xref table");
197  }
198 
199  function renderField($field = "")
200  {
201  if (count($this->options) == 0) return;
202 
203  $field = $this->field;
204 
205  $this->_startField($field);
206 
207  $obj = $this->parent->data;
208 
209  if (is_array($this->groupBy) && count($this->groupBy) > 0)
210  {
211  $keys = array_keys($this->options);
212  $rc = $this->options[$keys[0]][0];
213  }
214  else
215  {
216  $rc = $this->options[0];
217  }
218 
219  $xref = new $this->xrefClass;
220 
221  $itempk = $this->getMatchingPK($xref, $rc);
222  $pk = $this->getMatchingPK($xref, $obj);
223 
224  $selected = $this->getSelected($obj, $rc, $pk);
225 
226  if ($this->showSelectAll)
227  {
228  echo "<a class='select_toggle' href='#' onclick='return {$field}_toggleSelectAll(this);'>Select All</a><br/>";
229  }
230  if ($this->width && $this->height)
231  {
232  $resizable = ($this->resizable && !$this->dropdown) ? " resizable": "";
233  $dropdown = $this->dropdown ? " multi_select_dropdown_list" : "";
234  echo "<div id='{$this->parent->id}_{$field}_container' class='selectbox scrollbox{$resizable}{$dropdown}' style='width: {$this->width}px; height: {$this->height}px; overflow: auto'>\n";
235  }
236  else
237  {
238  echo "<div id='{$this->parent->id}_{$field}' class='selectbox'>\n";
239  }
240 
241  $countOptions = count($this->options);
242 
243  if (is_array($this->groupBy) && count($this->groupBy) > 0)
244  {
245  $gpk = $this->groupBy[0]->getPrimaryKey();
246 
247  foreach($this->groupBy as $group)
248  {
249  if (array_key_exists($group->get($gpk), $this->options))
250  {
251  echo $group->format($this->groupByFormat);
252  $this->renderCheckboxes($field, $this->options[$group->get($gpk)], $itempk, $selected);
253  }
254  }
255  }
256  else if (is_string($this->groupBy))
257  {
258  $options = regroupList($this->options, $this->groupBy);
259 
260  foreach($options as $group => $choices)
261  {
262  if (is_callable($this->groupByFormat))
263  {
264  $group = call_user_func($this->groupByFormat, $group);
265  }
266  echo "<br/><h4>$group</h4>";
267  $this->renderCheckboxes($field, $choices, $itempk, $selected);
268  }
269  }
270  else
271  {
272  $this->renderCheckBoxes($field, $this->options, $itempk, $selected);
273  }
274 
275  echo "</div>\n";
276 
277  // Save this count to loop through checkboxes on required validation
278  echo "<input type=\"hidden\" name=\"count_{$field}\" value=\"$countOptions\">";
279 
280  $this->_endField($field);
281  }
282 
283  function getSelected($obj, $rc, $pk)
284  {
285  $itempk = $this->xrefField ? $this->xrefField: $rc->getPrimaryKey();
286  return ($obj->get($pk) != "") ? indexedQuery($this->xrefClass, "WHERE {$pk}={$obj->get($pk)}", $itempk) : array();
287  }
288 
289 
290  function renderCheckboxes($field, $items, $itempk, $selected, $mode = null)
291  {
292  $name = $mode ? "$field:$mode" : $field;
293 
294  if ($this->columns > 1)
295  {
296  echo "<table class='layout'><tbody><tr><td>";
297  $colheight = ceil(count($items) / $this->columns);
298  }
299 
300  $i = 0;
301  foreach($items as $item)
302  {
303  ++$i;
304 
305  $p = $item->$itempk;
306  $v = $mode ? $p : "1";
307 
308  $disable = ($this->disable) ? "disabled='disabled'" : "";
309  echo "<label for='{$this->parent->id}_checkbox_{$field}_$p'>";
310  echo "<input type='checkbox' class='checkbox' name='{$name}[$p]' id='{$this->parent->id}_checkbox_{$field}_$p' $disable value='{$v}'";
311  if (array_key_exists($item->$itempk, $selected))
312  {
313  echo " checked";
314  }
315  echo "/>";
316 
317  echo $this->formatName($item, $this->nameField)."</label>";
318 
319 
320  if ($this->columns > 1 && ($i % $colheight == 0))
321  {
322  echo "</td>";
323  if ($i < count($items))
324  {
325  echo "<td>";
326  }
327  }
328  }
329 
330  if ($this->columns > 1)
331  {
332  echo "</td></tr></tbody></table>\n";
333  $colheight = ceil(count($items) / $this->columns);
334  }
335  }
336 
337  function renderSearchField($field = "", $mode = "member")
338  {
339  if (count($this->options) == 0) return;
340 
341  $field = $this->field;
342 
343  $this->_startField($field);
344 
345  $obj = $this->parent->data;
346 
347  if (is_array($this->groupBy) && count($this->groupBy) > 0)
348  {
349  $keys = array_keys($this->options);
350  $rc = $this->options[$keys[0]][0];
351  }
352  else
353  {
354  $rc = $this->options[0];
355  }
356 
357  $xref = new $this->xrefClass;
358 
359  $itempk = $this->getMatchingPK($xref, $rc);
360  $pk = $this->getMatchingPK($xref, $obj);
361 
362  $selected = $this->getSelected($obj, $rc, $pk);
363 
364  if ($this->showSelectAll)
365  {
366  echo "<a href='#' onclick='return {$field}_toggleSelectAll(this);'>Select All</a><br/>";
367  }
368  if ($this->width && $this->height)
369  {
370  $resizable = ($this->resizable && !$this->dropdown) ? " resizable": "";
371  $dropdown = $this->dropdown ? " multi_select_dropdown_list" : "";
372  echo "<div id='{$this->parent->id}_{$field}_container' class='selectbox scrollbox{$resizable}{$dropdown}' style='width: {$this->width}px; height: {$this->height}px; overflow: auto'>\n";
373  }
374  else
375  {
376  echo "<div id='{$this->parent->id}_{$field}' class='selectbox'>\n";
377  }
378 
379  $countOptions = count($this->options);
380 
381  if (is_array($this->groupBy) && count($this->groupBy) > 0)
382  {
383  $gpk = $this->groupBy[0]->getPrimaryKey();
384 
385  foreach($this->groupBy as $group)
386  {
387  if (array_key_exists($group->get($gpk), $this->options))
388  {
389  echo $group->format($this->groupByFormat);
390  $this->renderCheckboxes($field, $this->options[$group->get($gpk)], $itempk, $selected, $mode);
391  }
392  }
393  }
394  else if (is_string($this->groupBy))
395  {
396  $options = regroupList($this->options, $this->groupBy);
397 
398  foreach($options as $group => $choices)
399  {
400  echo "<br/><h4>$group</h4>";
401  $this->renderCheckboxes($field, $choices, $itempk, $selected, $mode);
402  }
403  }
404  else
405  {
406  $this->renderCheckBoxes($field, $this->options, $itempk, $selected, $mode);
407  }
408 
409  echo "</div>\n";
410 
411  // Save this count to loop through checkboxes on required validation
412  echo "<input type=\"hidden\" name=\"count_{$field}\" value=\"$countOptions\">";
413 
414  $this->_endField($field);
415  }
416 
417  function renderReadOnly($field = "")
418  {
419  if (count($this->options) == 0) return;
420 
421  $xref = new $this->xrefClass;
422 
423  $obj = $this->parent->data;
424  $pk = $this->getMatchingPK($xref, $obj);
425 
426  if ($obj->get($pk) == "") return;
427 
428 
429  $this->_startField($field);
430 
431  if (is_array($this->groupBy) && count($this->groupBy) > 0)
432  {
433  $gpk = $this->groupBy[0]->getPrimaryKey();
434 
435  foreach($this->groupBy as $group)
436  {
437  if (array_key_exists($group->get($gpk), $this->options))
438  {
439  echo "<span class='cross_reference_group'>".$group->format($this->groupByFormat)."</span>";
440  foreach($this->options[$group->get($gpk)] as $item)
441  {
442  if (array_key_exists($item->$optpk, $items))
443  {
444  echo $this->formatName($item, $this->nameField)."<br/>";
445  }
446  }
447  }
448  }
449  }
450  else
451  {
452  $optpk = $this->getMatchingPK($xref, $this->options[0]);
453 
454  $items = indexedQuery($this->xrefClass, "WHERE {$pk}=".$obj->get($pk), $optpk);
455 
456  foreach($this->options as $item)
457  {
458  if (array_key_exists($item->$optpk, $items))
459  {
460  echo $this->formatName($item, $this->nameField)."<br/>";
461  }
462  }
463  }
464 
465  $this->_endField($field);
466  }
467 
468  function postProcess($field = "")
469  {
470  if (count($this->options) == 0) return;
471 
472  $xref = new $this->xrefClass;
473 
474  $obj = $this->parent->data;
475  $pk = $this->getMatchingPK($xref, $obj);
476 
477  if (is_array($this->groupBy) && count($this->groupBy) > 0)
478  {
479  $keys = array_keys($this->options);
480  $rc = $this->options[$keys[0]][0];
481  }
482  else
483  {
484  $rc = $this->options[0];
485  }
486 
487  $optpk = $this->xrefField ? $this->xrefField : $this->getMatchingPK($xref, $rc);
488 
489  $this->clearOutRelations($obj, $pk);
490 
491  if (isset($_POST[$this->field]))
492  {
493  foreach($_POST[$this->field] as $optionpk => $dummy)
494  {
495  $xref = new $this->xrefClass;
496  $xref->set($pk, $obj->get($pk));
497  $xref->set($optpk, $optionpk);
498  $xref->save();
499  }
500  }
501  }
502 
509  function clearOutRelations($obj, $pk)
510  {
511  $xref = new $this->xrefClass;
512  $xref->delete("WHERE {$pk}=".$obj->get($pk));
513  }
514 }
515 
516 ?>
FieldRenderer is the abstract base class for all FieldRenderers.
_startField($field, $styles="")
Internal method to generate the starting HTML for the field (including the label)
renderField($field)
FieldRenderers must override this method to provide the HTML implementation of the control used to ed...
renderSearchScript($field, $mode)
FieldRenderers can override this method to provide any Javascript that the control requires when bein...
formatName($item, $name)
Formats the given DataItem based on the supplied format string.
_endField($field)
Internal method to generate the closing HTML for the field.
renderScript($field)
FieldRenderers can override this method to provide any Javascript that their control requires for an ...
renderSearchField($field, $mode)
FieldRenderers must override this method to provide the HTML implementation of the control displayed ...
FieldRenderer($parent)
Constructor.
postProcess($field="")
FieldRenderers can override this method to provide behavior that occurs after the parent form's targe...
SearchForm generates forms for searching based on a supplied DataItem.
trace($msg, $lvl=3, $callStack=null)
Send output to the trace log.
Definition: functions.inc:1010
regroupList($list, $field)
Regroup an indexed or grouped query result by a different field.
Definition: data_item.inc:1948
indexedQuery($class)
Performs a query against the database, returning an array of DataItem objects of the specified class,...