Example #1
0
 function handle($params)
 {
     if (!defined('DISABLE_reCAPTCHA')) {
         define('DISABLE_reCAPTCHA', 1);
     }
     import('Dataface/QuickForm.php');
     Dataface_QuickForm::$TRACK_SUBMIT = false;
     $app = Dataface_Application::getInstance();
     $query = $app->getQuery();
     $errors = null;
     try {
         if (!@$_POST['-table']) {
             throw new Exception("No table specified");
         }
         $table = $_POST['-table'];
         $rec = new Dataface_Record($table, array());
         $tableObj = $rec->_table;
         $fields = array();
         if (!$rec->checkPermission('new')) {
             throw new Exception("Failed to insert record.  Permission denied");
         }
         foreach ($_POST as $k => $v) {
             if ($k[0] == '-') {
                 continue;
             }
             $fields[] = $k;
             $rec->setValue($k, $v);
             if (!$rec->checkPermission('new', array('field' => $k))) {
                 throw new Exception(sprintf("Failed to insert record because you do not have permission to insert data into the %s column", $k));
             }
         }
         $form = df_create_new_record_form($table, $fields);
         $form->_flagSubmitted = true;
         $res = $form->validate();
         if (!$res) {
             $errors = $form->_errors;
             throw new Exception('Validation error', REST_INSERT_VALIDATION_ERROR);
         }
         $res = $rec->save(null, true);
         if (PEAR::isError($res)) {
             throw new Exception("Failed to insert record due to a server error: " . $res->getMessage(), 500);
         }
         $out = array();
         $vals = $rec->strvals();
         foreach ($vals as $k => $v) {
             if ($rec->checkPermission('view')) {
                 $out[$k] = $v;
             }
         }
         $this->out(array('code' => 200, 'message' => 'Record successfully inserted', 'record' => $out));
         exit;
     } catch (Exception $ex) {
         $this->out(array('code' => $ex->getCode(), 'message' => $ex->getMessage(), 'errors' => $errors));
         exit;
     }
 }
Example #2
0
 /**
  * Builds an SQL query to copy the given record.  This honours permissions
  * and will only copy columns for which 'view' access is available in the
  * source record and 'edit' access is available in the destination record.
  *
  * Individual column failures (due to permissions) are recorded in the 
  * $warnings variable of this class.  It will be an array of Dataface_Error
  * objects.
  *
  * @param Dataface_Record $record The record being copied.
  * @param array $valls Values that should be placed in the copied version.
  * @param boolean $force If true this will perform the copy despite individual
  *			column warnings.
  * @returns string The SQL query to copy the record.
  */
 function buildCopyQuery($record, $vals = array(), $force = true)
 {
     $dummy = new Dataface_Record($record->_table->tablename, $vals);
     if (!$record->checkPermission('view') || !$dummy->checkPermission('edit')) {
         return Dataface_Error::permissionDenied("Failed to copy record '" . $record->getTitle() . "' because of insufficient permissions.");
     }
     $copy_fields = array_keys($record->_table->fields());
     // Go through each field and see if we have copy permission.
     // Copy permission is two-fold: 1- make sure the source is viewable
     //								2- make sure the destination is editable.
     $failed = false;
     foreach ($copy_fields as $key => $fieldname) {
         if (!$record->checkPermission('view', array('field' => $fieldname)) || !$dummy->checkPermission('edit', array('field' => $fieldname))) {
             $this->warnings[] = Dataface_Error::permissionDenied("The field '{$fieldname}' could not be copied for record '" . $record->getTitle() . "' because of insufficient permissions.");
             unset($copy_fields[$key]);
             $failed = true;
         }
     }
     // If we are not forcing completion, any failures will result in cancellation
     // of the copy.
     if (!$force and $failed) {
         return Dataface_Error::permissionDenied("Failed to copy the record '" . $record->getTitle() . "' due to insufficient permissions on one or more of the columns.");
     }
     // We don't copy auto increment fields.
     $auto_inc_field = $record->_table->getAutoIncrementField();
     if ($auto_inc_field) {
         $key = array_search($auto_inc_field, $copy_fields);
         if ($key !== false) {
             unset($copy_fields[$key]);
         }
     }
     // Now we can build the query.
     $sql = array();
     $sql[] = "insert into `" . $record->_table->tablename . "`";
     $sql[] = "(`" . implode('`,`', $copy_fields) . "`)";
     $copy_values = array();
     foreach ($copy_fields as $key => $val) {
         if (isset($vals[$val])) {
             $copy_values[$key] = "'" . addslashes($dummy->getSerializedValue($val)) . "' as `{$val}`";
         } else {
             $copy_values[$key] = "`" . $val . "`";
         }
     }
     $sql[] = "select " . implode(', ', $copy_values) . " from `" . $record->_table->tablename . "`";
     $qb = new Dataface_QueryBuilder($record->_table->tablename);
     $keys = array_keys($record->_table->keys());
     $q = array();
     foreach ($keys as $key_fieldname) {
         $q[$key_fieldname] = $record->strval($key_fieldname);
     }
     $where = $qb->_where($q);
     $where = $qb->_secure($where);
     $sql[] = $where;
     return implode(' ', $sql);
 }
