CWIS Developer Documentation
SearchParameterSetEditingUI.php
Go to the documentation of this file.
1 <?PHP
2 #
3 # FILE: SearchParameterSetEditingUI.php
4 #
5 # Part of the Collection Workflow Integration System (CWIS)
6 # Copyright 2016 Edward Almasy and Internet Scout Research Group
7 # http://scout.wisc.edu/cwis/
8 #
9 
14 {
24  public function __construct($FormFieldName, $SearchParams = NULL)
25  {
26  $this->EditFormName = $FormFieldName;
27 
28  # iterate over the search parameter set, creating a
29  # flattened representation of it that is easier for printing
30  if ($SearchParams !== NULL)
31  {
32  $this->SearchParams = SPTSearchEngine::ConvertToDisplayParameters(
33  $SearchParams);
34  }
35  else
36  {
37  $this->SearchParams = new SearchParameterSet();
38  }
39 
40  # get the list of fields that are allowed in searches for all schemas
41  $this->MFields = array();
42  $this->AllSchemas = MetadataSchema::GetAllSchemas();
43  foreach ($this->AllSchemas as $SCId => $Schema)
44  {
45  foreach ($Schema->GetFields(NULL, MetadataSchema::MDFORDER_ALPHABETICAL)
46  as $FId => $Field)
47  {
48  if ($Field->IncludeInAdvancedSearch() ||
49  $Field->IncludeInKeywordSearch() )
50  {
51  $this->MFields[]= $Field;
52  }
53  }
54  }
55 
56  $this->Factories = array();
57  }
58 
67  public function DisplayAsTable($TableId = NULL, $TableStyle = NULL)
68  {
69  print('<table id="'.defaulthtmlentities($TableId).'" '
70  .'class="'.defaulthtmlentities($TableStyle).'" '
71  .'style="width: 100%">');
72  $this->DisplayAsRows();
73  print('</table>');
74  }
75 
80  public function DisplayAsRows()
81  {
82 
83  $Fields = $this->FlattenSearchParams(
84  $this->SearchParams);
85 
86  # make sure the necessary javascript is required
87  $GLOBALS["AF"]->RequireUIFile("jquery-ui.js");
88  $GLOBALS["AF"]->RequireUIFile("CW-QuickSearch.js");
89  $GLOBALS["AF"]->RequireUIFile("SearchParameterSetEditingUI.js");
90 
91  # note that all of the fields we create for these rows will be named
92  # $this->EditFormName.'[]' , combining them all into an array of results per
93  # http://php.net/manual/en/faq.html.php#faq.html.arrays
94 
95  # css classes required by our javascript are logic_row
96  # field-row, and field-value-edit
97 
98  $Depth = 0;
99 
100  foreach ($Fields as $FieldRow)
101  {
102  if (is_string($FieldRow) && $FieldRow == "(")
103  {
104  $Depth++;
105  print('<tr><td colspan=2 style="padding-left: 2em;">'
106  .'<input type="hidden" name="'.$this->EditFormName.'[]" '
107  .'value="X-BEGIN-SUBGROUP-X"/>'
108  .'<table class="cw-speui-subgroup">');
109  }
110  elseif (is_string($FieldRow) && $FieldRow == ")")
111  {
112  $Depth--;
113  $this->PrintTemplateRow();
114  print('<input type="hidden" name="'.$this->EditFormName.'[]" '
115  .'value="X-END-SUBGROUP-X"/></table></td></tr>');
116  }
117  elseif (is_array($FieldRow) && isset($FieldRow["Logic"]))
118  {
119  print('<tr class="logic_row '.$this->EditFormName.'">'
120  .'<td colspan="3">'
121  .($Depth==0?'Top-Level Logic: ':'Subgroup with '));
122 
123  $ListName = $this->EditFormName."[]";
124  $Options = array("AND"=>"AND", "OR"=>"OR");
125  $SelectedValue = $FieldRow["Logic"];
126 
127  $OptList = new HtmlOptionList($ListName, $Options, $SelectedValue);
128  $OptList->ClassForList("logic");
129  $OptList->PrintHtml();
130 
131  print (($Depth>0?' Logic':'').'</td></tr>');
132  }
133  elseif (is_array($FieldRow) && isset($FieldRow["FieldId"]) )
134  {
135  $FieldId = $FieldRow["FieldId"];
136  $Values = $FieldRow["Values"];
137  foreach ($Values as $CurVal)
138  {
139  print('<tr class="field-row '.$this->EditFormName.'""
140  ." style="white-space: nowrap;">'
141  ."<td><span class=\"cw-button cw-button-elegant "
142  ."cw-button-constrained cw-speui-delete\">X</span>"
143  ."</td><td>");
144 
145  # for selectable fields, we need to generate all the
146  # html elements that we might need and then depend on
147  # javascript to display only those that are relevant
148 
149  # each field will have four elements
150 
151  # 1. a field selector
152  $this->PrintFieldSelector($FieldId);
153 
154  # 2. a value selector (for option and flag values)
155  $this->PrintValueSelector($FieldId, $CurVal);
156 
157  $SearchText = (StdLib::strpos($CurVal, "=")===0) ?
158  StdLib::substr($CurVal, 1) : $CurVal;
159 
160  # 3. a text entry
161  print('<input type="text" class="field-value-edit" '
162  .'name="'.$this->EditFormName.'[]" '
163  .'placeholder="(search terms)" '
164  .'value="'.defaulthtmlentities($SearchText).'">');
165 
166  # 4. an ajax search box
167  $this->PrintQuicksearch($FieldId, $SearchText);
168 
169  print("</td></tr>");
170  }
171  }
172  }
173 
174  # add a template row, used for adding new fields
175  $this->PrintTemplateRow();
176  }
177 
183  public function GetValuesFromFormData()
184  {
185  if (!isset($_POST[$this->EditFormName]))
186  {
187  $Result = new SearchParameterSet();
188  }
189  else
190  {
191  # set up our result
192  $GroupStack = array();
193  array_push($GroupStack, new SearchParameterSet() );
194 
195  # extract the array of data associated with our EditFormName
196  $FormData = $_POST[$this->EditFormName];
197 
198  # extract and set the search logic, which is always the first
199  # element in the HTML that we generate
200  $Logic = array_shift($FormData);
201  end($GroupStack)->Logic($Logic);
202 
203  while (count($FormData))
204  {
205  # first element of each row is a field id
206  $FieldId = array_shift($FormData);
207 
208  if ($FieldId == "X-BEGIN-SUBGROUP-X")
209  {
210  # add a new subgroup to our stack of subgroups
211  array_push($GroupStack, new SearchParameterSet());
212  # extract and set the search logic
213  $Logic = array_shift($FormData);
214  end($GroupStack)->Logic($Logic);
215  }
216  elseif ($FieldId == "X-END-SUBGROUP-X")
217  {
218  $Subgroup = array_pop($GroupStack);
219  end($GroupStack)->AddSet($Subgroup);
220  }
221  else
222  {
223  # for selectable fields, we'll have all possible
224  # elements and will need to grab the correct ones for
225  # the currently selected field
226  $SelectVal = array_shift($FormData);
227  $TextVal = array_shift($FormData);
228  $SearchVal = array_shift($FormData);
229 
230  if ($FieldId == "X-KEYWORD-X")
231  {
232  $Val = $TextVal;
233  $Field = NULL;
234 
235  if (strlen($TextVal)==0)
236  {
237  continue;
238  }
239  }
240  else
241  {
242  $Field = new MetadataField($FieldId);
243 
244  # make sure we have factories for field types that need them
245  switch ($Field->Type())
246  {
250  if (!isset($this->Factories[$FieldId]))
251  {
252  $this->Factories[$FieldId] = $Field->GetFactory();
253  }
254  break;
255 
256  default:
257  break;
258  }
259 
260  # verify that we actually have a value for our selected field
261  switch ($Field->Type())
262  {
270  # if we have no value for this field, skip displaying it
271  if (strlen($TextVal)==0)
272  {
273  continue 2;
274 
275  }
276  break;
277 
280  # if we have no value for this field, skip displaying it
281  if (strlen($SearchVal)==0)
282  {
283  continue 2;
284  }
285  break;
286 
287  # no need to check the types where there's
288  # a SelectVal, as that cannot be left empty
289  default:
290  break;
291  }
292 
293  # extract the value for our field
294  switch ($Field->Type())
295  {
302  $Val = $TextVal;
303  break;
304 
306  $Val = "=".$TextVal;
307  break;
308 
310  $Item = $this->Factories[$FieldId]->GetItem(
311  $SearchVal);
312 
313  # for tree fields, use the same 'is X
314  # or a child of X' construction that we
315  # use when generating search facets
316  $Val = new SearchParameterSet();
317  $Val->Logic("OR");
318  $Val->AddParameter(array(
319  "=".$Item->Name(),
320  "^".$Item->Name()." -- "), $Field);
321  break;
322 
324  $Item = $this->Factories[$FieldId]->GetItem(
325  $SearchVal);
326  $Val = "=".$Item->Name();
327  break;
328 
330  $Item = $this->Factories[$FieldId]->GetItem(
331  $SelectVal);
332  $Val = "=".$Item->Name();
333  break;
334 
336  $Val = $SelectVal;
337  break;
338 
339  default:
340  throw new Exception("Unsupported field type");
341  }
342  }
343 
344  # add our value to the search parameters
345  if ($Val instanceof SearchParameterSet)
346  {
347  end($GroupStack)->AddSet($Val);
348  }
349  else
350  {
351  end($GroupStack)->AddParameter($Val, $Field);
352  }
353  }
354  }
355 
356  $Result = array_pop($GroupStack);
357  }
358 
359  # set internal search params to the "Display" version, as these
360  # are the ones we shall use for display
361  $this->SearchParams = SPTSearchEngine::ConvertToDisplayParameters($Result);
362  return $Result;
363  }
364 
370  public function SearchParameters($SearchParams = NULL)
371  {
372  if ($SearchParams !== NULL)
373  {
374  $this->SearchParams = clone $SearchParams;
375  }
376 
377  return clone $this->SearchParams;
378  }
379 
390  public function MaxFieldLabelLength($NewValue = NULL)
391  {
392  if (!is_null($NewValue))
393  {
394  $this->MaxFieldLabelLength = $NewValue;
395  }
396  return $this->MaxFieldLabelLength;
397  }
398 
409  public function MaxValueLabelLength($NewValue = NULL)
410  {
411  if (!is_null($NewValue))
412  {
413  $this->MaxValueLabelLength = $NewValue;
414  }
415  return $this->MaxValueLabelLength;
416  }
417 
418 
419  # ---- PRIVATE INTERFACE -------------------------------------------------
420 
421  private $EditFormName;
422  private $SearchParams;
423  private $MFields;
424  private $AllSchemas;
425  private $Factories;
426  private $MaxFieldLabelLength = 0;
427  private $MaxValueLabelLength = 0;
428 
440  private function FlattenSearchParams($SearchParams)
441  {
442  $Result = array();
443 
444  $Result[]= array(
445  "Logic" => $SearchParams->Logic() );
446 
447  $SearchStrings = $SearchParams->GetSearchStrings();
448  foreach ($SearchStrings as $FieldId => $Values)
449  {
450  $Result[]= array(
451  "FieldId" => $FieldId,
452  "Values" => $Values);
453  }
454 
455  $KeywordStrings = $SearchParams->GetKeywordSearchStrings();
456  if (count($KeywordStrings))
457  {
458  $Result[]= array(
459  "FieldId" => "X-KEYWORD-X",
460  "Values" => $KeywordStrings);
461  }
462 
463  $Subgroups = $SearchParams->GetSubgroups();
464  if (count($Subgroups))
465  {
466  foreach ($Subgroups as $Subgroup)
467  {
468  $Result[]= "(";
469  $SubgroupItems = $this->FlattenSearchParams($Subgroup);
470  foreach ($SubgroupItems as $Item)
471  {
472  $Result[] = $Item;
473  }
474  $Result[]= ")";
475  }
476  }
477 
478  return $Result;
479  }
480 
485  private function PrintFieldSelector($FieldId)
486  {
487  $ListName = $this->EditFormName."[]";
488  $SelectedValue = array();
489 
490  # "Keyword" option is always here
491  $Options["X-KEYWORD-X"] = "Keyword";
492  $OptionClass["X-KEYWORD-X"] = "field-type-keyword";
493  if ($FieldId == "X-KEYWORD-X")
494  {
495  $SelectedValue[] = "X-KEYWORD-X";
496  }
497 
498  # prepare options for print
499  foreach ($this->MFields as $MField)
500  {
501  $TypeName = defaulthtmlentities(
502  str_replace(' ', '', strtolower($MField->TypeAsName())));
503 
504  if (!$MField->Optional())
505  {
506  $TypeName .= " required";
507  }
508 
509  $FieldName = $MField->Name();
510  if ($MField->SchemaId() != MetadataSchema::SCHEMAID_DEFAULT)
511  {
512  $FieldName = $this->AllSchemas[$MField->SchemaId()]->Name()
513  .": ".$FieldName;
514  }
515 
516  $Options[$MField->Id()] = defaulthtmlentities($FieldName);
517  $OptionClass[$MField->Id()] = "field-type-".$TypeName;
518 
519  if ($FieldId == $MField->Id())
520  {
521  $SelectedValue[] = $MField->Id();
522  }
523  }
524 
525  # instantiate option list and print
526  $OptList = new HtmlOptionList($ListName, $Options, $SelectedValue);
527  $OptList->ClassForList("field-subject");
528  $OptList->ClassForOptions($OptionClass);
529  $OptList->MaxLabelLength($this->MaxFieldLabelLength);
530  $OptList->PrintHtml();
531  }
532 
533 
539  private function PrintValueSelector($FieldId, $CurVal)
540  {
541  # parameters of the option list
542  $ListName = $this->EditFormName."[]";
543  $Options = array();
544  $OptionClass = array();
545  $SelectedValue = array();
546 
547  # prepare options for print
548  foreach ($this->MFields as $MField)
549  {
550  if ($MField->Type() == MetadataSchema::MDFTYPE_FLAG ||
551  $MField->Type() == MetadataSchema::MDFTYPE_OPTION)
552  {
553  foreach ($MField->GetPossibleValues() as $Id => $Val)
554  {
555  $IsSelected = $MField->Id() == $FieldId &&
556  strlen($CurVal) > 1 && $CurVal[0] == "=" &&
557  substr($CurVal, 1) == $Val ;
558 
559  $Options[$Id] = defaulthtmlentities($Val);
560  $OptionClass[$Id] = "field-id-".$MField->Id();
561 
562  if ($IsSelected)
563  {
564  $SelectedValue[] = $Id;
565  }
566  }
567  }
568  }
569 
570  # instantiate an option list and print
571  $OptList = new HtmlOptionList($ListName, $Options, $SelectedValue);
572  $OptList->ClassForList("field-value-select");
573  $OptList->ClassForOptions($OptionClass);
574  $OptList->MaxLabelLength($this->MaxValueLabelLength);
575  $OptList->PrintHtml();
576  }
577 
583  private function PrintQuicksearch($FieldId, $CurVal)
584  {
585  if ($FieldId !== NULL && $FieldId != "X-KEYWORD-X")
586  {
587  if (!isset($this->Factories[$FieldId]))
588  {
589  $Field = new MetadataField($FieldId);
590  $Factory = $Field->GetFactory();
591 
592  $this->Factories[$FieldId] =
593  ($Factory !== NULL) ? $Factory : FALSE;
594  }
595 
596  $ItemId = ($this->Factories[$FieldId] !== FALSE) ?
597  $this->Factories[$FieldId]->GetItemIdByName($CurVal) : "" ;
598  }
599  else
600  {
601  $ItemId = "";
602  }
603 
604  # field-value-qs css class required by our javascript.
605  # various cw-quicksearch classes required by the quicksearch javascript
606  # and ui-front class required by jquery-ui, used by qs js
607  print('<div class="field-value-qs cw-quicksearch '
608  . 'cw-quicksearch-template">'
609  .'<input class="cw-quicksearch-display '
610  .'cw-resourceeditor-metadatafield" '
611  .'placeholder="(enter some text to begin searching)" '
612  .'value="'.defaulthtmlentities($CurVal).'" />'
613  .'<input name="'.$this->EditFormName.'[]" '
614  .'class="cw-quicksearch-value" type="hidden" '
615  .'value="'.defaulthtmlentities($ItemId).'" />'
616  .'<div style="display: none;" '
617  .'class="cw-quicksearch-menu">'
618  .'<div class="cw-quicksearch-message ui-front"></div>'
619  .'</div></div>');
620  }
621 
625  private function PrintTemplateRow()
626  {
627  # field-row, template-row, field-value-edit, cw-speui-add, and
628  # cw-speui-add-subgroup css classes required by our javascript
629  print(
630  "<tr class=\"field-row template-row ".$this->EditFormName."\""
631  ." style=\"white-space: nowrap;\">"
632  ."<td>"
633  ."<span class=\"cw-button cw-button-elegant cw-button-constrained "
634  ."cw-speui-delete\">X</span>"
635  ."</td><td>");
636  $this->PrintFieldSelector(NULL);
637  $this->PrintValueSelector(NULL, "");
638  print("<input type=\"text\" class=\"field-value-edit\" "
639  ."name=\"".$this->EditFormName."[]\" placeholder=\"(search terms)\" "
640  ."value=\"\">");
641  $this->PrintQuicksearch(NULL, "");
642  print("</td></tr>");
643  print("<tr><td colspan=2>"
644  ."<span class=\"cw-button cw-button-elegant cw-button-constrained "
645  ."cw-speui-add\">Add Field</span>"
646  ."<span class=\"cw-button cw-button-elegant cw-button-constrained "
647  ."cw-speui-add-subgroup\">Add Subgroup</span>"
648  ."</td></tr>");
649  }
650 }
GetValuesFromFormData()
Extract values from a dynamics field edit/modification form.
DisplayAsRows()
Display the table rows for the editing form, without the surrounding.
SearchParameters($SearchParams=NULL)
Get/Set search parameters.
const MDFORDER_ALPHABETICAL
Set of parameters used to perform a search.
DisplayAsTable($TableId=NULL, $TableStyle=NULL)
Display editing form elements enclosed in a.
MaxValueLabelLength($NewValue=NULL)
Get/set the max number of characters a label of a value option list will be displayed.
static strpos()
Multibyte-aware (if supported in PHP) version of strpos().
Definition: StdLib.php:529
__construct($FormFieldName, $SearchParams=NULL)
Create a UI for specifing edits to SearchParameterSets.
const MDFTYPE_CONTROLLEDNAME
static substr()
Multibyte-aware (if supported in PHP) version of substr().
Definition: StdLib.php:520
MaxFieldLabelLength($NewValue=NULL)
Get/set the max number of characters a label of a field option list will be displayed.
Object representing a locally-defined type of metadata field.
static ConvertToDisplayParameters($SearchParams)
Get a simplified SearchParameterSet for display purposes.
static GetAllSchemas()
Get all existing metadata schemas.
Convenience class for generating an HTML select/option form element.
Class to create a user interface for editing SearchParameterSets.