60 define(
'IMPORT_ADD_RECORD', 1);
61 define(
'IMPORT_EDIT_RECORD', 2);
62 define(
'IMPORT_DELETE_RECORD', 4);
73 printStdErr(
"Source CSV file to Matrix importer\n\n");
74 printStdErr(
"Usage: import_asset_csv_to_matrix [system root] [type code] [csv import file] [parent id] [schema id] [meta map file] [attr map file] (new assets live) (unique field name) (add edit delete field name)\n\n");
75 printStdErr(
"REQUIRED ARGUMENTS\n");
76 printStdErr(
"====================================================\n");
77 printStdErr(
"system root : The Matrix System root directory\n");
78 printStdErr(
"type code : The Matrix Asset Type Code of the assets to import\n");
79 printStdErr(
"csv import file : A CSV file containing the records to import as Matrix assets\n");
80 printStdErr(
"parent id : The asset ID of a Folder etc. under which the assets are to reside\n");
81 printStdErr(
"schema id : The asset ID of the Metadata Schema to apply to each asset\n");
82 printStdErr(
"meta map file : A CSV file containing attribute name-to-metadata field ID associations\n");
83 printStdErr(
"attr map file : A CSV file containing attribute name-to-asset attribute field associations\n");
85 printStdErr(
"OPTIONAL ARGUMENTS\n");
86 printStdErr(
"====================================================\n");
87 printStdErr(
"new assets live : When set to '1' all assets added by the import will be set to 'Live'\n");
88 printStdErr(
"unique field name : The field in the CSV file to be used for (A)dding, (E)diting, or (D)eleting\n");
89 printStdErr(
" assets referenced by imported data\n");
90 printStdErr(
"add edit delete\n");
91 printStdErr(
" field name : The field in the CSV file used to determine the operation performed on imported data\n");
92 printStdErr(
"ignore csv file : A single column file which specifies the fields to be ignored when editing an existing asset (eg; when importing User\n");
93 printStdErr(
" passwords from an Add operation but don't want to overwrite them during an Edit operation\n");
106 function printStdErr($string)
108 fwrite(STDERR,
"$string");
130 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())
132 $GLOBALS[
'SQ_SYSTEM']->setRunLevel(SQ_RUN_LEVEL_FORCED);
134 $num_assets_imported = 0;
135 $num_assets_modified = 0;
136 $num_assets_deleted = 0;
138 $csv_fd = fopen($source_csv_filename,
'r');
141 printStdErr(
"* The supplied CSV import file was not found\n\n");
146 $parent_asset = $GLOBALS[
'SQ_SYSTEM']->am->getAsset($parent_id);
147 if (!$parent_asset->id) {
149 printStdErr(
"* The specified parent asset was not found\n\n");
156 $trash = $GLOBALS[
'SQ_SYSTEM']->am->getSystemAsset(
'trash_folder');
157 $root_folder = $GLOBALS[
'SQ_SYSTEM']->am->getSystemAsset(
'root_folder');
160 $temp_trash_folder = FALSE;
162 while (($data = fgetcsv($csv_fd, 0,
',')) !== FALSE) {
163 $num_fields = count($data);
165 $asset_spec = Array();
167 foreach ($data as $key => $val) {
169 $headers[$key] = trim($val);
171 $asset_spec[$headers[$key]] = $val;
176 $header_line = FALSE;
180 $record_handling = IMPORT_ADD_RECORD;
182 if (!empty($unique_record_field) && !empty($record_modification_field) && isset($asset_spec[$unique_record_field]) && isset($asset_spec[$record_modification_field])) {
183 $record_modification_state = strtoupper($asset_spec[$record_modification_field]);
184 switch ($record_modification_state) {
185 case 'D': $record_handling = IMPORT_DELETE_RECORD;
188 case 'E': $record_handling = IMPORT_EDIT_RECORD;
195 $existing_asset_id = 0;
202 if (isset($metadata_mapping[$unique_record_field])) {
203 $search_type =
'metadata';
204 $search_field = $metadata_mapping[$unique_record_field];
205 $search_value = $asset_spec[$unique_record_field];
208 if (isset($attribute_mapping[$unique_record_field])) {
209 $search_type =
'attribute';
210 $search_field = $attribute_mapping[$unique_record_field];
211 $search_value = $asset_spec[$unique_record_field];
214 $search = Array($search_type => Array(
215 'field' => $search_field,
216 'value' => $search_value,
220 $existing_assets = findAsset($parent_id, $asset_type_code, $search);
221 if (count($existing_assets) > 1) {
223 printStdErr(
"\n*\t* The record for '".$search_value.
"' matched multiple existing assets. Cannot determine how to proceed - continuing to the next record.\n");
227 $existing_asset_id = reset($existing_assets);
230 if (empty($existing_assets) && ($record_handling == IMPORT_EDIT_RECORD)) {
231 printStdErr(
"\n*\t* The following 'Edit' request for '".$search_value.
"' has been changed to 'Add' as there is not an existing matching asset\n");
232 $record_handling = IMPORT_ADD_RECORD;
236 if (($existing_asset_id > 0) && ($record_handling == IMPORT_ADD_RECORD)) {
237 printStdErr(
"\n*\t* The following 'Add' request for '".$search_value.
"' has been changed to 'Edit' as this asset already exists.\n");
238 $record_handling = IMPORT_EDIT_RECORD;
242 if (empty($existing_assets) && ($record_handling == IMPORT_DELETE_RECORD)) {
243 printStdErr(
"\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");
247 if ($record_handling == IMPORT_DELETE_RECORD) {
250 printStdErr(
'- Deleting asset');
251 $asset = $GLOBALS[
'SQ_SYSTEM']->am->getAsset($existing_asset_id);
256 if (!$temp_trash_folder) {
258 $GLOBALS[
'SQ_SYSTEM']->am->includeAsset(
'folder');
259 $temp_trash_folder =
new Folder();
261 $temp_trash_folder->setAttrValue(
'name',
'temp_trash_folder');
262 $link_array = Array (
263 'asset' => $root_folder,
265 'link_type' => SQ_LINK_TYPE_1,
267 $linkid = $temp_trash_folder->create($link_array);
271 printStdErr(
"\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");
273 $GLOBALS[
'SQ_SYSTEM']->am->forgetAsset($asset);
279 $asset_linkid_old = $GLOBALS[
'SQ_SYSTEM']->am->getLinkByAsset($parent_id, $asset->id);
280 $linkid = $GLOBALS[
'SQ_SYSTEM']->am->moveLink($asset_linkid_old[
'linkid'], $temp_trash_folder->id, SQ_LINK_TYPE_1, -1);
284 printStdErr(
"\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");
286 $GLOBALS[
'SQ_SYSTEM']->am->forgetAsset($asset);
290 echo $search_value.
','.$existing_asset_id.
",D\n";
291 $num_assets_deleted++;
294 }
else if ($record_handling == IMPORT_EDIT_RECORD) {
298 foreach ($ignore_fields as $ignore_field_name => $val) {
299 if (isset($asset_spec[$ignore_field_name])) {
300 unset($asset_spec[$ignore_field_name]);
304 printStdErr(
'- Modifying asset with unique field value');
305 editAsset($existing_asset_id, $asset_spec, $attribute_mapping, $metadata_mapping, $schema_id);
306 echo $search_value.
','.$existing_asset_id.
",E\n";
307 $num_assets_modified++;
311 if ($record_handling == IMPORT_ADD_RECORD) {
312 $asset_info = createAsset($asset_spec, $asset_type_code, $parent_asset, $schema_id, $metadata_mapping, $attribute_mapping);
314 if (is_array($asset_info)) {
315 $asset_id = reset($asset_info);
320 if ($new_assets_live) {
321 $new_asset = $GLOBALS[
'SQ_SYSTEM']->am->getAsset($asset_id);
322 $new_asset->processStatusChange(SQ_STATUS_LIVE);
323 $GLOBALS[
'SQ_SYSTEM']->am->forgetAsset($new_asset);
326 echo key($asset_info).
','.$asset_id.
",A\n";
327 $num_assets_imported++;
337 $GLOBALS[
'SQ_SYSTEM']->restoreRunLevel();
340 if ($temp_trash_folder && $GLOBALS[
'SQ_SYSTEM']->am->trashAsset($temp_trash_folder->id)) {
342 $trash_folder = $GLOBALS[
'SQ_SYSTEM']->am->getSystemAsset(
'trash_folder');
343 $trash_linkid = $GLOBALS[
'SQ_SYSTEM']->am->getLinkByAsset($trash_folder->id, $temp_trash_folder->id);
345 if (isset($trash_linkid[
'linkid']) && $trash_linkid[
'linkid'] > 0) {
347 $hh = $GLOBALS[
'SQ_SYSTEM']->getHipoHerder();
350 'purge_root_linkid' => $trash_linkid[
'linkid'],
353 $errors = $hh->freestyleHipo(
'hipo_job_purge_trash', $vars);
355 if (!empty($errors)) {
357 foreach($errors as $error) {
358 $error_msg .=
' * '.$error[
'message'];
360 echo
"Following errors occured while deleting asset(s):\n$error_msg\n";
366 $status_report = Array(
367 'num_added' => $num_assets_imported,
368 'num_modified' => $num_assets_modified,
369 'num_deleted' => $num_assets_deleted,
372 return $status_report;
383 function editAsset($asset_id, Array $asset_spec, Array $attribute_mapping, Array $metadata_mapping, $schema_id)
385 $asset = $GLOBALS[
'SQ_SYSTEM']->am->getAsset($asset_id);
388 editAttributes($asset, $asset_spec, $attribute_mapping);
392 editMetadata($asset, $asset_spec, $metadata_mapping, $schema_id);
396 $GLOBALS[
'SQ_SYSTEM']->am->forgetAsset($asset);
398 printStdErr(
' => asset ID '.$asset_id.
"\n");
409 function findAsset($root_asset_id, $asset_type_code, Array $search)
414 $search_type_attribute = isset($search[
'attribute']);
418 if ($search_type_attribute) {
419 $field_name = $search[
'attribute'][
'field'];
420 $field_value = $search[
'attribute'][
'value'];
422 $field_name = $search[
'metadata'][
'field'];
423 $field_value = $search[
'metadata'][
'value'];
429 $sql =
'SELECT t.treeid FROM sq_ast_lnk_tree t, sq_ast_lnk l WHERE l.linkid = t.linkid AND l.minorid = :root_asset_id LIMIT 1';
435 }
catch (Exception $e) {
436 throw new Exception(
'Unable to search for an existing '.$asset_type_code.
' asset: '.$e->getMessage());
439 if ($tree_id ==
'')
return Array();
442 $attribute_sql_from =
'sq_ast_attr r, sq_ast_attr_val v ';
445 $metadata_sql_from =
'sq_ast_mdata_val m ';
447 $sql =
'SELECT a.assetid, a.name '.
448 'FROM sq_ast a, sq_ast_lnk l, sq_ast_lnk_tree t, '.(($search_type_attribute) ? $attribute_sql_from : $metadata_sql_from).
449 'WHERE t.treeid LIKE :tree_id '.
450 'AND l.linkid = t.linkid AND a.assetid = l.minorid ';
452 if (!empty($asset_type_code)) {
453 $sql .=
'AND a.type_code = :type_code ';
456 if ($search_type_attribute) {
457 $sql .=
' AND v.assetid = a.assetid AND r.name = :field_name AND v.attrid = r.attrid AND v.custom_val = :field_val';
459 $sql .=
' AND m.assetid = a.assetid AND m.fieldid = :field_name AND m.value = :field_val';
467 if (!empty($asset_type_code)) {
471 }
catch (Exception $e) {
472 throw new Exception(
'Unable to search for an existing '.$asset_type_code.
' asset: '.$e->getMessage());
475 return $matching_assets;
489 function createLink(
Asset &$parent_asset,
Asset &$child_asset)
493 'asset' => &$parent_asset,
496 'sort_order' => NULL,
497 'is_dependant' => FALSE,
498 'is_exclusive' => FALSE,
501 $link_id = $child_asset->
create($link);
521 function createAsset(Array $asset_spec, $asset_type_code,
Asset &$parent_asset, $schema_id, Array $metadata_mapping, Array $attribute_mapping)
525 printStdErr(
'- Creating asset');
527 $asset =
new $asset_type_code();
531 editAttributes($asset, $asset_spec, $attribute_mapping);
535 $link_id = createLink($parent_asset, $asset);
539 editMetadata($asset, $asset_spec, $metadata_mapping, $schema_id);
543 $GLOBALS[
'SQ_SYSTEM']->am->forgetAsset($asset);
545 printStdErr(
' => asset ID '.$asset->id.
"\n");
547 return Array(reset($asset_spec) => $asset->id);
556 function editAttributes(
Asset &$asset, Array $asset_spec, Array $attribute_mapping)
558 $first_attr_name =
'';
559 $attrs_modified = FALSE;
561 foreach ($attribute_mapping as $supplied_name => $attribute_name) {
562 if ($first_attr_name ==
'') {
563 $first_attr_name = $supplied_name;
564 printStdErr(
' '.$asset_spec[$first_attr_name]);
568 if (isset($asset_spec[$supplied_name]) && ($asset->
attr($attribute_name) != $asset_spec[$supplied_name])) {
569 $asset->
setAttrValue($attribute_name, $asset_spec[$supplied_name]);
570 $attrs_modified = TRUE;
576 if ($attrs_modified) {
587 function editMetadata(
Asset &$asset, Array $asset_spec, Array $metadata_mapping, $schema_id)
589 $mm = $GLOBALS[
'SQ_SYSTEM']->getMetadataManager();
590 $mm->setSchema($asset->id, $schema_id, TRUE);
592 foreach ($metadata_mapping as $supplied_field_name => $metadata_field_id) {
593 if (isset($asset_spec[$supplied_field_name])) {
594 $metadata = Array($metadata_field_id => Array (
596 'value' => $asset_spec[$supplied_field_name],
597 'name' => $supplied_field_name,
602 $mm->setMetadata($asset->id, $metadata);
607 $mm->regenerateMetadata($asset->id);
614 if (ini_get(
'memory_limit') !=
'-1') ini_set(
'memory_limit',
'-1');
616 if ((php_sapi_name() !=
'cli')) {
617 trigger_error(
"You can only run this script from the command line\n", E_USER_ERROR);
621 $argv = $_SERVER[
'argv'];
622 $GLOBALS[
'SYSTEM_ROOT'] = (isset($argv[1])) ? $argv[1] :
'';
623 if (empty($GLOBALS[
'SYSTEM_ROOT'])) {
625 printStdErr(
"* The Matrix system root directory must be specified as the first argument\n\n");
629 require_once $GLOBALS[
'SYSTEM_ROOT'].
'/core/include/init.inc';
632 $asset_type_code = $argv[2];
633 if (empty($asset_type_code)) {
635 printStdErr(
"* A Matrix Type Code must be specified as the second argument\n\n");
639 $GLOBALS[
'SQ_SYSTEM']->am->includeAsset($asset_type_code);
643 $source_csv_filename = $argv[3];
644 if (empty($source_csv_filename)) {
646 printStdErr(
"* A source CSV filename must be specified as the third argument\n\n");
651 $parent_id = (int)$argv[4];
652 if ($parent_id == 0) {
654 printStdErr(
"* A Parent asset ID must be specified as the fourth argument\n\n");
659 $schema_id = (int)$argv[5];
660 if ($schema_id == 0) {
662 printStdErr(
"* A Metadata Schema asset ID must be specified as the fifth argument\n\n");
667 $mapping_filename = $argv[6];
668 if (empty($mapping_filename)) {
670 printStdErr(
"* A Metadata Field CSV mapping file must be specified as the sixth argument\n\n");
675 $attribute_mapping_filename = $argv[7];
676 if (empty($mapping_filename)) {
678 printStdErr(
"* An attribute CSV mapping file must be specified as the seventh argument\n\n");
683 $new_assets_live = (isset($argv[8]) && ($argv[8] == 1));
686 $unique_record_field = (isset($argv[9])) ? $argv[9] :
'';
689 $record_modification_field = (isset($argv[10])) ? $argv[10] :
'';
692 $ignore_csv_filename = (isset($argv[11])) ? $argv[11] :
'';
695 $csv_fd = fopen($mapping_filename,
'r');
698 printStdErr(
"* The supplied metadata mapping file was not found\n\n");
703 $metadata_mapping = Array();
705 while (($data = fgetcsv($csv_fd, 0,
',')) !== FALSE) {
706 $num_fields = count($data);
708 if ($num_fields == 2) {
709 $metadata_mapping[trim($data[1])] = (int)$data[0];
714 $csv_fd = fopen($attribute_mapping_filename,
'r');
717 printStdErr(
"* The supplied attribute mapping file was not found\n\n");
722 $attribute_mapping = Array();
724 while (($data = fgetcsv($csv_fd, 0,
',')) !== FALSE) {
725 $num_fields = count($data);
727 if ($num_fields == 2) {
728 $attribute_mapping[trim($data[0])] = trim($data[1]);
733 $ignore_fields = Array();
735 if ($ignore_csv_filename !=
'') {
736 $csv_fd = fopen($ignore_csv_filename,
'r');
739 printStdErr(
"* The supplied ignore fields file was not found\n\n");
744 while (($data = fgetcsv($csv_fd, 0,
',')) !== FALSE) {
745 $num_fields = count($data);
747 if ($num_fields == 1) {
748 $ignore_fields[trim($data[0])] = 1;
754 $root_user = $GLOBALS[
'SQ_SYSTEM']->am->getSystemAsset(
'root_user');
755 $GLOBALS[
'SQ_SYSTEM']->setCurrentUser($root_user);
757 $status_report = importAssets($source_csv_filename, $asset_type_code, $parent_id, $schema_id, $metadata_mapping, $attribute_mapping, $new_assets_live, $unique_record_field, $record_modification_field, $ignore_fields);
759 $GLOBALS[
'SQ_SYSTEM']->restoreCurrentUser();
761 printStdErr(
"\n- All done\n");
762 printStdErr(
"\tAssets added : ".$status_report[
'num_added'].
"\n");
763 printStdErr(
"\tAssets modified : ".$status_report[
'num_modified'].
"\n");
764 printStdErr(
"\tAssets deleted : ".$status_report[
'num_deleted'].
"\n");