Example #3
0
 function handle($params)
 {
     $app = Dataface_Application::getInstance();
     $query = $app->getQuery();
     try {
         if (!@$_POST['-table']) {
             throw new Exception("No table was specified");
         }
         $vals = array();
         foreach ($query as $k => $v) {
             if ($k and $k[0] != '-') {
                 $vals[$k] = $v;
             }
         }
         $record = new Dataface_Record($_POST['-table'], array());
         $record->setValues($vals);
         if (!$record->checkPermission('ajax_save')) {
             throw new Exception("Permission Denied", 502);
         }
         $res = $record->save(null, true);
         if (PEAR::isError($res)) {
             error_log($res->getMessage(), $res->getCode());
             throw new Exception("Failed to save record due to a server error.  See log for details.");
         }
         $this->out(array('code' => 200, 'message' => 'Successfully inserted record.', 'recordId' => $record->getId()));
     } catch (Exception $ex) {
         $this->out(array('code' => $ex->getCode(), 'message' => $ex->getMessage()));
     }
 }
Example #4
0
File: IO.php Project: promoso/HVAC
 /**
  * Deletes a record from the database.
  * @param Dataface_Record $record Dataface_Record object to be deleted.
  * @param boolean $secure Whether to check permissions.
  * @returns mixed true if successful, or PEAR_Error if failed.
  */
 function delete(&$record, $secure = false)
 {
     if ($secure && !$record->checkPermission('delete')) {
         // Use security to check to see if we are allowed to delete this
         // record.
         return Dataface_Error::permissionDenied(df_translate('scripts.Dataface.IO.delete.PERMISSION_DENIED', 'Could not delete record "' . $record->getTitle() . '" from table "' . $record->_table->tablename . '" because you have insufficient permissions.', array('title' => $record->getTitle(), 'table' => $record->_table->tablename)));
     }
     $builder = new Dataface_QueryBuilder($this->_table->tablename);
     if ($this->fireTriggers) {
         $res = $this->fireBeforeDelete($record);
         if (PEAR::isError($res)) {
             return $res;
         }
     }
     // do the deleting
     $keys =& $record->_table->keys();
     if (!$keys || count($keys) == 0) {
         trigger_error(df_translate('scripts.Dataface.IO.delete.ERROR_NO_PRIMARY_KEY', 'Could not delete record from table "' . $record->_table->tablename . '" because no primary key was defined.', array('tablename' => $record->_table->tablename)));
         exit;
     }
     $query = array();
     foreach (array_keys($keys) as $key) {
         if (!$record->strval($key)) {
             return PEAR::raiseError(Dataface_LanguageTool::translate('Could not delete record because missing keys', 'Could not delete record ' . $record->getTitle() . ' because not all of the keys were included.', array('title' => $record->getTitle(), 'key' => $key)), DATAFACE_E_DELETE_FAILED);
         }
         $query[$key] = '=' . $record->strval($key);
     }
     $sql = $builder->delete($query);
     if (PEAR::isError($sql)) {
         return $sql;
     }
     //$res = mysql_query($sql);
     $res = $this->dbObj->query($sql, null, $this->lang);
     if (!$res || PEAR::isError($res)) {
         if (PEAR::isError($res)) {
             $msg = $res->getMessage();
         } else {
             $msg = mysql_error(df_db());
         }
         return PEAR::raiseError(Dataface_LanguageTool::translate('Failed to delete record. SQL error', 'Failed to delete record ' . $record->getTitle() . ' because of an sql error. ' . mysql_error(df_db()), array('title' => $record->getTitle(), 'sql' => $sql, 'mysql_error' => $msg)), DATAFACE_E_DELETE_FAILED);
     }
     $parentIO =& $this->getParentIO();
     if (isset($parentIO)) {
         $parentRecord =& $record->getParentRecord();
         if (isset($parentRecord)) {
             $res = $parentIO->delete($parentRecord, $secure);
             if (PEAR::isError($res)) {
                 return $res;
             }
         }
     }
     if ($this->fireTriggers) {
         $res2 = $this->fireAfterDelete($record);
         if (PEAR::isError($res2)) {
             return $res2;
         }
     }
     self::touchTable($this->_table->tablename);
     return $res;
 }
