/** * Converts the posted form values for a group into a warehouse submission. * @param array $values Form values * @param array $args Form configuration arguments * @return array Submission data */ public static function get_submission($values, $args) { $struct = array('model' => 'group'); if (!empty($values['filter:title'])) { $struct['superModels'] = array('filter' => array('fk' => 'filter_id')); } if (!empty($args['parent_group_relationship_type']) && !empty($_REQUEST['from_group_id'])) { // $from_group_id could be posted in the form if user selectable or provided in the URL if fixed. $from_group_id = empty($_GET['from_group_id']) ? $_POST['from_group_id'] : $_GET['from_group_id']; $struct['subModels'] = array('group_relation' => array('fk' => 'to_group_id')); $values['group_relation:from_group_id'] = $from_group_id; $values['group_relation:relationship_type_id'] = $args['parent_group_relationship_type']; } $s = submission_builder::build_submission($values, $struct); // scan the posted values for group pages. This search grabs the first column value keys. $pageKeys = preg_grep('/^group\\+:pages:\\d*:\\d+:0$/', array_keys($values)); $pages = array(); foreach ($pageKeys as $key) { // skip empty rows, unless they were rows loaded for an existing group_pages record if (!empty($values[$key]) || preg_match('/^group\\+:pages:(\\d+)/', $key)) { // get the key without the column index, so we can access any column we want $base = preg_replace('/0$/', '', $key); if (isset($values[$base . 'deleted']) && $values[$base . 'deleted'] === 't' || empty($values[$base . '0'])) { $page = array('deleted' => 't'); } else { $tokens = explode(':', $values[$base . '0']); $path = $tokens[0]; $caption = empty($values[$base . '1']) ? $tokens[1] : $values[$base . '1']; $administrator = explode(':', $values[$base . '2']); $administrator = empty($administrator) ? 'f' : $administrator[0]; $page = array('caption' => $caption, 'path' => $path, 'administrator' => $administrator); } // if existing group page, hook up to the id if (preg_match('/^group\\+:pages:(\\d+)/', $key, $matches)) { $page['id'] = $matches[1]; } $pages[] = $page; } } if (!empty($pages)) { if (!isset($s['subModels'])) { $s['subModels'] = array(); } foreach ($pages as $page) { $s['subModels'][] = array('fkId' => 'group_id', 'model' => array('id' => 'group_page', 'fields' => $page)); } } // need to manually build the submission for the admins sub_list, since we are hijacking what is // intended to be a custom attribute control if (self::extractUserInfoFromFormValues($s, $values, 'admin_user_id', 't') === 0 && empty($values['group:id'])) { // no admins created when setting up the group initially, so need to set the current user as an admin $s['subModels'][] = array('fkId' => 'group_id', 'model' => submission_builder::wrap(array('user_id' => hostsite_get_user_field('indicia_user_id'), 'administrator' => 't'), 'groups_user')); } self::extractUserInfoFromFormValues($s, $values, 'user_id', 'f'); self::deleteExistingUsers($s, $values); return $s; }
/** * Helper function to simplify building of a submission. Does simple submissions that do not involve * species checklist grids. * @param array $values List of the posted values to create the submission from. * @param array $structure Describes the structure of the submission. The form should be: * array( * 'model' => 'main model name', * 'subModels' => array('child model name' => array( * 'fieldPrefix'=>'Optional prefix for HTML form fields in the sub model. If not specified then the sub model name is used.', * 'fk' => 'foreign key name', * 'image_entity' => 'name of image entity if present' * )), * 'superModels' => array('child model name' => array( * 'fieldPrefix'=>'Optional prefix for HTML form fields in the sub model. If not specified then the sub model name is used.', * 'fk' => 'foreign key name', * 'image_entity' => 'name of image entity if present' * )), * 'metaFields' => array('fieldname1', 'fieldname2', ...) * ) */ public static function build_submission($values, $structure) { return submission_builder::build_submission($values, $structure); }
/** * Handles the construction of a submission array from a set of form values. * @param array $values Associative array of form data values. * @param array $args iform parameters. * @return array Submission structure. */ public static function get_submission($values, $args) { if (array_key_exists('newsample_parent_id', $_POST)) { // $mode = MODE_NEW_OCCURRENCE return null; } if (array_key_exists('sample:parent_id', $_POST)) { // $mode = MODE_POST_OCCURRENCE; // Can't call getGridMode in this context as we might not have the $_GET value to indicate grid if (isset($values['gridmode'])) { return data_entry_helper::build_sample_occurrences_list_submission($values); } else { return data_entry_helper::build_sample_occurrence_submission($values); } } else { // $mode = MODE_POST_SUPERSAMPLE; return submission_builder::build_submission($values, $structure = array('model' => 'sample')); } }
/** * Wraps a standard $_POST type array into a save array suitable for use in saving * records. * * @param array $array Array to wrap * @param bool $fkLink=false Link foreign keys? * @return array Wrapped array */ protected function wrap($array, $fkLink = false) { // share the wrapping library with the client helpers require_once DOCROOT . 'client_helpers/submission_builder.php'; $r = submission_builder::build_submission($array, $this->get_submission_structure()); // Map fk_* fields to the looked up id if ($fkLink) { $r = $this->getFkFields($r, $array); } if (array_key_exists('superModels', $r)) { $idx = 0; foreach ($r['superModels'] as $super) { $r['superModels'][$idx]['model'] = $this->getFkFields($super['model'], $array); $idx++; } } return $r; }
/** * Handles the construction of a submission array from a set of form values. * @param array $values Associative array of form data values. * @param array $args iform parameters. * @return array Submission structure. */ public static function get_submission($values, $args) { $values['sample:location_name'] = $values['sample:entered_sref']; $submission = submission_builder::build_submission($values, array('model' => 'sample')); return $submission; }
/** * Handles the construction of a submission array from a set of form values. * For example, the following represents a submission structure for a simple * sample and 1 occurrence submission * return data_entry_helper::build_sample_occurrence_submission($values); * @param array $values Associative array of form data values. * @param array $args iform parameters. * @return array Submission structure. * @todo: Implement this method */ public static function get_submission($values, $args) { if (!isset($values['page']) || $values['page'] != 'grid') { // submitting the first page, with top level sample details if (!isset($values['sample:entered_sref'])) { // the sample does not have sref data, as the user has just picked a transect site at this point. Copy the // site's centroid across to the sample. $read = array('nonce' => $values['read_nonce'], 'auth_token' => $values['read_auth_token']); $site = data_entry_helper::get_population_data(array('table' => 'location', 'extraParams' => $read + array('view' => 'detail', 'id' => $values['sample:location_id'], 'deleted' => 'f'))); $site = $site[0]; $values['sample:entered_sref'] = $site['centroid_sref']; $values['sample:entered_sref_system'] = $site['centroid_sref_system']; } } $submission = submission_builder::build_submission($values, array('model' => 'sample')); return $submission; }
public static function create_submission($values, $args) { $structure = array('model' => 'location'); // Either an uploadable file, or a link to a Flickr external detail means include the submodel // (Copied from data_entry_helper::build_sample_occurrence_submission. If file_box control is used // then build_submission calls wrap_with_images instead) if (array_key_exists('location:image', $values) && $values['location:image'] || array_key_exists('location_image:external_details', $values) && $values['location_image:external_details']) { $structure['submodel'] = array('model' => 'location_image', 'fk' => 'location_id'); } $s = submission_builder::build_submission($values, $structure); // On first save of a new location, link it to the website. // Be careful not to over-write other subModels (e.g. images) if (empty($values['location:id'])) { $s['subModels'][] = array('fkId' => 'location_id', 'model' => array('id' => 'locations_website', 'fields' => array('website_id' => $args['website_id']))); } return $s; }
/** * Builds a submission for identifiers_subject_observation join data * from the form values. Also adds identifier if it doesn't exist. * @param array $values Associative array of form data values. * @param array $matches Associative array of stored identifiers which match submitted values. * @param array $so The subject_observation submission we are adding to * @return array subject_observation Submission structure with identifier data added. */ private static function build_identifier_observation_submission($values, $matches, $so) { // work out what to do, insert?, update? delete? $set = $values['identifier:checkbox'] == 1; $code = $values['identifier:coded_value']; $old_id = (int) $values['identifier:id']; $new_id = 0; $identifier_status = 'U'; foreach ($matches as $match) { if ($match['coded_value'] === $code) { $new_id = (int) $match['id']; $identifier_status = $match['status']; } } // see if we have any updates on the isoAttr $isoAttrUpdated = count(preg_grep('/^isoAttr:[0-9]+$/', array_keys($values))) > 0; if (!$isoAttrUpdated) { $keys = preg_grep('/^isoAttr:[0-9]+:[0-9]+$/', array_keys($values)); foreach ($keys as $key) { if ($values[$key] === '') { $isoAttrUpdated = true; break; } } } // this identifier exists but its identity has been changed if ($old_id > 0 && $old_id !== $new_id) { // unlink the old identifier $values['identifiers_subject_observation:deleted'] = 't'; $iso = submission_builder::build_submission($values, array('model' => 'identifiers_subject_observation')); $so['subModels'][] = array('fkId' => 'subject_observation_id', 'model' => $iso); } // identifier submitted, has been edited and matches an existing identifier if ($set && $new_id > 0 && $old_id !== $new_id) { // create link to the new matching identifier unset($values['identifiers_subject_observation:id']); $values['identifiers_subject_observation:identifier_id'] = $new_id; $values['identifiers_subject_observation:matched'] = $identifier_status !== 'U' ? 't' : 'f'; unset($values['identifiers_subject_observation:verified_status']); unset($values['identifiers_subject_observation:verified_by_id']); unset($values['identifiers_subject_observation:verified_on']); unset($values['identifiers_subject_observation:created_on']); unset($values['identifiers_subject_observation:created_by_id']); unset($values['identifiers_subject_observation:updated_on']); unset($values['identifiers_subject_observation:updated_by_id']); unset($values['identifiers_subject_observation:deleted']); $iso = submission_builder::build_submission($values, array('model' => 'identifiers_subject_observation')); $so['subModels'][] = array('fkId' => 'subject_observation_id', 'model' => $iso); } // identifier submitted and doesn't match an existing identifier if ($set && $new_id === 0) { // create new link to a new identifier which we also create here unset($values['identifiers_subject_observation:id']); unset($values['identifiers_subject_observation:identifier_id']); $values['identifiers_subject_observation:matched'] = 'f'; unset($values['identifiers_subject_observation:verified_status']); unset($values['identifiers_subject_observation:verified_by_id']); unset($values['identifiers_subject_observation:verified_on']); unset($values['identifiers_subject_observation:created_on']); unset($values['identifiers_subject_observation:created_by_id']); unset($values['identifiers_subject_observation:updated_on']); unset($values['identifiers_subject_observation:updated_by_id']); unset($values['identifiers_subject_observation:deleted']); $iso = submission_builder::build_submission($values, array('model' => 'identifiers_subject_observation')); // now add the identifier unset($values['identifier:id']); unset($values['identifier:issue_authority_id']); unset($values['identifier:issue_scheme_id']); unset($values['identifier:issue_date']); unset($values['identifier:first_use_date']); unset($values['identifier:last_observed_date']); unset($values['identifier:final_date']); unset($values['identifier:summary']); unset($values['identifier:status']); unset($values['identifier:verified_by_id']); unset($values['identifier:verified_on']); unset($values['identifier:known_subject_id']); unset($values['identifier:created_on']); unset($values['identifier:created_by_id']); unset($values['identifier:updated_on']); unset($values['identifier:updated_by_id']); unset($values['identifier:deleted']); $i = submission_builder::build_submission($values, array('model' => 'identifier')); $iso['superModels'] = array(array('fkId' => 'identifier_id', 'model' => $i)); $so['subModels'][] = array('fkId' => 'subject_observation_id', 'model' => $iso); } // identifier exists and is unchanged but has iso attributes which have changed if ($old_id > 0 && $old_id === $new_id && $isoAttrUpdated) { // update link to trigger update to isoAttr $iso = submission_builder::build_submission($values, array('model' => 'identifiers_subject_observation')); $so['subModels'][] = array('fkId' => 'subject_observation_id', 'model' => $iso); } return $so; }
/** * Handles the construction of a submission array from a set of form values. * @param array $values Associative array of form data values. * @param array $args iform parameters. * @return array Submission structure. */ public static function get_submission($values, $args) { $structure = array('model' => 'person'); $s = submission_builder::build_submission($values, $structure); return $s; }
/** * Handles the construction of a submission array from a set of form values. * @param array $values Associative array of form data values. * @param array $args iform parameters. * @return array Submission structure. * @todo: Implement this method */ public static function get_submission($values, $args) { $subsampleModels = array(); if (isset($values['page']) && $values['page'] == 'speciesmap') { $submission = data_entry_helper::build_sample_subsamples_occurrences_submission($values); } else { if (!isset($values['page']) || $values['page'] == 'mainSample') { // submitting the first page, with top level sample details $read = array('nonce' => $values['read_nonce'], 'auth_token' => $values['read_auth_token']); if (!isset($values['sample:entered_sref'])) { // the sample does not have sref data, as the user has just picked a transect site at this point. Copy the // site's centroid across to the sample. Should this be cached? $site = data_entry_helper::get_population_data(array('table' => 'location', 'extraParams' => $read + array('view' => 'detail', 'id' => $values['sample:location_id'], 'deleted' => 'f'))); $site = $site[0]; $values['sample:entered_sref'] = $site['centroid_sref']; $values['sample:entered_sref_system'] = $site['centroid_sref_system']; } // Build the subsamples $sections = data_entry_helper::get_population_data(array('table' => 'location', 'extraParams' => $read + array('view' => 'detail', 'parent_id' => $values['sample:location_id'], 'deleted' => 'f'), 'nocache' => true)); if (isset($values['sample:id'])) { $existingSubSamples = data_entry_helper::get_population_data(array('table' => 'sample', 'extraParams' => $read + array('view' => 'detail', 'parent_id' => $values['sample:id'], 'deleted' => 'f'), 'nocache' => true)); } else { $existingSubSamples = array(); } $sampleMethods = helper_base::get_termlist_terms(array('read' => $read), 'indicia:sample_methods', array('Transect Section')); $attributes = data_entry_helper::getAttributes(array('valuetable' => 'sample_attribute_value', 'attrtable' => 'sample_attribute', 'key' => 'sample_id', 'fieldprefix' => 'smpAttr', 'extraParams' => $read, 'survey_id' => $values['sample:survey_id'], 'sample_method_id' => $sampleMethods[0]['id'], 'multiValue' => false)); $smpDate = self::parseSingleDate($values['sample:date']); foreach ($sections as $section) { $smp = false; $exists = false; foreach ($existingSubSamples as $existingSubSample) { if ($existingSubSample['location_id'] == $section['id']) { $exists = $existingSubSample; break; } } if (!$exists) { $smp = array('fkId' => 'parent_id', 'model' => array('id' => 'sample', 'fields' => array('survey_id' => array('value' => $values['sample:survey_id']), 'website_id' => array('value' => $values['website_id']), 'date' => array('value' => $values['sample:date']), 'location_id' => array('value' => $section['id']), 'entered_sref' => array('value' => $section['centroid_sref']), 'entered_sref_system' => array('value' => $section['centroid_sref_system']), 'sample_method_id' => array('value' => $sampleMethods[0]['id']))), 'copyFields' => array('date_start' => 'date_start', 'date_end' => 'date_end', 'date_type' => 'date_type')); foreach ($attributes as $attr) { foreach ($values as $key => $value) { $parts = explode(':', $key); if (count($parts) > 1 && $parts[0] == 'smpAttr' && $parts[1] == $attr['attributeId']) { $smp['model']['fields']['smpAttr:' . $attr['attributeId']] = array('value' => $value); } } } } else { // need to ensure any date change is propagated: only do if date has changed for performance reasons. $subSmpDate = self::parseSingleDate($exists['date_start']); if (strcmp($smpDate, $subSmpDate)) { $smp = array('fkId' => 'parent_id', 'model' => array('id' => 'sample', 'fields' => array('survey_id' => array('value' => $values['sample:survey_id']), 'website_id' => array('value' => $values['website_id']), 'id' => array('value' => $exists['id']), 'date' => array('value' => $values['sample:date']), 'location_id' => array('value' => $exists['location_id']))), 'copyFields' => array('date_start' => 'date_start', 'date_end' => 'date_end', 'date_type' => 'date_type')); } } if ($smp) { $subsampleModels[] = $smp; } } } $submission = submission_builder::build_submission($values, array('model' => 'sample')); if (count($subsampleModels) > 0) { $submission['subModels'] = $subsampleModels; } } return $submission; }
/** * Converts the posted form values for a group into a warehouse submission. * @param array $values Form values * @param array $args Form configuration arguments * @return array Submission data */ public static function get_submission($values, $args) { $struct = array('model' => 'group'); if (!empty($values['filter:title'])) { $struct['superModels'] = array('filter' => array('fk' => 'filter_id')); } if (!empty($args['parent_group_relationship_type']) && !empty($_GET['from_group_id'])) { $struct['subModels'] = array('group_relation' => array('fk' => 'to_group_id')); $values['group_relation:from_group_id'] = $_GET['from_group_id']; $values['group_relation:relationship_type_id'] = $args['parent_group_relationship_type']; } $s = submission_builder::build_submission($values, $struct); // need to manually build the submission for the admins sub_list, since we are hijacking what is // intended to be a custom attribute control self::extractUserInfoFromFormValues($s, $values, 'admin_user_id', 't'); self::extractUserInfoFromFormValues($s, $values, 'user_id', 'f'); return $s; }
public function testCreateUser() { $array = array('person:first_name' => 'Test', 'person:surname' => 'Person', 'person:email_address' => '*****@*****.**'); $s = submission_builder::build_submission($array, array('model' => 'person')); $r = data_entry_helper::forward_post_to('person', $s, $this->auth['write_tokens']); $this->assertTrue(isset($r['success']), 'Submitting a new person did not work'); $personId = $r['success']; $array = array('user:person_id' => $personId, 'user:email_visible' => 'f', 'user:core_role_id' => 1, 'user:username' => 'testUser'); $s = submission_builder::build_submission($array, array('model' => 'user')); $r = data_entry_helper::forward_post_to('user', $s, $this->auth['write_tokens']); $this->assertTrue(isset($r['success']), 'Submitting a new user did not work'); $userId = $r['success']; ORM::Factory('user', $userId)->delete(); ORM::Factory('person', $personId)->delete(); }
/** * Construct a submission for the location. * @param array $values Associative array of form data values. * @param array $args iform parameters. * @return array Submission structure. */ public static function get_submission($values, $args) { $s = submission_builder::build_submission($values, array('model' => 'location')); if (empty($values['location:id'])) { $s['subModels'] = array(array('fkId' => 'location_id', 'model' => array('id' => 'locations_website', 'fields' => array('website_id' => $args['website_id'])))); } return $s; }
/** * Converts the posted form values for a group into a warehouse submission. * @param array $values Form values * @param array $args Form configuration arguments * @return array Submission data */ public static function get_submission($values, $args) { $struct = array('model' => 'user_trust'); return submission_builder::build_submission($values, $struct); }
/** * Handles the construction of a submission array from a set of form values. * @param array $values Associative array of form data values. * @param array $args iform parameters. * @return array Submission structure. */ public static function get_submission($values, $args) { iform_load_helpers(array('submission_builder')); return submission_builder::build_submission($values, array('model' => 'termlists_term', 'superModels' => array('meaning' => array('fk' => 'meaning_id'), 'term' => array('fk' => 'term_id')))); }
/** * Handles the construction of a submission array from a set of form values. * @param array $values Associative array of form data values. * @param array $args iform parameters. * @return array Submission structure. */ public static function get_submission($values, $args) { //If the location_type_id is supplied in the url, then use this if (!empty($_GET['location_type_id'])) { $values['location:location_type_id'] = $_GET['location_type_id']; } $structure = array('model' => 'location'); // Either an uploadable file, or a link to a Flickr external detail means include the submodel // (Copied from data_entry_helper::build_sample_occurrence_submission. If file_box control is used // then build_submission calls wrap_with_images instead) if (array_key_exists('location:medium', $values) && $values['location:medium'] || array_key_exists('location_medium:external_details', $values) && $values['location_medium:external_details']) { $structure['submodel'] = array('model' => 'location_medium', 'fk' => 'location_id'); } $s = submission_builder::build_submission($values, $structure); // On first save of a new location, link it to the website. // Be careful not to over-write other subModels (e.g. images) if (empty($values['location:id'])) { $s['subModels'][] = array('fkId' => 'location_id', 'model' => array('id' => 'locations_website', 'fields' => array('website_id' => $args['website_id']))); // also, on first save we might be linking to a group if (!empty($values['group_id'])) { $s['subModels'][] = array('fkId' => 'location_id', 'model' => array('id' => 'groups_location', 'fields' => array('group_id' => $values['group_id']))); } } return $s; }
/** * Handles the construction of a submission array from a set of form values. * @param array $values Associative array of form data values. * @param array $args iform parameters. * @return array Submission structure. */ public static function get_submission($values, $args) { $subsampleModels = array(); $read = array('nonce' => $values['read_nonce'], 'auth_token' => $values['read_auth_token']); if (!isset($values['page']) || $values['page'] == 'site') { // submitting the first page, with top level sample details // keep the first count date on a subsample for use later. // only create if a new sample: if existing, then this will already exist. if (isset($values['C1:sample:date']) && !isset($values['sample:id'])) { $sampleMethods = helper_base::get_termlist_terms(array('read' => $read), 'indicia:sample_methods', array('Timed Count Count')); $smp = array('fkId' => 'parent_id', 'model' => array('id' => 'sample', 'fields' => array('survey_id' => array('value' => $values['sample:survey_id']), 'website_id' => array('value' => $values['website_id']), 'date' => array('value' => $values['C1:sample:date']), 'sample_method_id' => array('value' => $sampleMethods[0]['id']))), 'copyFields' => array('entered_sref' => 'entered_sref', 'entered_sref_system' => 'entered_sref_system')); // 'copyFields' => array('date_start'=>'date_start','date_end'=>'date_end','date_type'=>'date_type')); $subsampleModels[] = $smp; } } else { if ($values['page'] == 'occurrences') { // at this point there is a parent supersample. // loop from 1 to numberOfCounts, or number of existing subsamples, whichever is bigger. $subSamples = data_entry_helper::get_population_data(array('table' => 'sample', 'extraParams' => $read + array('parent_id' => $values['sample:id']), 'nocache' => true)); for ($i = 1; $i <= max(count($subSamples), $args['numberOfCounts']); $i++) { if (isset($values['C' . $i . ':sample:id']) || isset($values['C' . $i . ':sample:date']) && $values['C' . $i . ':sample:date'] != '') { $subSample = array('website_id' => $values['website_id'], 'survey_id' => $values['sample:survey_id']); $occurrences = array(); $occModels = array(); foreach ($values as $field => $value) { $parts = explode(':', $field, 2); if ($parts[0] == 'C' . $i) { $subSample[$parts[1]] = $value; } if ($parts[0] == 'O' . $i) { $occurrences[$parts[1]] = $value; } } ksort($occurrences); foreach ($occurrences as $field => $value) { // have take off O<i> do is now <j>:<ttlid>:<occid>:<attrid>:<attrvalid> - sorted in <j> order $parts = explode(':', $field); $occurrence = array('website_id' => $values['website_id']); if ($parts[1] != '--ttlid--') { $occurrence['taxa_taxon_list_id'] = $parts[1]; } if ($parts[2] != '--occid--') { $occurrence['id'] = $parts[2]; } if ($value == '') { $occurrence['deleted'] = 't'; } else { if ($parts[4] == '--valid--') { $occurrence['occAttr:' . $parts[3]] = $value; } else { $occurrence['occAttr:' . $parts[3] . ':' . $parts[4]] = $value; } } if (array_key_exists('occurrence:determiner_id', $values)) { $occurrence['determiner_id'] = $values['occurrence:determiner_id']; } if (array_key_exists('occurrence:record_status', $values)) { $occurrence['record_status'] = $values['occurrence:record_status']; } if (isset($occurrence['id']) || !isset($occurrence['deleted'])) { $occ = data_entry_helper::wrap($occurrence, 'occurrence'); $occModels[] = array('fkId' => 'sample_id', 'model' => $occ); } } $smp = array('fkId' => 'parent_id', 'model' => data_entry_helper::wrap($subSample, 'sample'), 'copyFields' => array('entered_sref' => 'entered_sref', 'entered_sref_system' => 'entered_sref_system')); // from parent->to child if (!isset($subSample['sample:deleted']) && count($occModels) > 0) { $smp['model']['subModels'] = $occModels; } $subsampleModels[] = $smp; } } } } $sampleMod = submission_builder::build_submission($values, array('model' => 'sample')); if (count($subsampleModels) > 0) { $sampleMod['subModels'] = $subsampleModels; } return $sampleMod; }
/** * Construct a submission for the location. * @param array $values Associative array of form data values. * @param array $args iform parameters. * @return array Submission structure. */ public static function get_submission($values, $args) { $s = submission_builder::build_submission($values, array('model' => 'location')); // on first save of a new transect, link it to the website. if (empty($values['location:id'])) { $s['subModels'] = array(array('fkId' => 'location_id', 'model' => array('id' => 'locations_website', 'fields' => array('website_id' => $args['website_id'])))); } return $s; }
/** * Handles the construction of a submission array from a set of form values. * @param array $values Associative array of form data values. * @param array $args iform parameters. * @return array Submission structure. */ public static function get_submission($values, $args) { return submission_builder::build_submission($values, array('model' => 'occurrence')); }
/** * Given a reject response, delete the invite, and redirect to the groups home page. * @param array $args Form config arguments * @param array $invite Invitation record */ private static function reject($args, $invite, $auth) { $values = array('id' => $invite['id'], 'deleted' => 't'); $s = submission_builder::build_submission($values, array('model' => 'group_invitation')); $r = data_entry_helper::forward_post_to('group_invitation', $s, $auth['write_tokens']); hostsite_show_message(lang::get("OK, thanks anyway. We've removed your invitation to join this group.")); hostsite_goto_page($args['groups_page_path']); }
/** * Performs the sending of invitation emails. * @param array $args Form configuration arguments * @param array $auth Authorisation tokens * @todo Integrate with notifications for logged in users. */ private static function sendInvites($args, $auth) { $emails = helper_base::explode_lines($_POST['invitee_emails']); // first task is to populate the groups_invitations table $base = uniqid(); $success = true; $failedRecipients = array(); foreach ($emails as $idx => $email) { $values = array('group_invitation:group_id' => $_GET['group_id'], 'group_invitation:email' => $email, 'group_invitation:token' => $base . $idx, 'website_id' => $args['website_id']); $s = submission_builder::build_submission($values, array('model' => 'group_invitation')); $r = data_entry_helper::forward_post_to('group_invitation', $s, $auth['write_tokens']); $pathParam = function_exists('variable_get') && variable_get('clean_url', 0) == '0' ? 'q' : ''; $rootFolder = data_entry_helper::getRootFolder() . (empty($pathParam) ? '' : "?{$pathParam}="); $protocol = !empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] != 'off' || $_SERVER['SERVER_PORT'] == 443 ? "https://" : "http://"; $acceptUrl = $protocol . $_SERVER['HTTP_HOST'] . $rootFolder . $args['accept_invite_path'] . (empty($pathParam) ? '?' : '&') . 'token=' . $base . $idx; $body = $_POST['invite_message'] . "<br/><br/>" . '<a href="' . $acceptUrl . '">' . lang::get('Accept this invitation') . '</a>'; $message = array('id' => 'iform_group_invite', 'to' => implode(',', $emails), 'subject' => 'Invitation to join a recording group', 'body' => $body, 'headers' => array('MIME-Version' => '1.0', 'Content-type' => 'text/html; charset=iso-8859-1')); $mimeheaders = array(); foreach ($message['headers'] as $name => $value) { $mimeheaders[] = $name . ': ' . mime_header_encode($value); } $thismailsuccess = mail($message['to'], mime_header_encode($message['subject']), str_replace("\r", '', $message['body']), join("\n", $mimeheaders)); if (!$thismailsuccess) { $failedRecipients[$message['to']] = $acceptUrl; } $success = $success && $thismailsuccess; } if ($success) { drupal_set_message(lang::get('Invitation emails sent')); } else { drupal_set_message(lang::get('The emails could not be sent due to a server configuration issue. Please contact the site admin. ' . 'The list below gives the emails and the links you need to send to each invitee which they need to click on in order to join the group.'), 'warning'); $list = array(); foreach ($failedRecipients as $email => $link) { $list[] = lang::get("Send link {1} to {2}.", $link, $email); } drupal_set_message(implode('<br/>', $list), 'warning'); } drupal_goto($args['redirect_on_success']); }
/** * Handles the construction of a submission array from a set of form values. * @param array $values Associative array of form data values. * @param array $args iform parameters. * @return array Submission structure. */ public static function get_submission($values, $args) { global $user; $subsampleModels = array(); $submission = submission_builder::build_submission($values, array('model' => 'sample')); // this handles the photos as well. // deal with any species grid options. foreach ($values as $key => $value) { $parts = explode(':', $key, 5); if ($parts[0] == 'Grid') { $details = explode(':', $parts[4], 3); if (!isset($subsampleModels[$parts[1]])) { $smp = array('fkId' => 'parent_id', 'model' => array('id' => 'sample', 'fields' => array('sample_method_id' => array('value' => $args['quadrat_level_sample_method_id']))), 'data' => $parts[2] != '', 'copyFields' => array('survey_id' => 'survey_id', 'date_start' => 'date_start', 'date_end' => 'date_end', 'date_type' => 'date_type', 'entered_sref_system' => 'entered_sref_system', 'entered_sref' => 'entered_sref', 'location_name' => 'location_name')); // from parent->to child if ($parts[2] != '') { // set any existing subsample id $smp['model']['fields']['id'] = array('value' => $parts[2]); } $subsampleModels[$parts[1]] = $smp; } if ($parts[3] == 'smpAttr') { $subsampleModels[$parts[1]]['model']['fields']['smpAttr:' . $parts[4]] = array('value' => $value); if ($details[0] != $args['sample_attribute_id_1'] && (!isset($args['sample_attribute_id_2']) || $args['sample_attribute_id_2'] == '' || $details[0] != $args['sample_attribute_id_2'])) { $subsampleModels[$parts[1]]['data'] = $subsampleModels[$parts[1]]['data'] || $value != ''; } } else { if ($parts[3] == 'occ') { $occ = array('fkId' => 'sample_id', 'model' => array('id' => 'occurrence', 'fields' => array('taxa_taxon_list_id' => array('value' => $details[0]), 'website_id' => array('value' => $values['website_id']), 'record_status' => array('value' => $values['occurrence:record_status']), 'zero_abundance' => array('value' => $value != '0' ? 'f' : 't'), $details[2] => array('value' => $value)))); if ($details[1] != '') { $occ['model']['fields']['id'] = array('value' => $details[1]); } if ($value != '' || $details[1] != '') { if (!isset($subsampleModels[$parts[1]]['model']['subModels'])) { $subsampleModels[$parts[1]]['model']['subModels'] = array($occ); } else { $subsampleModels[$parts[1]]['model']['subModels'][] = $occ; } $subsampleModels[$parts[1]]['data'] = true; } } } } } foreach ($subsampleModels as $row => $data) { if (!$subsampleModels[$row]['data']) { unset($subsampleModels[$row]); } } if (count($subsampleModels) > 0) { $submission['subModels'] = array_merge(isset($submission['subModels']) && is_array($submission['subModels']) ? $submission['subModels'] : array(), array_values($subsampleModels)); //if($user->uid == 1) // drupal_set_message(print_r($submission,true), 'warning'); } return $submission; }
/** * Controller action that performs the import of data in an uploaded CSV file. * Allows $_GET parameters to specify the filepos, offset and limit when uploading just a chunk at a time. * This method is called to perform the entire upload when JavaScript is not enabled, or can * be called to perform part of an AJAX csv upload where only a part of the data is imported * on each call. * Requires a $_GET parameter for uploaded_csv - the uploaded file name. */ public function upload() { $csvTempFile = DOCROOT . "upload/" . $_GET['uploaded_csv']; $metadata = $this->_get_metadata($_GET['uploaded_csv']); if (!empty($metadata['user_id'])) { global $remoteUserId; $remoteUserId = $metadata['user_id']; } // Check if details of the last supermodel (e.g. sample for an occurrence) are in the cache from a previous iteration of // this bulk operation $cache = Cache::instance(); $this->getPreviousRowSupermodel($cache); // enable caching of things like language lookups ORM::$cacheFkLookups = true; // make sure the file still exists if (file_exists($csvTempFile)) { // Following helps for files from Macs ini_set('auto_detect_line_endings', 1); // create the file pointer, plus one for errors $handle = fopen($csvTempFile, "r"); $this->checkIfUtf8($metadata, $handle); $errorHandle = $this->_get_error_file_handle($csvTempFile, $handle); $count = 0; $limit = isset($_GET['limit']) ? $_GET['limit'] : false; $filepos = isset($_GET['filepos']) ? $_GET['filepos'] : 0; $offset = isset($_GET['offset']) ? $_GET['offset'] : 0; if ($filepos == 0) { // first row, so skip the header fseek($handle, 0); fgetcsv($handle, 1000, ","); // also clear the lookup cache $cache->delete_tag('lookup'); } else { // skip rows to allow for the last file position fseek($handle, $filepos); } $model = ORM::Factory($_GET['model']); $this->submissionStruct = $model->get_submission_structure(); // special date processing. $index = 0; $dayColumn = false; $monthColumn = false; $yearColumn = false; foreach ($metadata['mappings'] as $col => $attr) { // skip cols to do with remembered mappings if ($col !== 'RememberAll' && substr($col, -9) !== '_Remember') { switch ($attr) { case 'sample:date:day': $dayColumn = $index; case 'sample:date:month': $monthColumn = $index; case 'sample:date:year': $yearColumn = $index; } $index++; } } $processDate = $dayColumn !== false && $monthColumn !== false && $yearColumn !== false; // initially has to have all 3 fields: TODO vaguer dates? while (($data = fgetcsv($handle, 1000, ",")) !== FALSE && ($limit === false || $count < $limit)) { if (!array_filter($data)) { // skip empty rows continue; } $count++; $index = 0; $saveArray = $model->getDefaults(); // Note, the mappings will always be in the same order as the columns of the CSV file foreach ($metadata['mappings'] as $col => $attr) { // skip cols to do with remembered mappings if ($col !== 'RememberAll' && substr($col, -9) !== '_Remember') { if (isset($data[$index])) { // '<Please select>' is a value fixed in import_helper::model_field_options if ($attr != '<Please select>' && $data[$index] !== '') { // Add the data to the record save array. Utf8 encode if file does not have UTF8 BOM. $saveArray[$attr] = $metadata['isUtf8'] ? $data[$index] : utf8_encode($data[$index]); } } else { // This is one of our static fields at the end $saveArray[$col] = $attr; } $index++; } } if ((!isset($saveArray['sample:date']) || $saveArray['sample:date'] == '') && $processDate) { $saveArray['sample:date'] = $data[$yearColumn] . '-' . sprintf('%02d', $data[$monthColumn]) . '-' . sprintf('%02d', $data[$dayColumn]); // initially has to have all 3 fields: TODO vaguer dates? unset($saveArray['sample:date:day']); unset($saveArray['sample:date:month']); unset($saveArray['sample:date:year']); } // copy across the fixed values, including the website id, into the data to save. if ($metadata['settings']) { $saveArray = array_merge($metadata['settings'], $saveArray); } if (!empty($saveArray['website_id'])) { // automatically join to the website if relevant if (isset($this->submissionStruct['joinsTo']) && in_array('websites', $this->submissionStruct['joinsTo'])) { $saveArray['joinsTo:website:' . $saveArray['website_id']] = 1; } } // Check if in an association situation $associationExists = false; if (self::_check_module_active($this->submissionStruct['model'] . '_associations')) { // assume model has attributes. $attrDetails = $model->get_attr_details(); $associatedSuffix = '_2'; $associatedRecordSubmissionStructure = $this->submissionStruct; $originalRecordPrefix = $this->submissionStruct['model']; $originalAttributePrefix = $attrDetails['attrs_field_prefix']; $originalMediaPrefix = $originalRecordPrefix . '_media'; $associatedRecordPrefix = $originalRecordPrefix . $associatedSuffix; $associatedAttributePrefix = $originalAttributePrefix . $associatedSuffix; $associatedMediaPrefix = $originalMediaPrefix . $associatedSuffix; $associationRecordPrefix = $originalRecordPrefix . '_association'; // find out if association or associated records exist foreach ($saveArray as $assocField => $assocValue) { $associationExists = $associationExists || substr($assocField, 0, strlen($associationRecordPrefix)) == $associationRecordPrefix || substr($assocField, 0, strlen($associatedRecordPrefix)) == $associatedRecordPrefix; } } // If posting a supermodel, are the details of the supermodel the same as for the previous CSV row? If so, we can link to that // record rather than create a new supermodel record. $updatedPreviousCsvSupermodelDetails = $this->checkForSameSupermodel($saveArray, $model, $associationExists); // Clear the model, so nothing else from the previous row carries over. $model->clear(); // Save the record $model->set_submission_data($saveArray, true); /* At this point, if model has associations (i.e. a module is active called <modelSingular>_associations) we flip the submission so the model becomes the subModel. This way we can bolt any second associated record in, into the submodel array. */ // GvB TODO alter automatic mappings to set up secondary occurrences correctly. if ($associationExists && isset($model->submission['superModels']) && is_array($model->submission['superModels']) && count($model->submission['superModels']) === 1) { // We are assuming only one superModel, which must exist at this point. // Use key 'record1' into the subModel array so association record knows which is which. unset($associatedRecordSubmissionStructure['superModels']); // we are using the previously wrapped superModel // flip then bolt in as second submodel to the supermodel using key 'record2', $submissionData = $model->submission; $superModelSubmission = $submissionData['superModels'][0]['model']; $superModelFK = $submissionData['superModels'][0]['fkId']; $superModel = ORM::Factory($superModelSubmission['id']); $superModel->clear(); unset($submissionData['superModels']); // try to wrap second record of original model. // as the submission builder needs a 1-1 match between field prefix and model name, we need to generate an altered saveArray. $associatedArray = array(); foreach ($saveArray as $fieldname => $value) { $parts = explode(':', $fieldname); // filter out original model feilds, any of its attributes and media records. if ($parts[0] != $originalRecordPrefix && $parts[0] != $originalAttributePrefix && $parts[0] != $originalMediaPrefix) { if ($parts[0] == $associatedRecordPrefix) { $parts[0] = $originalRecordPrefix; } else { if ($parts[0] == $associatedAttributePrefix) { $parts[0] = $originalAttributePrefix; } else { if ($parts[0] == $associatedMediaPrefix) { $parts[0] = $originalMediaPrefix; } } } $associatedArray[implode(':', $parts)] = $value; } } $associatedSubmission = submission_builder::build_submission($associatedArray, $associatedRecordSubmissionStructure); // func already loaded for previous wrap // Map fk_* fields to the looked up id $associatedSubmission = $model->getFkFields($associatedSubmission, $associatedArray); // wrap the association and bolt in as a submodel of original model, using '||record2||' pointer. $association = ORM::Factory($associationRecordPrefix); $association->set_submission_data($saveArray, true); $association->submission['fields']['to_' . $associatedRecordSubmissionStructure['model'] . '_id'] = array('value' => '||record2||'); $submissionData['subModels'] = array(array('fkId' => 'from_' . $associatedRecordSubmissionStructure['model'] . '_id', 'model' => $association->submission)); $superModelSubmission['subModels'] = array('record1' => array('fkId' => $superModelFK, 'model' => $submissionData), 'record2' => array('fkId' => $superModelFK, 'model' => $associatedSubmission)); $superModel->submission = $superModelSubmission; $model = $superModel; } else { $associationExists = false; } if (($id = $model->submit()) == null) { // Record has errors - now embedded in model, so dump them into the error file $errors = array(); foreach ($model->getAllErrors() as $field => $msg) { $fldTitle = array_search($field, $metadata['mappings']); $fldTitle = $fldTitle ? $fldTitle : $field; $errors[] = "{$fldTitle}: {$msg}"; } $errors = implode("\n", array_unique($errors)); $data[] = $errors; $data[] = $count + $offset + 1; // 1 for header fputcsv($errorHandle, $data); kohana::log('debug', 'Failed to import CSV row: ' . $errors); $metadata['errorCount'] = $metadata['errorCount'] + 1; } else { // now the record has successfully posted, we need to store the details of any new supermodels and their Ids, // in case they are duplicated in the next csv row. $this->previousCsvSupermodel['details'] = array_merge($this->previousCsvSupermodel['details'], $updatedPreviousCsvSupermodelDetails); $this->captureSupermodelIds($model, $associationExists); } // get file position here otherwise the fgetcsv in the while loop will move it one record too far. $filepos = ftell($handle); } // Get percentage progress $progress = $filepos * 100 / filesize($csvTempFile); $r = "{\"uploaded\":{$count},\"progress\":{$progress},\"filepos\":{$filepos}}"; // allow for a JSONP cross-site request if (array_key_exists('callback', $_GET)) { $r = $_GET['callback'] . "(" . $r . ")"; } echo $r; fclose($handle); fclose($errorHandle); self::internal_cache_upload_metadata($metadata); // An AJAX upload request will just receive the number of records uploaded and progress $this->auto_render = false; $cache->set(basename($csvTempFile) . 'previousSupermodels', $this->previousCsvSupermodel); } }