3 # FILE: FormUI_Base.php 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/ 16 # ---- PUBLIC INTERFACE -------------------------------------------------- 47 # make sure parameters are legal and complete 48 $BooleanParams = array(
56 if (!isset($Params[
"Type"]))
58 $ErrMsgs[] =
"Type missing for form field ".$FieldName.
".";
60 elseif (($Params[
"Type"] == self::FTYPE_OPTION)
61 && !isset($Params[
"Options"]))
63 $ErrMsgs[] =
"Option values missing for form field ".$FieldName.
".";
65 if (!isset($Params[
"Label"]))
67 $ErrMsgs[] =
"Label missing for form field ".$FieldName.
".";
69 if (isset($Params[
"ValidateFunction"])
70 && !is_callable($Params[
"ValidateFunction"]))
72 $ErrMsgs[] =
"Uncallable validation function for form field " 75 if (isset($Params[
"InsertIntoField"])
78 $ErrMsgs[] =
"Unknown insertion field (".$Params[
"InsertIntoField"]
79 .
") found for form field ".$FieldName.
".";
81 foreach ($BooleanParams as $ParamName)
83 if (!isset($Params[$ParamName]))
91 $ErrMsgString = implode(
" ", $ErrMsgs);
92 throw new InvalidArgumentException($ErrMsgString);
95 # save form parameters and values 98 $this->UniqueKey = $UniqueKey;
106 abstract public function DisplayFormTable($TableId = NULL, $TableStyle = NULL);
114 public static function LogError($Msg, $Field = NULL)
116 self::$ErrorMessages[$Field][] = $Msg;
127 return self::$ErrorMessages;
138 if ($Field === FALSE)
140 return count(self::$ErrorMessages) ? TRUE : FALSE;
144 return isset(self::$ErrorMessages[$Field]) ? TRUE : FALSE;
154 if ($Field === FALSE)
156 self::$ErrorMessages = array();
160 unset(self::$ErrorMessages[$Field]);
173 # retrieve field values 178 foreach ($this->FieldParams as $Name => $Params)
181 if ($Params[
"Type"] == self::FTYPE_HEADING) {
continue; }
183 # determine if field has a value set 184 switch ($Params[
"Type"])
186 case self::FTYPE_SEARCHPARAMS:
187 $IsEmpty = !$Values[$Name]->ParameterCount();
190 case self::FTYPE_PRIVILEGES:
191 $IsEmpty = !$Values[$Name]->ComparisonCount();
195 if (is_array($Values[$Name]))
197 $IsEmpty = !count($Values[$Name]);
201 $IsEmpty = !strlen(trim($Values[$Name]));
206 # if field has validation function 207 if (isset($Params[
"ValidateFunction"]))
209 # swap in our object if this is one of our methods 210 $VFunc = $Params[
"ValidateFunction"];
211 if (is_array($VFunc) && ($VFunc[0] ==
"FormUI"))
216 # call validation function for value 217 $Args = array_merge(array($Name, $Values[$Name], $Values),
218 $this->ExtraValidationParams);
219 $ErrMsg = call_user_func_array($VFunc, $Args);
220 if ($ErrMsg === FALSE)
222 throw new Exception(
"Calling validation function for" 223 .
" parameter \"".$Name.
"\" failed.");
226 # log any resulting error 227 if ($ErrMsg !== NULL)
229 self::LogError($ErrMsg, $Name);
234 # if field is required and empty 235 if ($IsEmpty && isset($Params[
"Required"]) && $Params[
"Required"])
237 # log error to indicate required value is missing 238 self::LogError(
"<i>".$Params[
"Label"].
"</i> is required.", $Name);
241 # else validate based on field type 244 switch ($Params[
"Type"])
246 case self::FTYPE_NUMBER:
247 # make sure value is within any specified range 248 if ((isset($Params[
"MinVal"])
249 && ($Values[$Name] < $Params[
"MinVal"]))
250 || (isset($Params[
"MaxVal"])
251 && ($Values[$Name] > $Params[
"MaxVal"])))
253 if (!isset($Params[
"MaxVal"]))
255 self::LogError(
"<i>".$Params[
"Label"].
"</i> must be " 256 .$Params[
"MinVal"].
" or greater.", $Name);
258 elseif (!isset($Params[
"MinVal"]))
260 self::LogError(
"<i>".$Params[
"Label"].
"</i> must be " 261 .$Params[
"MaxVal"].
" or less.", $Name);
265 self::LogError(
"<i>".$Params[
"Label"].
"</i> must be" 266 .
" in the range ".$Params[
"MinVal"]
267 .
" to ".$Params[
"MaxVal"].
".", $Name);
273 case self::FTYPE_URL:
274 # make sure URL entered looks valid 275 if (!$IsEmpty && (filter_var(
276 $Values[$Name], FILTER_VALIDATE_URL) === FALSE))
278 self::LogError(
"Value \"".$Values[$Name]
279 .
"\" does not appear to be a valid URL for <i>" 280 .$Params[
"Label"].
"</i>.", $Name);
285 case self::FTYPE_USER:
286 # make sure user name entered is valid 288 if (!$UFactory->UserNameExists($Values[$Name]))
290 self::LogError(
"User name \"".$Values[$Name]
291 .
"\" not found for <i>" 292 .$Params[
"Label"].
"</i>.", $Name);
300 # report number of fields with invalid values found to caller 311 $this->ExtraValidationParams = func_get_args();
321 # for each form field 322 $NewSettings = array();
323 foreach ($this->FieldParams as $Name => $Params)
326 if ($Params[
"Type"] == self::FTYPE_HEADING) {
continue; }
328 # determine form field name (matches mechanism in HTML) 330 ($Params[
"Type"] != self::FTYPE_PRIVILEGES));
332 # assume the value will not change 333 $DidValueChange = FALSE;
334 $OldValue = isset($this->FieldValues[$Name])
335 ? $this->FieldValues[$Name]
336 : (isset($Params[
"Value"]) ? $Params[
"Value"] : NULL);
337 $NewSettings[$Name] = $OldValue;
339 # retrieve value based on configuration parameter type 340 switch ($Params[
"Type"])
342 case self::FTYPE_FLAG:
343 # if radio buttons were used 344 if (array_key_exists(
"OnLabel", $Params)
345 && array_key_exists(
"OffLabel", $Params))
347 if (isset($_POST[$FieldName]))
349 $NewValue = ($_POST[$FieldName] ==
"1") ? TRUE : FALSE;
351 # flag that the values changed if they did 352 $DidValueChange = self::DidValueChange(
353 $OldValue, $NewValue);
355 $NewSettings[$Name] = $NewValue;
358 # else checkbox was used 361 $NewValue = isset($_POST[$FieldName]) ? TRUE : FALSE;
363 # flag that the values changed if they did 364 $DidValueChange = self::DidValueChange($OldValue, $NewValue);
366 $NewSettings[$Name] = $NewValue;
370 case self::FTYPE_OPTION:
371 $NewValue = GetArrayValue($_POST, $FieldName, array());
373 # flag that the values changed if they did 374 $DidValueChange = self::DidValueChange($OldValue, $NewValue);
376 $NewSettings[$Name] = $NewValue;
379 case self::FTYPE_METADATAFIELD:
380 $NewValue = GetArrayValue($_POST, $FieldName, array());
381 if ($NewValue ==
"-1") { $NewValue = array(); }
383 # flag that the values changed if they did 384 $DidValueChange = self::DidValueChange($OldValue, $NewValue);
386 $NewSettings[$Name] = $NewValue;
389 case self::FTYPE_PRIVILEGES:
390 $Schemas = GetArrayValue($Params,
"Schemas");
391 $MFields = GetArrayValue($Params,
"MetadataFields", array());
393 $NewValues = $PEditor->GetPrivilegeSetsFromForm();
394 $NewValue = $NewValues[$FieldName];
395 $DidValueChange = self::DidValueChange($OldValue, $NewValue);
396 $NewSettings[$Name] = $NewValue;
399 case self::FTYPE_SEARCHPARAMS:
401 $NewValue = $SPEditor->GetValuesFromFormData();
402 $DidValueChange = self::DidValueChange($OldValue, $NewValue);
403 $NewSettings[$Name] = $NewValue;
406 case self::FTYPE_IMAGE:
407 $NewSettings[$Name] = GetArrayValue(
408 $_POST, $FieldName.
"_ID", array());
409 foreach ($NewSettings[$Name] as $Index => $ImageId)
411 if ($ImageId == self::NO_VALUE_FOR_FIELD)
413 unset($NewSettings[$Name][$Index]);
415 if (isset($_POST[$FieldName.
"_AltText_".$ImageId]))
418 $Image->AltText($_POST[$FieldName.
"_AltText_".$ImageId]);
424 if (isset($_POST[$FieldName]))
426 $NewValue = $_POST[$FieldName];
428 # flag that the values changed if they did 429 $DidValueChange = self::DidValueChange($OldValue, $NewValue);
431 $NewSettings[$Name] = $NewValue;
436 # if value changed and there is an event to signal for changes 437 if ($DidValueChange && $this->SettingChangeEventName)
439 # set info about changed value in event parameters if appropriate 441 foreach ($EventParams as $ParamName => $ParamValue)
446 $EventParams[$ParamName] = $Name;
450 $EventParams[$ParamName] = $OldValue;
454 $EventParams[$ParamName] = $NewValue;
460 $GLOBALS[
"AF"]->SignalEvent(
461 $this->SettingChangeEventName, $EventParams);
465 # return updated setting values to caller 476 # get base form field name 477 $FieldType = $this->FieldParams[$FieldName][
"Type"];
479 ($FieldType != self::FTYPE_PRIVILEGES));
481 # get fallback value for field (in case no value from form) 482 if (isset($this->FieldValues[$FieldName]))
484 $Value = $this->FieldValues[$FieldName];
486 elseif (isset($this->FieldParams[$FieldName][
"Value"]))
488 $Value = self::LoadValue($FieldType,
489 $this->FieldParams[$FieldName][
"Value"]);
491 elseif (isset($this->FieldParams[$FieldName][
"Default"]))
493 $Value = self::LoadValue($FieldType,
494 $this->FieldParams[$FieldName][
"Default"]);
498 $Value = self::LoadValue($FieldType, NULL);
503 case self::FTYPE_IMAGE:
504 # get name of image ID form field 505 $ImgIdFieldName = $FormFieldName.
"_ID";
507 # use an updated value for this field if available 508 if (isset($this->HiddenFields[$ImgIdFieldName]))
510 $Value = $this->HiddenFields[$ImgIdFieldName];
512 # else use a value from form if available 513 elseif (isset($_POST[$ImgIdFieldName]))
515 $Value = $_POST[$ImgIdFieldName];
518 # add in any previously-set extra values 519 if (isset($this->ExtraValues[$ImgIdFieldName])
520 && count($this->ExtraValues[$ImgIdFieldName]))
522 if (!is_array($Value))
524 $Value = array($Value);
526 $Value = array_merge($Value,
527 $this->ExtraValues[$ImgIdFieldName]);
531 case self::FTYPE_SEARCHPARAMS:
532 # use incoming form value if available 533 if (isset($_POST[$FormFieldName]))
535 # use incoming form value 537 $Value = $SPEditor->GetValuesFromFormData();
541 case self::FTYPE_PRIVILEGES:
542 # use incoming form value if available 543 $Schemas = GetArrayValue(
544 $this->FieldParams[$FieldName],
"Schemas");
545 $MFields = GetArrayValue(
546 $this->FieldParams[$FieldName],
"MetadataFields", array());
548 $PSet = $PEditor->GetPrivilegeSetFromForm($FormFieldName);
551 # use incoming form value 557 # use incoming form value if available 558 if (isset($_POST[$FormFieldName]))
560 # use incoming form value 561 $Value = $_POST[$FormFieldName];
566 # return value found to caller 575 # for each form field 576 foreach ($this->FieldParams as $FieldName =>
$FieldParams)
578 # move on to next field if this field does not allow uploads 584 # move on to next field if this field does not have an uploaded file 586 if (!isset($_FILES[$FormFieldName][
"name"]))
590 $UploadedFileName = $_FILES[$FormFieldName][
"name"];
591 if (!strlen($UploadedFileName))
596 # create temp copy of file with correct name 597 $TmpFile =
"tmp/".$UploadedFileName;
598 copy($_FILES[$FormFieldName][
"tmp_name"], $TmpFile);
602 case self::FTYPE_IMAGE:
603 # create new image object from uploaded file 612 # check for errors during image object creation 613 if ($Image->Status() !=
AI_OKAY)
615 switch ($Image->Status())
618 $this->
LogError(
"Unknown format for file " 619 .$UploadedFileName.
".", $FieldName);
623 $this->
LogError(
"Unsupported format for file " 624 .$UploadedFileName.
" (" 625 .$Image->Format().
").", $FieldName);
629 $this->
LogError(
"Error encountered when" 630 .
" processing uploaded image file " 631 .$UploadedFileName.
".", $FieldName);
638 # set image object alternate text 639 $Image->AltText($_POST[$FormFieldName.
"_AltText_NEW"]);
641 # add image ID to extra values 642 $this->ExtraValues[$FormFieldName.
"_ID"][] = $Image->Id();
653 # if deleted image ID is available 656 $IncomingValue = GetFormValue($DeleteFieldName);
657 if (is_numeric($IncomingValue)
658 || (is_array($IncomingValue) && count($IncomingValue)))
660 # retrieve ID of image 661 $ImageId = is_array($IncomingValue)
662 ? array_shift($IncomingValue)
665 # add ID to deleted images list 666 $this->DeletedImages[] = $ImageId;
683 $this->SettingChangeEventName = $EventName;
684 $this->SettingChangeEventParams = $EventParams;
695 # didn't change if they are identical 696 if ($OldValue === $NewValue)
701 # need special cases from this point because PHP returns some odd results 702 # when performing loose equality comparisons: 703 # http://php.net/manual/en/types.comparisons.php#types.comparisions-loose 705 # consider NULL and an empty string to be the same. this is in case a field 706 # is currently set to NULL and receives an empty value from the form. 707 # $_POST values are always strings 708 if ((is_null($OldValue) && is_string($NewValue) && !strlen($NewValue))
709 || (is_null($NewValue) && is_string($OldValue) && !strlen($OldValue)))
714 # if they both appear to be numbers and are equal 715 if (is_numeric($OldValue) && is_numeric($NewValue) && $OldValue == $NewValue)
721 if (($OldValue === TRUE && ($NewValue === 1 || $NewValue ===
"1"))
722 || ($NewValue === TRUE && ($OldValue === 1 || $OldValue ===
"1")))
728 if (($OldValue === FALSE && ($NewValue === 0 || $NewValue ===
"0"))
729 || ($NewValue === FALSE && ($OldValue === 0 || $OldValue ===
"0")))
735 if (is_array($OldValue) && is_array($NewValue))
737 # they certainly changed if the counts are different 738 if (count($OldValue) != count($NewValue))
743 # the algorithm for associative arrays is slightly different from 744 # sequential ones. the values for associative arrays must match the keys 745 if (count(array_filter(array_keys($OldValue),
"is_string")))
747 foreach ($OldValue as $Key => $Value)
749 # it changed if the keys don't match 750 if (!array_key_exists($Key, $NewValue))
755 # the arrays changed if a value changed 756 if (self::DidValueChange($Value, $NewValue[$Key]))
763 # sequential values don't have to have the same keys, just the same 767 # sort them so all the values match up if they're equal 771 foreach ($OldValue as $Key => $Value)
773 # the arrays changed if a value changed 774 if (self::DidValueChange($Value, $NewValue[$Key]))
781 # the arrays are equal 799 case self::FTYPE_IMAGE:
800 $Value = ($Data === NULL) ? array() : $Data;
803 case self::FTYPE_PRIVILEGES:
808 case self::FTYPE_SEARCHPARAMS:
838 if (trim($Value) ==
"") {
continue; }
839 if (filter_var($Value, FILTER_VALIDATE_EMAIL) === FALSE)
841 return "The value for <i>".$this->FieldParams[$FieldName][
"Label"]
842 .
"</i> does not appear to be a valid email address.";
865 if (trim($Value) ==
"") {
continue; }
866 if (filter_var($Value, FILTER_VALIDATE_URL) === FALSE)
868 return "The value for <i>".$this->FieldParams[$FieldName][
"Label"]
869 .
"</i> does not appear to be a valid URL.";
893 if (trim($Value) ==
"") {
continue; }
894 if (gethostbyname($Value) === $Value)
896 return "The value for <i>".$this->FieldParams[$FieldName][
"Label"]
897 .
"</i> does not appear to be a valid host name.";
904 # ---- PRIVATE INTERFACE ------------------------------------------------- 937 return ($IncludePrefix ?
"F_" :
"")
938 .($this->UniqueKey ? $this->UniqueKey.
"_" :
"")
939 .preg_replace(
"/[^a-zA-Z0-9]/",
"", $FieldName);
948 if (count($this->HiddenFields))
950 foreach ($this->HiddenFields as $FieldName => $Value)
952 if (is_array($Value))
954 foreach ($Value as $EachValue)
956 $Html .=
'<input type="hidden" name="'.$FieldName
957 .
'[]" value="'.htmlspecialchars($EachValue).
'">';
962 $Html .=
'<input type="hidden" name="'.$FieldName
963 .
'[]" id="'.$FieldName.
'" value="' 964 .htmlspecialchars($Value).
'">';
Set of parameters used to perform a search.
User interface element for editing PrivilegeSets.
Set of privileges used to access resource information or other parts of the system.
CWIS-specific user factory class.
Encapsulates a full-size, preview, and thumbnail image.
Class to create a user interface for editing SearchParameterSets.
const AI_UNSUPPORTEDFORMAT