Example #5
0
 function saveTransients(Dataface_Record $record, $keys = null, $tablename = null, $secure = false)
 {
     $app = Dataface_Application::getInstance();
     // Now we take care of the transient relationship fields.
     // Transient relationship fields aren't actually stored in the record
     // itself, they are stored as related records.
     foreach ($record->_table->transientFields() as $tfield) {
         if (!isset($tfield['relationship'])) {
             continue;
         }
         if (!$record->valueChanged($tfield['name'])) {
             continue;
         }
         $trelationship =& $record->_table->getRelationship($tfield['relationship']);
         if (!$trelationship or PEAR::isError($trelationship)) {
             // We couldn't find the specified relationship.
             //$record->vetoSecurity = $oldVeto;
             return $trelationship;
         }
         $orderCol = $trelationship->getOrderColumn();
         if (PEAR::isError($orderCol)) {
             $orderCol = null;
         }
         $tval = $record->getValue($tfield['name']);
         if ($tfield['widget']['type'] == 'grid') {
             $tval_existing = array();
             $tval_new = array();
             $tval_new_existing = array();
             $torder = 0;
             foreach ($tval as $trow) {
                 if (!is_array($trow)) {
                     continue;
                 }
                 $trow['__order__'] = $torder++;
                 if (isset($trow['__id__']) and preg_match('/^new:/', $trow['__id__'])) {
                     $tval_new_existing[] = $trow;
                 } else {
                     if (isset($trow['__id__']) and $trow['__id__'] != 'new') {
                         $tval_existing[$trow['__id__']] = $trow;
                     } else {
                         if (isset($trow['__id__']) and $trow['__id__'] == 'new') {
                             $tval_new[] = $trow;
                         }
                     }
                 }
             }
             // The transient field was loaded so we can go about saving the
             // changes/
             $trecords =& $record->getRelatedRecordObjects($tfield['relationship'], 'all');
             if (!is_array($trecords) or PEAR::isError($trecords)) {
                 error_log('Failed to get related records for record ' . $record->getId() . ' in its relationship ' . $tfield['relationship']);
                 unset($tval);
                 unset($orderCol);
                 unset($tval_new);
                 unset($torder);
                 unset($trelationship);
                 unset($tval_existing);
                 continue;
             }
             // Update the existing records in the relationship.
             // We use the __id__ parameter in each row for this.
             //echo "About to save related records";
             foreach ($trecords as $trec) {
                 $tid = $trec->getId();
                 if (isset($tval_existing[$tid])) {
                     $tmp = new Dataface_RelatedRecord($trec->_record, $tfield['relationship'], $trec->getValues());
                     $tmp->setValues($tval_existing[$tid]);
                     $changed = false;
                     foreach ($tval_existing[$tid] as $k1 => $v1) {
                         if ($tmp->isDirty($k1)) {
                             $changed = true;
                             break;
                         }
                     }
                     if ($changed) {
                         $trec->setValues($tval_existing[$tid]);
                         if ($orderCol) {
                             $trec->setValue($orderCol, $tval_existing[$tid]['__order__']);
                         }
                         //echo "Saving ";print_r($trec->vals());
                         $res_t = $trec->save($this->lang, $secure);
                         if (PEAR::isError($res_t)) {
                             return $res_t;
                             error_log('Failed to save related record ' . $trec->getId() . ' while saving transient field ' . $tfield['name'] . ' in record ' . $record->getId() . '. The error returned was : ' . $res_t->getMessage());
                         }
                     } else {
                         if ($orderCol and $record->checkPermission('reorder_related_records', array('relationship' => $tfield['relationship']))) {
                             $trec->setValue($orderCol, $tval_existing[$tid]['__order__']);
                             $res_t = $trec->save($this->lang, false);
                             // we don't need this to be secure
                             if (PEAR::isError($res_t)) {
                                 return $res_t;
                                 error_log('Failed to save related record ' . $trec->getId() . ' while saving transient field ' . $tfield['name'] . ' in record ' . $record->getId() . '. The error returned was : ' . $res_t->getMessage());
                             }
                         }
                     }
                     unset($tmp);
                 } else {
                 }
                 unset($trec);
                 unset($tid);
                 unset($res_t);
             }
             // Now add new records  (specified by __id__ field being 'new'
             foreach ($tval_new as $tval_to_add) {
                 $temp_rrecord = new Dataface_RelatedRecord($record, $tfield['relationship'], array());
                 $temp_rrecord->setValues($tval_to_add);
                 if ($orderCol) {
                     $temp_rrecord->setValue($orderCol, $tval_to_add['__order__']);
                 }
                 $res_t = $this->addRelatedRecord($temp_rrecord, $secure);
                 if (PEAR::isError($res_t)) {
                     error_log('Failed to save related record ' . $temp_rrecord->getId() . ' while saving transient field ' . $tfield['name'] . ' in record ' . $record->getId() . '. The error returned was : ' . $res_t->getMessage());
                 }
                 unset($temp_rrecord);
                 unset($res_t);
             }
             // Now add new existing records  (specified by __id__ field being 'new:<recordid>'
             foreach ($tval_new_existing as $tval_to_add) {
                 $tid = preg_replace('/^new:/', '', $tval_to_add['__id__']);
                 $temp_record = df_get_record_by_id($tid);
                 if (PEAR::isError($temp_record)) {
                     return $temp_record;
                 }
                 if (!$temp_record) {
                     return PEAR::raiseError("Failed to load existing record with ID {$tid}.");
                 }
                 $temp_rrecord = new Dataface_RelatedRecord($record, $tfield['relationship'], $temp_record->vals());
                 $temp_rrecord->setValues($tval_to_add);
                 if ($orderCol) {
                     $temp_rrecord->setValue($orderCol, $tval_to_add['__order__']);
                 }
                 $res_t = $this->addExistingRelatedRecord($temp_rrecord, $secure);
                 if (PEAR::isError($res_t)) {
                     error_log('Failed to save related record ' . $temp_rrecord->getId() . ' while saving transient field ' . $tfield['name'] . ' in record ' . $record->getId() . '. The error returned was : ' . $res_t->getMessage());
                 }
                 unset($temp_rrecord);
                 unset($res_t);
             }
             // Now we delete the records that were deleted
             // we use the __deleted__ field.
             if (isset($tval['__deleted__']) and is_array($tval['__deleted__']) and $trelationship->supportsRemove()) {
                 $tdelete_record = ($trelationship->isOneToMany() and !$trelationship->supportsAddExisting());
                 // If it supports add existing, then we shouldn't delete the entire record.  Just remove it
                 // from the relationship.
                 foreach ($tval['__deleted__'] as $del_id) {
                     if ($del_id == 'new') {
                         continue;
                     }
                     $drec = Dataface_IO::getByID($del_id);
                     if (PEAR::isError($drec) or !$drec) {
                         unset($drec);
                         continue;
                     }
                     $mres = $this->removeRelatedRecord($drec, $tdelete_record, $secure);
                     if (PEAR::isError($mres)) {
                         throw new Exception($mres->getMessage());
                     }
                     unset($drec);
                 }
             }
             unset($trecords);
         } else {
             if ($tfield['widget']['type'] == 'checkbox') {
                 // Load existing records in the relationship
                 $texisting =& $record->getRelatedRecordObjects($tfield['relationship'], 'all');
                 if (!is_array($texisting) or PEAR::isError($texisting)) {
                     error_log('Failed to get related records for record ' . $record->getId() . ' in its relationship ' . $tfield['relationship']);
                     unset($tval);
                     unset($orderCol);
                     unset($tval_new);
                     unset($torder);
                     unset($trelationship);
                     unset($tval_existing);
                     continue;
                 }
                 $texistingIds = array();
                 foreach ($texisting as $terec) {
                     $texistingIds[] = $terec->getId();
                 }
                 // Load currently checked records
                 $tchecked = array();
                 $tcheckedRecords = array();
                 $tcheckedIds = array();
                 $tcheckedId2ValsMap = array();
                 foreach ($tval as $trkey => $trval) {
                     // $trval is in the form key1=val1&size=key2=val2
                     parse_str($trval, $trquery);
                     $trRecord = new Dataface_RelatedRecord($record, $tfield['relationship'], $trquery);
                     $trRecords[] =& $trRecord;
                     $tcheckedIds[] = $tid = $trRecord->getId();
                     $checkedId2ValsMap[$tid] = $trquery;
                     unset($trRecord);
                     unset($trquery);
                 }
                 // Now we have existing ids in $texistingIds
                 // and checked ids in $tcheckedIds
                 // See which records we need to have removed
                 $tremoves = array_diff($texistingIds, $tcheckedIds);
                 $tadds = array_diff($tcheckedIds, $texistingIds);
                 foreach ($tremoves as $tid) {
                     $trec = df_get_record_by_id($tid);
                     $res = $this->removeRelatedRecord($trec, false, $secure);
                     if (PEAR::isError($res)) {
                         return $res;
                     }
                     unset($trec);
                 }
                 foreach ($tadds as $tid) {
                     $trecvals = $checkedId2ValsMap[$tid];
                     $trec = new Dataface_RelatedRecord($record, $tfield['relationship'], $trecvals);
                     $res = $this->addExistingRelatedRecord($trec, $secure);
                     if (PEAR::isError($res)) {
                         return $res;
                     }
                     unset($trec, $trecvals);
                 }
                 unset($tadds);
                 unset($tremoves);
                 unset($tcheckedIds, $tcheckedId2ValsMap);
                 unset($tcheckedRecords);
                 unset($tchecked);
                 unset($texistingIds);
                 unset($texisting);
             }
         }
         unset($tval);
         unset($trelationship);
     }
 }
