/**
  * Populate the history of entries for the form field if the storage module handles history.
  * @param I2CE_FormField $form_field
  * @return boolean
  */
 public function FF_populateHistory($form_field)
 {
     $field = $form_field->getName();
     $form = $form_field->getContainer();
     if (!$form instanceof I2CE_Form) {
         return false;
     }
     $fieldQry = $this->getRequiredFieldsQuery($form->getName(), array($field), $form->getId());
     $result = $this->db->getRow($fieldQry);
     if (I2CE::pearError($result, "Error populating field {$field} of form " . $form->getName())) {
         return false;
     }
     $ref = strtolower($form->getName() . '+' . $field);
     $entry = new I2CE_Entry(I2CE_Date::blank(), 1, 0, $form_field->getFromDB($result->{$ref}));
     $form_field->addHistory($entry);
     return true;
 }
 /**
  * Populate the history of entries for the form field if the storage module handles history.
  * @param I2CE_FormField $form_field
  * @return boolean
  */
 public function FF_populateHistory($form_field)
 {
     $field = $form_field->getName();
     $form = $form_field->getContainer();
     if (!$form instanceof I2CE_Form) {
         return false;
     }
     $field_name = $form_field->getName();
     $fields = $this->lookupField($form->getName(), $form->getId(), array($field_name), false);
     if (!is_array($fields) || !array_key_exists($field_name, $fields)) {
         //no data to populate
         return true;
     }
     $last_modified = I2CE_Date::blank();
     $entry = new I2CE_Entry($last_modified, 1, 0, $form_field->getFromDB($fields[$field_name]));
     $form_field->addHistory($entry);
     return true;
 }
 /**
  * update value of each  instance  of a given form field by a sql  function call
  * @param I2CE_FormField $form_field
  * @param array $where Array of where data
  * @param string $set_sql sql used to update the field
  */
 public function globalFieldUpdateBySQL($form_field, $where, $set_sql)
 {
     if (!$form_field instanceof I2CE_FormField) {
         I2CE::raiseError("Not passed form_field");
         return false;
     }
     $formObj = $form_field->getContainer();
     if (!$formObj instanceof I2CE_Form) {
         I2CE::raiseError("No form as a container for the form field");
         return false;
     }
     $form = $formObj->getName();
     if (!$set_sql) {
         I2CE::raiseError("No SQL provided to update {$form}+{$field}");
         return false;
     }
     $sub_qry = $this->getRequiredFieldsQuery($form, array($form_field->getName()));
     $where_qry = $formObj->generateWhereClause($where);
     if (!$where_qry) {
         I2CE::raiseError("Could not gernerate where clasue for {$form} by\n" . print_r($where, true));
         return false;
     }
     $qry = "UPDATE config_alt JOIN ({$sub_qry}) AS data  " . "ON  parent = CONCAT( '/I2CE/formsData/forms/{$form}/', `{$form}+id` , '/fields' ) " . "SET value = {$set_sql} " . " WHERE (name = '" . $form_field->getName() . "' AND ({$where_qry}))";
     //I2CE::raiseError("Updating by $qry");
     $res = $this->db->exec($qry);
     I2CE::getConfig()->clearCache(false);
     //since we did a write to the DB, need to clear cache
     if (I2CE::pearError("Cannot update by:\n{$qry}", $res)) {
         return false;
     }
     return true;
 }
 /**
  * Get/prepare the prepared statement for the given field obj
  * @param I2CE_FormField $fieldObj
  * @returns mixed.  false om failure.  a mdb2 preapred statement object on success
  */
 protected function getFieldSave($fieldObj)
 {
     $formName = $fieldObj->getContainer()->getName();
     $fieldName = $fieldObj->getName();
     if (!array_key_exists($formName, $this->fieldSaves)) {
         $this->fieldSaves[$formName] = array();
     }
     if (!array_key_exists($fieldName, $this->fieldSaves[$formName])) {
         $cols = $this->getSaveColumns($fieldObj->getContainer());
         $table = $this->getTable($formName);
         if (!$table || !array_key_exists($fieldName, $cols)) {
             $this->fieldSaves[$formName][$fieldName] = false;
             return false;
         }
         $stmt = "UPDATE {$table} SET `{$cols[$fieldName]}` = ? WHERE `{$cols['id']}` = ?";
         $prepStmt = $this->db->prepare($stmt, array($fieldObj->getMDB2Type(), 'text'), MDB2_PREPARE_MANIP);
         if (I2CE::pearError($prepStmt, "Error preparing save statemnt for " . $fieldObj->getName() . "\n" . $stmt)) {
             $prepStmt = false;
         }
         $this->fieldSaves[$formName][$fieldName] = $prepStmt;
     }
     return $this->fieldSaves[$formName][$fieldName];
 }
 /**
  * Hooked Function to check if a field is unique or unique restricted to a certain field
  * @param I2CE_FormField $field_obj
  * @returns boolean
  */
 public function validate_formfield($field_obj)
 {
     if (!$field_obj->hasOption('unique') || !$field_obj->getOption('unique') || !$field_obj->isValid() || !$field_obj->issetValue() || $field_obj->getDBValue() == "") {
         return;
     }
     $where = array('operator' => 'FIELD_LIMIT', 'style' => 'equals', 'field' => $field_obj->getName(), 'data' => array('value' => $field_obj->getDBValue()));
     $form_obj = $field_obj->getContainer();
     if (!$form_obj instanceof I2CE_Form) {
         I2CE::raiseError(get_class($form_obj));
         return;
     }
     $names = array();
     $search_parent = false;
     if ($field_obj->hasOption('unique_field')) {
         $unique = $field_obj->getOption('unique_field');
         if (strpos($unique, ':') !== false) {
             //the value is a mapped thing.  this is handled by hooked mehtod defined in I2CE_Module_List
             return;
         }
         $unique_fields = explode(',', $unique);
         $unique_where = array($where);
         foreach ($unique_fields as $unique_field) {
             if ($unique_field == "parent") {
                 $search_parent = $form_obj->getParent();
                 if ($search_parent == "") {
                     // If there is no parent then we can't validate
                     // by parent so ignore this
                     return;
                 }
                 continue;
             }
             if (!($unique_field_obj = $form_obj->getField($unique_field)) instanceof I2CE_FormField) {
                 I2CE::raiseError("Invalid field {$unique_field}");
                 return;
             }
             if ($unique_field_obj->hasHeader('default')) {
                 $names[] = $unique_field_obj->getHeader('default');
             } else {
                 $names[] = $unique_field_obj->getName();
             }
             if ($unique_field_obj->isValid()) {
                 $unique_where[] = array('operator' => 'FIELD_LIMIT', 'style' => 'equals', 'field' => $unique_field_obj->getName(), 'data' => array('value' => $unique_field_obj->getDBValue()));
             } else {
                 $unique_where[] = array('operator' => 'OR', 'operand' => array(0 => array('operator' => 'FIELD_LIMIT', 'style' => 'equals', 'field' => $unique_field_obj->getName(), 'data' => array('value' => $unique_field_obj->getDBValue())), 1 => array('operator' => 'FIELD_LIMIT', 'style' => 'null', 'field' => $unique_field_obj->getName())));
             }
         }
         if (count($unique_where) > 1) {
             //we added somehitng
             $where = array('operator' => 'AND', 'operand' => $unique_where);
         }
     }
     $found = I2CE_FormStorage::search($form_obj->getName(), $search_parent, $where, array(), 1);
     if ($found !== false && '' . $found != '' . $form_obj->getId()) {
         I2CE::raiseMessage("found is {$found} and id is " . $form_obj->getId() . " and names are " . print_r($names, true));
         if (count($names) > 1) {
             $field_obj->setInvalidMessage('unique_fields', null, ' ' . implode(', ', $names));
             //$field_obj->setInvalid("This must be unique and another record has this value for the given value of the fields " .implode(',',$names) );
         } else {
             if (count($names) == 1) {
                 $field_obj->setInvalidMessage('unique_field', null, ' ' . implode(', ', $names));
                 //$field_obj->setInvalid("This must be unique and another record has this value for the given value of the field " .implode(',',$names) );
             } else {
                 $field_obj->setInvalidMessage('unique');
                 //$field_obj->setInvalid("This must be unique and another record has this value." );
             }
         }
     }
 }
 /**
  * update value of each  instance  of a given form field by a sql  function call
  * @param I2CE_FormField $form_field
  * @param array $where Array of where data
  * @param string $set_sql sql used to update the field
  */
 public function globalFieldUpdateBySQL($form_field, $where, $set_sql)
 {
     if (!$form_field instanceof I2CE_FormField) {
         I2CE::raiseError("Not passed form_field");
         return false;
     }
     $formObj = $form_field->getContainer();
     if (!$formObj instanceof I2CE_Form) {
         I2CE::raiseError("No form as a container for the form field");
         return false;
     }
     $form = $formObj->getName();
     if (!$set_sql) {
         I2CE::raiseError("No SQL provided to update {$form}+{$field}");
         return false;
     }
     $where_qry = $formObj->generateWhereClause($where);
     if (!$where_qry) {
         I2CE::raiseError("Could not gernerate where clasue for {$form} by\n" . print_r($where, true));
         return false;
     }
     $this->setupForm($formObj);
     $referenceCallback = $this->generateReferenceCallback_2($form, $form_field->getName());
     if (!$referenceCallback) {
         return false;
     }
     if ($form_field->getName() == 'parent') {
         $formID = $this->getFormId($form, true);
         if (!$formID) {
             //form has not been saved to yet
             return false;
         }
         $last_entry_fields_qry = $this->_getRequiredFieldsQuery($form, array($form_field->getName()), null, false, null, -1, true);
         if (!$last_entry_fields_qry) {
             I2CE::raiseError("Could not generage field query for " . $form_field->getName());
             return false;
         }
         $qry = "UPDATE record JOIN ({$last_entry_fields_qry} ) AS data ON record.id = data.`{$form}+id` SET  " . "record.parent_form = SUBSTR({$set_sql},1,LOCATE('|',{$set_sql})-1)," . "record.parent_id = CONVERT(SUBSTR({$set_sql},LOCATE('|',{$set_sql})+1),SIGNED INTEGER) WHERE ( (record.form = {$formID}  )AND ({$where_qry}))";
         //I2CE::raiseError("Updating by $qry");
         $res = $this->db->exec($qry);
         if (I2CE::pearError("Cannot update by:\n{$qry}", $res)) {
             return false;
         }
     } else {
         $last_entry_fields_qry = $this->_getRequiredFieldsQuery($form, array($form_field->getName()), null, false, null, -1, true);
         $entry_fields_qry = $this->_getRequiredFieldsQuery($form, array($form_field->getName()), null, false, null, -1, false);
         if (!$last_entry_fields_qry) {
             I2CE::raiseError("Could not generage field query for " . $form_field->getName());
             return false;
         }
         if (!$entry_fields_qry) {
             I2CE::raiseError("Could not generage field query for " . $form_field->getName());
             return false;
         }
         $details = $this->getFormFieldIdAndType($form, $form_field->getName());
         if (!is_array($details) || !array_key_exists('type', $details)) {
             // This shoueld be rare but could happen if no data has been saved yet.  Interpret as nothing to update
             return true;
         }
         $qry = "UPDATE last_entry JOIN ({$last_entry_fields_qry} ) AS data ON last_entry.record = data.`{$form}+id` SET  " . 'last_entry.`' . $details['type'] . '_value`  = ' . $set_sql . ' WHERE (last_entry.form_field = ' . $details['id'] . " AND ({$where_qry}))";
         //I2CE::raiseError("Updating by $qry");
         $res = $this->db->exec($qry);
         if (I2CE::pearError("Cannot update by:\n{$qry}", $res)) {
             return false;
         }
         $qry = "UPDATE entry  JOIN ({$entry_fields_qry} ) AS data ON entry.record = data.`{$form}+id` SET  " . 'entry.`' . $details['type'] . '_value`  = ' . $set_sql . ' WHERE (entry.form_field = ' . $details['id'] . " AND ({$where_qry}) )";
         //I2CE::raiseError("Updating by $qry");
         $res = $this->db->exec($qry);
         if (I2CE::pearError("Cannot update by:\n{$qry}", $res)) {
             return false;
         }
     }
     return true;
 }
 /**
  * Hooked Function to check if a field is unique
  * @param I2CE_FormField $field_obj
  */
 public function validate_formfield($field_obj)
 {
     if (!$field_obj->hasOption('unique') || !$field_obj->getOption('unique') || !$field_obj->isValid()) {
         return;
     }
     if (!$field_obj->hasOption('unique_field')) {
         return;
     }
     $unique = $field_obj->getOption('unique_field');
     if (strpos($unique, ':') === false) {
         //the value is not a mapped thing.  this is handled by hooked mehtod defined in I2CE_FormStorage
         return;
     }
     $form_obj = $field_obj->getContainer();
     if (!$form_obj instanceof I2CE_Form) {
         return;
     }
     $factory = I2CE_FormFactory::instance();
     //$unique should have the form 'unqique_field:form2(+field2):..:..:formM(+fieldM):...:formN
     //example $unique = 'region:country' or 'region+region+country:country' are the same.
     //    means that $field_obj needs to be unqiue when reseticted to the set of forms within a country and all of its regions
     //    the country and the region that is specified is the
     //    in this case, we need that region is a field of $form_obj
     //example: $unqiue = 'county:district+region:region:country' or 'county:district:region:country' are the same
     //    means that $field_obj needs to be unique when resitrcicted to a country, any of its regions any of those regions
     //    in this case, we need that county is a field of $form_obj
     //example: $unqiue = '[location]county:district+region:region:country' or 'county:district:region:country' are the same
     //    means that $field_obj needs to be unique when resitrcicted to a country, any of its regions any of those regions
     //    in this case, we need that location is a field of $form_obj
     $unique_fields = explode(',', $unique);
     $matches = null;
     $names = array();
     $main_where = array('operator' => 'FIELD_LIMIT', 'style' => 'equals', 'field' => $field_obj->getName(), 'data' => array('value' => $field_obj->getDBValue()));
     foreach ($unique_fields as $unique_field) {
         if ($matches === false) {
             break;
         }
         if (strpos($unique_field, ':') === false) {
             //this field is not mapped... just handle it as a regular value.
             if (!($unique_field_obj = $form_obj->getField($unique_field)) instanceof I2CE_FormField) {
                 I2CE::raiseError("Invalid field {$unqiue_field}");
                 return;
             }
             if ($unique_field_obj->hasHeader('default')) {
                 $names[] = $unique_field_obj->getHeader('default');
             } else {
                 $names[] = $unique_field_obj->getName();
             }
             $where = array($main_where);
             if ($unique_field_obj->getDBValue()->isValid()) {
                 $where[] = array('operator' => 'FIELD_LIMIT', 'style' => 'equals', 'field' => $unique_field_obj->getName(), 'data' => array('value' => $unique_field_obj->getDBValue()));
             } else {
                 $where[] = array('operator' => 'OR', 'operand' => array(0 => array('operator' => 'FIELD_LIMIT', 'style' => 'equals', 'field' => $unique_field_obj->getName(), 'data' => array('value' => $unique_field_obj->getDBValue())), 1 => array('operator' => 'FIELD_LIMIT', 'style' => 'null', 'field' => $unique_field_obj->getName())));
             }
             if (count($where) > 1) {
                 $where = array('operator' => 'AND', 'operand' => $where);
             }
             $found = I2CE_FormStorage::search($form_obj->getName(), false, $where);
             foreach ($found as &$f) {
                 $f = (string) $f;
             }
             $matches = count($found) > 0 && in_array((string) $form_obj->getId(), $found, true);
         } else {
             $field_path = explode(':', $unique_field);
             $restricted_field = false;
             if (preg_match('/^\\[(.*?)\\](.*)$/', $field_path[0])) {
                 $restricted_field = $matches[1];
                 $field_path[0] = $matches[2];
             } else {
                 if (preg_match('/^(.*?)\\+(.*)$/', $field_path[0], $matches)) {
                     $restricted_field = $matches[1];
                 } else {
                     $restricted_field = $field_path[0];
                 }
             }
             $restricted_field_obj = $form_obj->getField($restricted_field);
             if (!$restricted_field_obj instanceof I2CE_FormField_MAP) {
                 I2CE::raiseError("Invalid field passed as restricted field for " . $form_obj->getName() . ": {$unique_field}");
                 return;
             }
             if ($restricted_field_obj->hasHeader('default')) {
                 $names[] = $restricted_field_obj->getHeader('default');
             } else {
                 $names[] = $restricted_field_obj->getName();
             }
             //now let's split up field_path into the forms and the fields
             $top_formid = I2CE_List::walkupFieldPath($field_path, $restricted_field_obj->getDBValue());
             if ($top_formid === false) {
                 //the value is not set. or inappropriately set.  error silently.
                 //this is handled by hooked method defined in I2CE_Module_Form.
                 return;
             }
             //now we get all forms under $top_formid defined by the field path
             $field_name = $field_obj->getName();
             $field_val = $field_obj->getDBValue();
             $form_id = $form_obj->getID();
             $dtree_path = $field_path;
             array_unshift($dtree_path, $form_obj->getName());
             list($top_form, $top_id) = explode('|', $top_formid, 2);
             $dtree_limits = array($top_form => array('operator' => 'FIELD_LIMIT', 'style' => 'equals', 'field' => 'id', 'data' => array('value' => $top_id)), $form_obj->getName() => $main_where);
             $options = I2CE_List::buildDataTree($dtree_path, array($form_obj->getName()), $dtree_limits);
             $options = I2CE_List::flattenDataTree($options);
             if (count($options) == 1) {
                 // If there's only one match and it is this form then don't block
                 // changes.
                 if ($options[0]['value'] != $form_obj->getNameId()) {
                     $matches = true;
                 }
             } elseif (count($options) > 1) {
                 $matches = true;
             }
             /*
             array_pop($field_path);
             $options = I2CE_List::monsterMash(
                 $form_obj->getName(),  //facility
                 $restricted_field, //location
                 $top_formid, //country|10
                 $field_path, //array(county+district,district+region,region+country)            
                 $field_name, //name
                 false
                 );
             
             //starts get all facility where location = country|10  
             //    get all regions region|X where region+country = country|10
             //    this means we need to start with
             //           link_field = country (e.g link_field_path[$len-1] 
             //           list(sub_form,sub_link_field) = explode(+,end(subfields) ) == (region,country)
             //             
             //next get all facility where location = residence|X 
             $option_matches = false;
             foreach ($options as $id=>$data) {
                 if (array_key_exists($field_name,$data) && ($data[$field_name] == $field_val) && ( $id != $form_id)) {
                     $option_matches =true;
                     break;
                 }
             }
             $matches = ($option_matches);
             */
         }
     }
     if ($matches === true) {
         if (count($names) > 1) {
             $field_obj->setInvalidMessage('unique_fields', null, ' ' . implode(', ', $names));
         } else {
             if (count($names) == 1) {
                 $field_obj->setInvalidMessage('unique_field', null, ' ' . implode(', ', $names));
             } else {
                 $field_obj->setInvalidMessage('unique');
             }
         }
         return;
     }
 }