/** * Prints the supplied string to "standard error" (STDERR) instead of the "standard output" (STDOUT) stream * * @param string $source_csv_filename The CSV import file containing the asset attribute and metadata field specifications * @param string $asset_type_code The Matrix asset type code or the assets which are to be created * @param object $parent_id The asset ID of the parent asset under which the new assets are to reside * @param int $schema_id The asset ID of the Metadata Schema to associate with the new assets * @param array $metadata_mapping A structure containing Supplied Field Name to Metadata Field asset ID associations * @param array $attribute_mapping A structure containing Supplied Field Name to Asset Attribute Name associations * @param boolean$new_assets_live When set to TRUE, assets created during the import will be set to 'Live' * @param string $unique_record_field The CSV field to be treated as a primary identifier for editing and deletion purposes * @param string $record_modification_field The CSV field to determine whether the associated record is to be (A)dded, (E)dited, or (D)eleted * @param array $ignore_fields The fields for the ignoring * * @return array * @access public */ function importAssets($source_csv_filename, $asset_type_code, $parent_id, $schema_id, array $metadata_mapping, array $attribute_mapping, $new_assets_live = FALSE, $unique_record_field = '', $record_modification_field = '', array $ignore_fields = array()) { $GLOBALS['SQ_SYSTEM']->setRunLevel(SQ_RUN_LEVEL_FORCED); $num_assets_imported = 0; $num_assets_modified = 0; $num_assets_deleted = 0; $csv_fd = fopen($source_csv_filename, 'r'); if (!$csv_fd) { printUsage(); printStdErr("* The supplied CSV import file was not found\n\n"); fclose($csv_fd); exit(-6); } $parent_asset = $GLOBALS['SQ_SYSTEM']->am->getAsset($parent_id); if (!$parent_asset->id) { printUsage(); printStdErr("* The specified parent asset was not found\n\n"); exit(-7); } $header_line = TRUE; $headers = array(); $trash = $GLOBALS['SQ_SYSTEM']->am->getSystemAsset('trash_folder'); $root_folder = $GLOBALS['SQ_SYSTEM']->am->getSystemAsset('root_folder'); // Set to true if temporary trash folder is created, where all the assets to be deleted are moved to $temp_trash_folder = FALSE; while (($data = fgetcsv($csv_fd, 0, ',')) !== FALSE) { $num_fields = count($data); $asset_spec = array(); foreach ($data as $key => $val) { if ($header_line) { $headers[$key] = trim($val); } else { $asset_spec[$headers[$key]] = $val; } } if ($header_line) { $header_line = FALSE; } else { // If a Record Modification Field was specified, we also require that a Unique Field was specified for the import // These two fields must be present in the CSV file for us to Edit and Delete existing assets. Otherwise, we'll just add $record_handling = IMPORT_ADD_RECORD; if (!empty($unique_record_field) && !empty($record_modification_field) && isset($asset_spec[$unique_record_field]) && isset($asset_spec[$record_modification_field])) { $record_modification_state = strtoupper($asset_spec[$record_modification_field]); switch ($record_modification_state) { case 'D': $record_handling = IMPORT_DELETE_RECORD; break; case 'E': $record_handling = IMPORT_EDIT_RECORD; break; } // Okey dokey, let's find the existing asset as we are either performing an (E)dit or (D)elete operation... // Also try to find an existing asset as we may be unfortunately performing an (A)dd that matches the unique // identifier, in which case we are probably intending to (E)dit the existing matching asset $existing_asset_id = 0; // Our search is limited to the exact asset type used for the import, and the parent root node (and children) specified // The unique field may be either one to be assigned to an attribute or to a metadata field $search_field = ''; $search_value = ''; if (isset($metadata_mapping[$unique_record_field])) { $search_type = 'metadata'; $search_field = $metadata_mapping[$unique_record_field]; $search_value = $asset_spec[$unique_record_field]; } if (isset($attribute_mapping[$unique_record_field])) { $search_type = 'attribute'; $search_field = $attribute_mapping[$unique_record_field]; $search_value = $asset_spec[$unique_record_field]; } $search = array($search_type => array('field' => $search_field, 'value' => $search_value)); $existing_assets = findAsset($parent_id, $asset_type_code, $search); if (count($existing_assets) > 1) { // Multiple matching assets - skip echo "\n*\t* The record for '" . $search_value . "' matched multiple existing assets. Cannot determine how to proceed - continuing to the next record.\n"; continue; } $existing_asset_id = reset($existing_assets); // If it is an (E)dit request and the asset was not found, then let's make it an (A)dd instead if (empty($existing_assets) && $record_handling == IMPORT_EDIT_RECORD) { echo "\n*\t* The following 'Edit' request for '" . $search_value . "' has been changed to 'Add' as there is not an existing matching asset\n"; $record_handling = IMPORT_ADD_RECORD; } // If it's there and we wanted to (A)dd, then make it an (E)dit instead if ($existing_asset_id > 0 && $record_handling == IMPORT_ADD_RECORD) { echo "\n*\t* The following 'Add' request for '" . $search_value . "' has been changed to 'Edit' as this asset already exists.\n"; $record_handling = IMPORT_EDIT_RECORD; } // If it is a (D)elete request and the asset was not found, then skip this record gracefully if (empty($existing_assets) && $record_handling == IMPORT_DELETE_RECORD) { echo "\n*\t* Deletion request for asset with unique field value '" . $search_value . "' was aborted due to a missing matching asset. Continuing to the next record.\n"; continue; } if ($record_handling == IMPORT_DELETE_RECORD) { // Deletify echo '- Deleting asset'; $asset = $GLOBALS['SQ_SYSTEM']->am->getAsset($existing_asset_id); if ($asset) { // Create temporary trash folder, if not already created if (!$temp_trash_folder) { $GLOBALS['SQ_SYSTEM']->am->includeAsset('folder'); $temp_trash_folder = new Folder(); $temp_trash_folder->setAttrValue('name', 'temp_trash_folder'); $link_array = array('asset' => $root_folder, 'value' => '', 'link_type' => SQ_LINK_TYPE_1); $linkid = $temp_trash_folder->create($link_array); // If cannot create the temporary trash folder then we cannot delete any asset if (!$linkid) { echo "\n*\t* Deletion request for asset with unique field value '" . $search_value . "' was aborted due to unable to create temporary trash folder. Continuing to the next record.\n"; $GLOBALS['SQ_SYSTEM']->am->forgetAsset($asset); continue; } } // Move the asset to the temporary trash folder $asset_linkid_old = $GLOBALS['SQ_SYSTEM']->am->getLinkByAsset($parent_id, $asset->id); $linkid = $GLOBALS['SQ_SYSTEM']->am->moveLink($asset_linkid_old['linkid'], $temp_trash_folder->id, SQ_LINK_TYPE_1, -1); // If cannot move the asset to temporary trash folder then it cannot be deleted if (!$linkid) { echo "\n*\t* Deletion request for asset with unique field value '" . $search_value . "' was aborted due to unable to move this asset to temporary trash folder. Continuing to the next record.\n"; $GLOBALS['SQ_SYSTEM']->am->forgetAsset($asset); continue; } echo $search_value . ',' . $existing_asset_id . ",D\n"; $num_assets_deleted++; } // End if asset } else { if ($record_handling == IMPORT_EDIT_RECORD) { // Editise // Ok we are editing - has the user specified fields to ignore at this point? If so, let's eliminificate foreach ($ignore_fields as $ignore_field_name => $val) { if (isset($asset_spec[$ignore_field_name])) { unset($asset_spec[$ignore_field_name]); } } echo '- Modifying asset with unique field value'; editAsset($existing_asset_id, $asset_spec, $attribute_mapping, $metadata_mapping, $schema_id); echo $search_value . ',' . $existing_asset_id . ",E\n"; $num_assets_modified++; } } } if ($record_handling == IMPORT_ADD_RECORD) { $asset_info = createAsset($asset_spec, $asset_type_code, $parent_asset, $schema_id, $metadata_mapping, $attribute_mapping); $asset_id = 0; if (is_array($asset_info)) { $asset_id = reset($asset_info); } if ($asset_id) { // Ok see if we need to set it live if ($new_assets_live) { $new_asset = $GLOBALS['SQ_SYSTEM']->am->getAsset($asset_id); $new_asset->processStatusChange(SQ_STATUS_LIVE); $GLOBALS['SQ_SYSTEM']->am->forgetAsset($new_asset); } echo key($asset_info) . ',' . $asset_id . ",A\n"; $num_assets_imported++; } } } } // End while fclose($csv_fd); $GLOBALS['SQ_SYSTEM']->restoreRunLevel(); // Now actually delete all the assets moved to "temporary purge folder" by purging this folder if ($temp_trash_folder && $GLOBALS['SQ_SYSTEM']->am->trashAsset($temp_trash_folder->id)) { $trash_folder = $GLOBALS['SQ_SYSTEM']->am->getSystemAsset('trash_folder'); $trash_linkid = $GLOBALS['SQ_SYSTEM']->am->getLinkByAsset($trash_folder->id, $temp_trash_folder->id); if (isset($trash_linkid['linkid']) && $trash_linkid['linkid'] > 0) { $hh = $GLOBALS['SQ_SYSTEM']->getHipoHerder(); $vars = array('purge_root_linkid' => $trash_linkid['linkid']); $errors = $hh->freestyleHipo('hipo_job_purge_trash', $vars); if (!empty($errors)) { $error_msg = ''; foreach ($errors as $error) { $error_msg .= ' * ' . $error['message']; } echo "Following errors occured while deleting asset(s):\n{$error_msg}\n"; } } } $status_report = array('num_added' => $num_assets_imported, 'num_modified' => $num_assets_modified, 'num_deleted' => $num_assets_deleted); return $status_report; }
if (!empty($linkid)) { // purge trash hipo will know what to do $vars['purge_root_linkid'] = $linkid; } else { printStdErr("Purge root node assetid id #" . $purge_rootnode . " not found\n"); exit(1); } } $hh = $GLOBALS['SQ_SYSTEM']->getHipoHerder(); $errors = $hh->freestyleHipo('hipo_job_purge_trash', $vars); if (!empty($errors)) { $error_msg = ''; foreach ($errors as $error) { $error_msg .= ' * ' . $error['message']; } printStdErr("Following errors occured while deleting asset(s):\n{$error_msg}\n"); exit(1); } /** * Prints the supplied string to "standard error" (STDERR) instead of the "standard output" (STDOUT) stream * * @param string $string The string to write to STDERR * * @return void * @access public */ function printStdErr($string) { fwrite(STDERR, "{$string}"); } //end printStdErr()
/** * Ensures that the XML mapping contains a correct and complete definition of the target metadata schema * * @param array &$metadata_mapping The metadata mapping structure which is used to import the CSV data * * @return void * @access public */ function validateMetadataMapping(&$metadata_mapping) { // Start Matrix printStdErr('- Initialising Matrix...'); // Check the schema is available in the system $schema_asset = $GLOBALS['SQ_SYSTEM']->am->getAsset($metadata_mapping['metadata_schema_id']); if (!$schema_asset) { printStdErr('* The supplied schema (ID: ' . $metadata_mapping['metadata_schema_id'] . ") could not be found in the system\n"); exit(-21); } if ($schema_asset->type() != 'metadata_schema') { printStdErr('* The supplied schema (ID: ' . $metadata_mapping['metadata_schema_id'] . ") is not a valid Metadata Schema in the system\n"); exit(-22); } // Now we have the schema, find its fields and make sure that they were specified $mm = $GLOBALS['SQ_SYSTEM']->getMetadataManager(); $metadata_fields = $mm->getMetadataFields(array($metadata_mapping['metadata_schema_id'])); // Fields specified in the system... $metadata_system_field_ids = array_keys($metadata_fields); $metadata_mapping_field_ids = array_values($metadata_mapping['metadata_fields']); $metadata_differences = array_diff($metadata_system_field_ids, $metadata_mapping_field_ids); if (count($metadata_differences) > 0) { printStdErr('* One or more system metadata fields were not specified in the mapping file'); printStdErr(' The following metadata field IDs are required:'); foreach ($metadata_differences as $metadata_field_id) { printStdErr(' ' . $metadata_field_id); } exit(-23); } // All expected metadata fields were defined in the mapping file. Add the data types to our mapping. // This will be used while importing to verify that the fields are correct $metadata_mapping['metadata_field_types'] = $metadata_fields; $am = $GLOBALS['SQ_SYSTEM']->am; foreach ($metadata_fields as $metadata_field_id => $metadata_field_type) { $metadata_field_type = $metadata_field_type[0]['type_code']; $field = $am->getAsset($metadata_field_id, $metadata_field_type); $metadata_mapping['metadata_field_objects'][$metadata_field_id] = $field; if ($field->attr('required')) { if (isset($metadata_mapping['metadata_ignored_fields'][$metadata_field_id])) { printStdErr('* The metadata field (ID ' . $metadata_field_id . ') cannot be ignored upon import as it is mandatory'); exit(-24); } $metadata_mapping['metadata_required_fields'][$metadata_field_id] = 1; } } }
/** * Assigns a title attribute value to a selected asset * * @param int $asset_id The asset ID * @param string $asset_title The title to be set for the asset * * @return boolean * @access public */ function setAssetTitle($asset_id, $asset_title) { $success = FALSE; $asset =& $GLOBALS['SQ_SYSTEM']->am->getAsset($asset_id); if ($asset->id) { // Make sure that we have a 'title' attribute $current_title = $asset->attr('title'); if ($current_title == NULL) { printStdErr('* Asset ID ' . $asset_id . " does not have a title field, so one cannot be assigned.\n"); printStdErr('User Options ------------'); printStdErr('(I)gnore this asset and continue with modification of titles'); printStdErr('(C)ancel modification script'); $user_choice = getUserInput(array('i', 'c')); if ($user_choice == 'c') { printStdErr("\n- Titles modification cancelled by user"); exit(-7); } } else { // Set the 'title' attribute for the asset $asset->setAttrValue('title', $asset_title); $asset->saveAttributes(); // Read back the title to ensure that it is set as expected $success = $asset->attr('title') == $asset_title; if (!$success) { printStdErr('* The title "' . $asset_title . '" could not be set for asset ID ' . $asset_id . "\n"); printStdErr('User Options ------------'); printStdErr('(I)gnore this asset and continue with modification of titles'); printStdErr('(C)ancel modification script'); $user_choice = getUserInput(array('i', 'c')); if ($user_choice == 'c') { printStdErr("\n- Titles modification cancelled by user"); exit(-8); } } } } //end if return $success; }
/** * Creates a Folder asset with the specified name and parent * * @param string $name The name of the Folder to create * @param object &$parent_folder The parent asset * * @return int * @access public */ function createFolder($name, &$parent_folder) { printStdErr('- Creating Folder ' . $name); $folder = new Folder(); printStdErr('.'); // Set Folder name $folder->setAttrValue('name', $name); printStdErr('.'); // Link the new asset under the parent folder $link_id = createLink($parent_folder, $folder); printStdErr('.'); // Free memory $GLOBALS['SQ_SYSTEM']->am->forgetAsset($folder); printStdErr(' => asset ID ' . $folder->id . "\n"); echo formatCSVValue($name) . ',' . $folder->id; return $folder->id; }