Example #6
0
 function &buildWidget(&$record, &$field, &$form, $formFieldName, $new = false)
 {
     /*
      *
      * This field uses a table widget.
      *
      */
     //$field['display'] = 'block';
     $table =& $record->_table;
     $formTool =& Dataface_FormTool::getInstance();
     $factory =& Dataface_FormTool::factory();
     $widget =& $field['widget'];
     $el =& $factory->addElement('grid', $formFieldName, $widget['label']);
     if (!$record->checkPermission('delete related record', array('relationship' => $field['relationship']))) {
         $el->delete = false;
     }
     if (!$record->checkPermission('add new related record', array('relationship' => $field['relationship']))) {
         //echo "No add new ".$record->_table->tablename;
         $el->addNew = false;
     }
     if (isset($field['relationship'])) {
         $relationship =& $table->getRelationship($field['relationship']);
         if (!$relationship->supportsAddNew()) {
             $el->addNew = false;
         }
         if (!$relationship->supportsAddExisting()) {
             $el->addExisting = false;
         } else {
             $el->addExistingFilters = $relationship->getAddExistingFilters();
         }
         $el->table = $relationship->getDomainTable();
         if (isset($widget['columns'])) {
             $columns = array_map('trim', explode(',', $widget['columns']));
         } else {
             $columns = $relationship->_schema['short_columns'];
         }
         $count = 0;
         $subfactory = new HTML_QuickForm();
         foreach ($columns as $column) {
             $colTable =& $relationship->getTable($column);
             if (!$colTable) {
                 echo "Could not find table for column {$column}";
             }
             // We need to be a bit more refined on this one.  We need to take
             // into account the context being that we are in a relationship.
             $dummyRecord = new Dataface_Record($colTable->tablename, $record->vals());
             if (!$dummyRecord->checkPermission('view', array('field' => $column, 'recordmask' => array('view' => 1)))) {
                 unset($colTable);
                 unset($dummyRecord);
                 continue;
             }
             $colFieldDef =& $colTable->getField($column);
             $columnElement =& $formTool->buildWidget($dummyRecord, $colFieldDef, $subfactory, $column, false);
             $defaultValue = $colTable->getDefaultValue($column);
             $columnElement->setValue($defaultValue);
             $el->addField($colFieldDef, $columnElement);
             $orderCol = $relationship->getOrderColumn();
             if (PEAR::isError($orderCol)) {
                 $el->reorder = false;
             }
             unset($columnElement);
             unset($colFieldDef);
             unset($dummyRecord);
             unset($colTable);
             unset($elementFilter);
         }
     } else {
         if (isset($widget['fields'])) {
             $widget_fields =& $widget['fields'];
             foreach ($widget_fields as $widget_field) {
                 $widget_field =& Dataface_Table::getTableField($widget_field, $this->db);
                 if (PEAR::isError($widget_field)) {
                     return $widget_field;
                 }
                 $widget_widget = $formTool->buildWidget($record, $widget_field, $factory, $widget_field['name']);
                 $defaultValue = $table->getDefaultValue($widget_field['name']);
                 $widget_widget->setValue($defaultValue);
                 $el->addField($widget_widget);
             }
         } else {
             if (isset($field['fields'])) {
                 foreach (array_keys($field['fields']) as $field_key) {
                     $widget_widget = $formTool->buildWidget($record, $field['fields'][$field_key], $factory, $field['fields'][$field_key]['name']);
                     $defaultValue = $table->getDefaultValue($widget_field['name']);
                     $widget_widget->setValue($defaultValue);
                     $el->addField($widget_widget);
                     unset($widget_widget);
                 }
             }
         }
     }
     return $el;
 }
Example #7
0
 function testPermissions()
 {
     $formulasTable = Dataface_Table::loadTable('formulas');
     $formulasDel = $formulasTable->getDelegate();
     $formulasDel->testPermissions = true;
     $formula = new Dataface_Record('formulas', array('formula_name' => 'test formula'));
     // Test the standard permissions on tables and fields
     $this->assertTrue($formula->checkPermission('view'), 'View permission should be set by default.');
     $this->assertTrue(!$formula->checkPermission('list'), 'List permission should be denied by default.');
     $this->assertTrue($formula->checkPermission('new'), 'New permission should be permitted by default.');
     $this->assertTrue(!$formula->checkPermission('new', array('field' => 'formula_name')), 'New permission should be denied on the formula_name field.');
     $this->assertTrue($formula->checkPermission('view', array('field' => 'formula_name')), 'The view permission should be allowed on the formula_name field.');
     $this->assertTrue(!$formula->checkPermission('view', array('field' => 'formula_id')), 'The view permission should be denied on the formula_id field.');
     // Test the nobubble parameter on getPermissions
     $this->assertTrue(!$formula->checkPermission('delete', array('field' => 'formula_name', 'nobubble' => 1)), 'Since we are not bubbling up to record, we should not have permission for the delete permission as it is not enabled at field level explicitly - only at record level.');
     $this->assertTrue($formula->checkPermission('delete', array('field' => 'formula_name')), 'Now that we are allowing bubbling, we should return true for delete on teh formula_name field.');
     $this->assertTrue($formula->checkPermission('copy', array('field' => 'formula_name', 'nobubble' => 1)), 'Even though there is no bubbling, we should still return true for the copy permission on the formula_name field since it is defined in the __field__permssions() method.');
     $this->assertTrue($formula->checkPermission('view', array('field' => 'amount', 'relationship' => 'ingredients')), 'view permission of the amount field in the ingredients relationship should be allowed because it is granted in the rel_ingredients__amount__permissions() method of the formulas delegate class.');
     $this->assertTrue($formula->checkPermission('view', array('field' => 'amount', 'relationship' => 'ingredients', 'nobubble' => 1)), 'view permission for amount field in ingredients relationship should be allowed even with nobubble=1 because it is permistted in the rel_ingredients__amount__permissions().');
     $this->assertTrue($formula->checkPermission('link', array('field' => 'amount', 'relationship' => 'ingredients')), 'link permission on amount field of the ingredients relationship should be allowed because it is granted in the rel_ingredients__permissions() method of the formulas delegate class.');
     $this->assertTrue(!$formula->checkPermission('link', array('field' => 'amount', 'relationship' => 'ingredients', 'nobubble' => 1)), 'link permission on the amount field of the ingredients relationship should not be allowed when nobubble=1 because although it is granted in the rel_ingredients__permissions() method of the formulas delegate class - this method shouldnt be consulted if nobubble=1.  It should just check the specific field permissions of the relationship and then break.');
     $this->assertTrue($formula->checkPermission('link', array('relationship' => 'ingredients')), 'link  permission should be allowed on the ingredients relationship because it is granted in the rel_ingredients__permissions() method of the formulas delegate class.');
     $this->assertTrue($formula->checkPermission('link', array('relationship' => 'ingredients', 'nobubble' => 1)), 'link permission should be allowed in the ingredients relationship even with nobubble=1 because it is granted in the rel_ingredients__permissions() method of the formulas delegate class.  nobubble should just prevent it from looking past the relationship permissions.');
     // Test related record permissions
     $formulaIngredientsTable = Dataface_Table::loadTable('formula_ingredients');
     $formulaIngredientsDel = $formulaIngredientsTable->getDelegate();
     $formulaIngredientsDel->testPermissions = true;
     $relatedRecord = new Dataface_RelatedRecord($formula, 'ingredients', array('ingredient_id' => 1, 'concentration' => 3, 'amount' => 4));
     // Test the standard related permission
     $this->assertTrue(!$relatedRecord->checkPermission('view', array('field' => 'concentration')), 'There shouldn\'t be permission to view the concentration field as it is denied in the getPermissions() method and is not overridden in any of the function methods.');
     $this->assertTrue($relatedRecord->checkPermission('view', array('field' => 'ingredient_id')), 'There should be permission to view the ingredient_id field since it is overridden in the ingredient_id__permissions() method of the formula_ingredients delegate class.');
     $this->assertTrue($relatedRecord->checkPermission('view', array('field' => 'amount')), 'There should be permission to view the amount field since the rel_ingredients__amount__permissions() method is defined in the parent table delegate class and grants the permission..  This should table precedence.');
     $ingredientRecord = new Dataface_Record('formula_ingredients', array('ingredient_id' => 1, 'concentration' => 3, 'amount' => 4));
     $this->assertTrue(!$ingredientRecord->checkPermission('view', array('field' => 'amount')), 'There should be no permission for view of the amount field directly because it hasnt been granted in the formula_ingredients delegate class.');
     // Test the display now.
     $this->assertEquals('NO ACCESS', $relatedRecord->display('concentration'), 'Concentration should be no access via the related record because we havent granted access yet.');
     $this->assertEquals('4', $relatedRecord->display('amount'), 'Amount should display the proper value because view has been granted via the relationship.');
     $this->assertEquals('NO ACCESS', $ingredientRecord->display('amount'), 'Amount should display "NO ACCESS" when accessing the record directly, but instead received the actual value.');
     $formulasDel->testPermissions = false;
 }