Squiz Matrix  4.12.2
 All Data Structures Namespaces Functions Variables Pages
metadata_manager.inc
1 <?php
17 require_once SQ_FUDGE_PATH.'/general/text.inc';
18 
30 {
31 
32 
37  function Metadata_Manager()
38  {
39  $this->MySource_Object();
40 
41  }//end constructor
42 
43 
54  function requiredFieldsComplete($assetid)
55  {
56  $asset = $GLOBALS['SQ_SYSTEM']->am->getAsset($assetid);
57  if (is_null($asset)) return TRUE;
58 
59  // if this asset does not allow the user to set metadata values then
60  // its okay to assume that we dont need check if schema is complete
61  if (!$this->allowsMetadata($assetid)) return TRUE;
62 
63  $schemas = $this->getSchemas($asset->id, TRUE);
64  if (empty($schemas)) return TRUE;
65 
66  $values = $this->getMetadata($asset->id);
67 
68  foreach ($schemas as $schemaid) {
69  $schema = $GLOBALS['SQ_SYSTEM']->am->getAsset($schemaid);
70  if (is_null($schema)) continue;
71  if (!($schema instanceof Metadata_Schema)) continue;
72  $edit_fns = $schema->getEditFns();
73  if (!$edit_fns->requiredFieldsComplete($schema, $values, $asset->type())) {
74  return FALSE;
75  }
76  }
77 
78  return TRUE;
79 
80  }//end requiredFieldsComplete()
81 
82 
91  function allowsMetadata($assetid)
92  {
93  $asset = $GLOBALS['SQ_SYSTEM']->am->getAsset($assetid);
94  if (is_null($asset)) return FALSE;
95  $edit_fns = $asset->getEditFns();
96  return isset($edit_fns->static_screens['metadata']);
97 
98  }//end allowsMetadata()
99 
100 
101 //-- SCHEMAS --//
102 
103 
116  function getSchemas($assetid, $granted=NULL, $cascades=NULL)
117  {
118  $sql = ' SELECT DISTINCT schemaid, granted, cascades
119  FROM '.SQ_TABLE_RUNNING_PREFIX.'ast_mdata ';
120  $where = 'assetid = :assetid';
121  if (!is_null($granted)) {
122  $where .= ' AND granted = :granted';
123  }
124  if (!is_null($cascades)) {
125  $where .= ' AND cascades = :cascades';
126  }
127  $where = $GLOBALS['SQ_SYSTEM']->constructRollbackWhereClause($where);
128 
129  try {
130  $query = MatrixDAL::preparePdoQuery($sql.$where);
131  MatrixDAL::bindValueToPdo($query, 'assetid', $assetid);
132  if (!is_null($granted)) {
133  MatrixDAL::bindValueToPdo($query, 'granted', $granted ? '1' : '0', PDO::PARAM_STR);
134  }
135  if (!is_null($cascades)) {
136  MatrixDAL::bindValueToPdo($query, 'cascades', $cascades ? '1' : '0', PDO::PARAM_STR);
137  }
138  $result = DAL::executePdoAll($query);
139  } catch (Exception $e) {
140  throw new Exception('Unable to get applied schemas for asset ID #'.$assetid.' due to database error: '.$e->getMessage());
141  }
142 
143  $schemas = Array();
144  foreach ($result as $data) {
145  if (is_null($granted)) {
146  $schemas[$data['schemaid']] = $data['granted'];
147  } else {
148  $schemas[] = $data['schemaid'];
149  }
150  }
151 
152  return $schemas;
153 
154  }//end getSchemas()
155 
156 
163  function getAssetSchemaInfo($assetid, $schemaid=NULL, $cascades=NULL, $include_cascades=TRUE)
164  {
165  $sql = ' SELECT DISTINCT schemaid, granted, cascades
166  FROM '.SQ_TABLE_RUNNING_PREFIX.'ast_mdata ';
167  $where = 'assetid = :assetid';
168  if (!is_null($schemaid)) {
169  $where .= ' AND schemaid = :schemaid';
170  }
171  if (!is_null($cascades)) {
172  $where .= ' AND cascades = :cascades';
173  }
174  $where = $GLOBALS['SQ_SYSTEM']->constructRollbackWhereClause($where);
175 
176  try {
177  $query = MatrixDAL::preparePdoQuery($sql.$where);
178  MatrixDAL::bindValueToPdo($query, 'assetid', $assetid, PDO::PARAM_STR);
179  if (!is_null($schemaid)) {
180  MatrixDAL::bindValueToPdo($query, 'schemaid', $schemaid, PDO::PARAM_STR);
181  }
182  if (!is_null($cascades)) {
183  MatrixDAL::bindValueToPdo($query, 'cascades', $cascades ? '1' : '0', PDO::PARAM_STR);
184  }
185  $result = MatrixDAL::executePdoAssoc($query);
186  } catch (Exception $e) {
187  throw new Exception('Unable to get asset metadata schemas of asset ID #'.$assetid.' due to database error: '.$e->getMessage());
188  }
189 
190  $schemas = Array();
191  foreach ($result as $data) {
192  if ($include_cascades) {
193  $schemas[$data['schemaid']] = Array(
194  'granted' => $data['granted'],
195  'cascades' => $data['cascades'],
196  );
197  } else {
198  $schemas[$data['schemaid']] = $data['granted'];
199  }
200  }
201 
202  // If a schemaid is specified, flatten out array
203  if (!is_null($schemaid)) {
204  if (array_key_exists($schemaid, $schemas)) {
205  $schemas = $schemas[$schemaid];
206  } else {
207  $schemas = Array();
208  }
209  }
210 
211  return $schemas;
212 
213  }//end getAssetSchemaInfo()
214 
215 
228  function setSchema($assetid, $schemaid, $granted, $cascades=TRUE, $force_set=FALSE)
229  {
230  $db_action = 'insert';
231  $schema = $GLOBALS['SQ_SYSTEM']->am->getAsset($schemaid);
232  if (is_null($schema)) {
233  trigger_localised_error('SYS0047', E_USER_WARNING, $schemaid);
234  return FALSE;
235  }
236 
237  if (!($schema instanceof Metadata_Schema)) {
238  trigger_localised_error('SYS0045', E_USER_WARNING, $schema->name, $schemaid);
239  return FALSE;
240  }
241 
242  $asset = $GLOBALS['SQ_SYSTEM']->am->getAsset($assetid);
243  if (is_null($asset)) {
244  trigger_localised_error('SYS0046', E_USER_WARNING, $assetid);
245  return FALSE;
246  }
247 
248  if (!$asset->adminAccess('metadata')) {
249  trigger_localised_error('SYS0031', E_USER_WARNING, $asset->name);
250  return FALSE;
251  }
252 
253  // open a queue for all messages we are going to be logging
254  $ms = $GLOBALS['SQ_SYSTEM']->getMessagingService();
255  $ms->openLog();
256 
257  // get the current schemas that are set
258  $schema_info = $this->getAssetSchemaInfo($assetid, $schemaid);
259 
260  // check if this schema is already set
261  if (!empty($schema_info)) {
262 
263  if ((bool)$schema_info['granted'] == $granted) {
264  // schema is set with same access level
265  if ((bool)$schema_info['cascades'] == $cascades) {
266  // same cascade level too, so no update needed
267  return TRUE;
268  } else {
269  // same access level, but different cascade, so update it
270  $db_action = 'update';
271  }
272  } else {
273  if ($force_set) {
274  $db_action = 'update';
275  } else {
276  // schema is set but with the opposite access level
277  $new_access = ($granted) ? 'apply' : 'deny';
278  $current_access = ($granted) ? 'denied' : 'applied';
279 
280  trigger_localised_error('SYS0032', E_USER_WARNING, $new_access, $schema->name, $asset->name, $current_access);
281  return FALSE;
282  }
283  }
284  }
285 
286  $GLOBALS['SQ_SYSTEM']->changeDatabaseConnection('db2');
287  $GLOBALS['SQ_SYSTEM']->doTransaction('BEGIN');
288 
289  // log a message for the asset - this wont get logged until we close the queue
290  $msg_reps = Array(
291  'asset_name' => $asset->name,
292  'metadata_schema' => $schema->name,
293  );
294  $msg_type = 'asset.metadata.schema.set.fulllog';
295  $message = $ms->newMessage(Array(), $msg_type, $msg_reps);
296  $message->parameters['assetid'] = $asset->id;
297  $ms->logMessage($message);
298 
299  try {
300  switch ($db_action) {
301  case 'insert':
302  $message = 'set';
303  $bind_vars = Array (
304  'assetid' => $asset->id,
305  'schemaid' => (string) $schemaid,
306  'granted' => (string) ($granted ? '1' : '0'),
307  'cascades' => (string) ($cascades ? '1' : '0'),
308  );
309  $result = MatrixDAL::executeQuery('core', 'setMetadataSchemaOnAsset', $bind_vars);
310  break;
311  case 'update':
312  $message = 'update';
313  $bind_vars = Array (
314  'assetid' => $asset->id,
315  'schemaid' => (string) $schemaid,
316  'granted' => (string) ($granted ? '1' : '0'),
317  'cascades' => (string) ($cascades ? '1' : '0'),
318  );
319  $result = MatrixDAL::executeQuery('core', 'updateMetadataSchemaOnAsset', $bind_vars);
320  break;
321  }//end switch
322 
323  } catch (Exception $e) {
324  throw new Exception('Unable to '.$message.' metadata schema id #'.$schemaid.' on assetid #'.$asset->id.' due to the following database error:'.$e->getMessage());
325  }//end try catch
326 
327  if ($granted) {
328  //TODO:
329  if (!$asset->shouldFastTrack('metadata_manager_generate_content_file', $schemaid)) {
330  $all_contexts = $GLOBALS['SQ_SYSTEM']->getAllContexts();
331  foreach ($all_contexts as $all_contextid => $context_data) {
332  $this->generateContentFile($assetid, FALSE, $all_contextid);
333  }
334 
335  $em = $GLOBALS['SQ_SYSTEM']->getEventManager();
336 
337  // Needs broadcast this event for all the "FastTracked" schemas
338  $fast_tracked_schemas = $asset->getFaskTrackedTaskAssetids('metadata_manager_generate_content_file');
339  if (!empty($fast_tracked_schemas)) {
340  foreach($fast_tracked_schemas as $ft_schemaid) {
341  $em->broadcastEvent($asset, 'MetadataUpdate', Array('schemaid' => $ft_schemaid));
342  }
343  }
344  $em->broadcastEvent($asset, 'MetadataUpdate', Array('schemaid' => $schemaid));
345  $GLOBALS['SQ_SYSTEM']->broadcastTriggerEvent('trigger_event_metadata_updated', $asset);
346  }
347  }
348 
349  $GLOBALS['SQ_SYSTEM']->doTransaction('COMMIT');
350  $GLOBALS['SQ_SYSTEM']->restoreDatabaseConnection();
351  $ms->closeLog();
352 
353  return TRUE;
354 
355  }//end setSchema()
356 
357 
367  function deleteSchema($assetid, $schemaid)
368  {
369  $asset = $GLOBALS['SQ_SYSTEM']->am->getAsset($assetid);
370  if (is_null($asset)) {
371  trigger_localised_error('SYS0036', E_USER_WARNING, $assetid);
372  return FALSE;
373  }
374 
375  if (!$asset->adminAccess('metadata')) {
376  trigger_localised_error('SYS0029', E_USER_WARNING, $asset->name);
377  return FALSE;
378  }
379 
380  // open a queue for all messages we are going to be logging
381  $ms = $GLOBALS['SQ_SYSTEM']->getMessagingService();
382  $ms->openLog();
383 
384  $GLOBALS['SQ_SYSTEM']->changeDatabaseConnection('db2');
385  $GLOBALS['SQ_SYSTEM']->doTransaction('BEGIN');
386 
387  // log a message for the asset - this wont get logged until we close the queue
388  $schema = $GLOBALS['SQ_SYSTEM']->am->getAsset($schemaid);
389  $msg_reps = Array(
390  'asset_name' => $asset->name,
391  'metadata_schema' => $schema->name,
392  );
393  $msg_type = 'asset.metadata.schema.delete.fulllog';
394  $message = $ms->newMessage(Array(), $msg_type, $msg_reps);
395  $message->parameters['assetid'] = $asset->id;
396  $ms->logMessage($message);
397 
398  try {
399  $bind_vars = Array (
400  'schemaid' => $schemaid,
401  'assetid' => $asset->id,
402  );
403  $result = MatrixDAL::executeQuery('core', 'deleteSchemaOnAsset', $bind_vars);
404 
405  } catch (Exception $e) {
406  throw new Exception('Unable to delete schemaid #'.$schemaid.' on assetid #'.$asset->id.' due to the following database error:'.$e->getMessage());
407  }//end try catch
408 
409  $this->_cleanupMetadataValues($assetid);
410  //TODO:
411  $all_contexts = $GLOBALS['SQ_SYSTEM']->getAllContexts();
412  foreach ($all_contexts as $all_contextid => $context_data) {
413  if ($all_contextid === 0) {
414  // always generate a plain metadata.php
415  $this->generateContentFile($assetid, FALSE, $all_contextid);
416  } else {
417  $context_metadata = $this->getMetadata($assetid, 0, $all_contextid);
418  if (empty($context_metadata) === FALSE) {
419  $this->generateContentFile($assetid, FALSE, $all_contextid);
420  }
421  }
422  }
423 
424  $em = $GLOBALS['SQ_SYSTEM']->getEventManager();
425  $em->broadcastEvent($asset, 'MetadataDeleted', Array('schemaid' => $schemaid));
426  $GLOBALS['SQ_SYSTEM']->broadcastTriggerEvent('trigger_event_metadata_updated', $asset);
427 
428  $GLOBALS['SQ_SYSTEM']->doTransaction('COMMIT');
429  $GLOBALS['SQ_SYSTEM']->restoreDatabaseConnection();
430  $ms->closeLog();
431  return TRUE;
432 
433  }//end deleteSchema()
434 
435 
445  function getSchemaAssets($schemaid, $granted=NULL)
446  {
447  $sql = 'SELECT DISTINCT
448  assetid, granted
449  FROM
450  '.SQ_TABLE_RUNNING_PREFIX.'ast_mdata ';
451 
452  $where = 'schemaid = :schemaid';
453  if (!is_null($granted)) {
454  $where .= ' AND granted = :granted';
455  }
456  $where = $GLOBALS['SQ_SYSTEM']->constructRollbackWhereClause($where);
457 
458  try {
459  $query = MatrixDAL::preparePdoQuery($sql.$where);
460  MatrixDAL::bindValueToPdo($query, 'schemaid', $schemaid);
461  if (!is_null($granted)) {
462  MatrixDAL::bindValueToPdo($query, 'granted', $granted ? '1' : '0', PDO::PARAM_STR);
463  }
464  $result = MatrixDAL::executePdoAll($query);
465  } catch (Exception $e) {
466  throw new Exception('Unable to get assetid with schemaid #'.$schemaid.' applied due to the following database error:'.$e->getMessage());
467  }//end try catch
468 
469  $assets = Array();
470  foreach ($result as $data) {
471  if (is_null($granted)) {
472  $assets[$data['assetid']] = $data['granted'];
473  } else {
474  $assets[] = $data['assetid'];
475  }
476  }
477 
478  return $assets;
479 
480  }//end getSchemaAssets()
481 
482 
492  function getMetadataFields($schemaids)
493  {
494  if (!is_array($schemaids)) {
495  return $GLOBALS['SQ_SYSTEM']->am->getChildren($schemaids, 'metadata_field', FALSE);
496  } else {
497  $fieldids = Array();
498  foreach ($schemaids as $schemaid) {
499  $field_children = $GLOBALS['SQ_SYSTEM']->am->getChildren($schemaid, 'metadata_field', FALSE);
500  foreach ($field_children as $fieldid => $field_type) {
501  $fieldids[$fieldid] = $field_type;
502  }
503  }
504  return $fieldids;
505  }
506 
507  }//end getMetadataFields()
508 
509 
510 //-- METADATA VALUES --//
511 
512 
528  function getMetadata($assetid, $schemaid=0, $contextid=NULL)
529  {
530  if ($contextid === NULL) {
531  $contextid = $GLOBALS['SQ_SYSTEM']->getContextId();
532  }
533 
534  $asset = $GLOBALS['SQ_SYSTEM']->am->getAsset($assetid);
535  if (is_null($asset)) {
536  trigger_localised_error('SYS0043', E_USER_WARNING, $assetid);
537  return FALSE;
538  }
539 
540  // check that the schema we are getting metadata for is actually set
541  $schemas = $this->getSchemas($assetid, TRUE);
542  if ($schemaid) {
543  if (!in_array($schemaid, $schemas)) return Array();
544  // restrict to just the one schema
545  $schemas = Array($schemaid);
546  }
547 
548  if (empty($schemas)) return Array();
549 
550  // And to think I didn't like it when this generating query got pulled out of the Asset_Manager::getChildren() :)
551  // Instead of doing any thinking...let them do it all for us and use it in our query
552  $sql = 'SELECT
553  mv.fieldid, a.name, mv.value
554  FROM
555  '.SQ_TABLE_RUNNING_PREFIX.'ast_mdata_val mv
556  INNER JOIN
557  '.SQ_TABLE_RUNNING_PREFIX.'ast a ON mv.fieldid = a.assetid';
558 
559  $where = ' mv.assetid = :assetid
560  AND mv.contextid = :contextid
561  AND (';
562 
563  $bind_vars = Array();
564  foreach ($schemas as $schemaid) {
565  $schema = $GLOBALS['SQ_SYSTEM']->am->getAsset($schemaid);
566  if (is_null($schema)) {
567  trigger_localised_error('SYS0044', E_USER_WARNING, $schemaid);
568  return FALSE;
569  }
570 
571  $bind_prefix = 'gc_'.$schemaid.'_';
572  $ret_val = $GLOBALS['SQ_SYSTEM']->am->generateGetChildrenQuery($schema, 'metadata_field', FALSE, NULL, NULL, NULL, TRUE, FALSE, NULL, NULL, TRUE, NULL, $bind_prefix);
573  $sql_array = $ret_val['sql_array'];
574  $bind_vars = array_merge($bind_vars, $ret_val['bind_vars']);
575  $where .= '
576  mv.fieldid IN ('.implode(' ', $sql_array).') OR ';
577 
578  }// end foreach
579 
580  $where = trim($where, ' OR ').'
581  )';
582 
583  $where = $GLOBALS['SQ_SYSTEM']->constructRollbackWhereClause($where, 'mv');
584  $where = $GLOBALS['SQ_SYSTEM']->constructRollbackWhereClause($where, 'a');
585 
586  try {
587  $query = MatrixDAL::preparePdoQuery($sql.$where);
588  MatrixDAL::bindValueToPdo($query, 'assetid', $asset->id);
589  MatrixDAL::bindValueToPdo($query, 'contextid', $contextid);
590  foreach ($bind_vars as $bind_var => $bind_value) {
591  MatrixDAL::bindValueToPdo($query, $bind_var, $bind_value);
592  }
593  $metadata = MatrixDAL::executePdoGroupedAssoc($query);
594  } catch (Exception $e) {
595  // SYS0338 = Unable to get current metadata values due to DB error
596  throw new Exception(translate_error('SYS0338', $asset->id, $contextid, $e->getMessage()));
597  }//end try catch
598 
599  return $metadata;
600 
601  }//end getMetadata()
602 
603 
613  function _cleanupMetadataValues($assetid)
614  {
615  $contextids = $GLOBALS['SQ_SYSTEM']->getAllContexts();
616  $assetid_cond = 'assetid = '.MatrixDAL::quote((string)$assetid);
617  $fieldid_conds = Array();
618  $bind_vars = Array();
619 
620  foreach ($this->getSchemas($assetid, TRUE) as $schemaid) {
621  $schema = $GLOBALS['SQ_SYSTEM']->am->getAsset($schemaid, 'metadata_schema');
622 
623  $bind_prefix = 'gc_'.$schemaid.'_';
624  $ret_val = $GLOBALS['SQ_SYSTEM']->am->generateGetChildrenQuery($schema, 'metadata_field', FALSE, NULL, NULL, NULL, TRUE, FALSE, NULL, NULL, TRUE, NULL, $bind_prefix);
625  $sql_array = $ret_val['sql_array'];
626  $bind_vars = array_merge($bind_vars, $ret_val['bind_vars']);
627 
628  $fieldid_conds[] = '(fieldid NOT IN ('.implode(' ', $sql_array).'))';
629  }
630 
631  $sql = 'DELETE FROM sq_ast_mdata_val
632  ';
633  $where = 'WHERE '.$assetid_cond;
634 
635  if (!empty($fieldid_conds)) {
636  $where .= ' AND (('.implode("\n\tAND ", $fieldid_conds).') OR (contextid NOT IN ('.implode(', ', array_keys($contextids)).')))';
637  }
638 
639  $sql .= $where;
640 
641  try {
642  $query = MatrixDAL::preparePdoQuery($sql);
643  foreach ($bind_vars as $bind_var => $bind_value) {
644  MatrixDAL::bindValueToPdo($query, $bind_var, $bind_value);
645  }
646  MatrixDAL::execPdoQuery($query);
647  } catch (Exception $e) {
648  throw new Exception(translate_error('SYS0342', $assetid, $e->getMessage()));
649  }
650 
651 
652  }//end _cleanupMetadataValues()
653 
654 
664  function getSchemaDefaultValues($schemaid, $contextid=NULL)
665  {
666  if ($contextid === NULL) {
667  $contextid = $GLOBALS['SQ_SYSTEM']->getContextId();
668  }
669 
670  // Cache the field names here. We don't need to cache the value so much
671  // because getMetadataFieldDefaultValue() does that for us
672  static $cached_field_names = Array();
673 
674  $am =& $GLOBALS['SQ_SYSTEM']->am;
675 
676  $schema = $am->getAsset($schemaid);
677  if (is_null($schema)) {
678  trigger_localised_error('SYS0040', E_USER_WARNING, $schemaid);
679  return Array();
680  }
681 
682  $fields = $this->getMetadataFields(Array($schemaid));
683 
684  $default_values = Array();
685  $field_names = Array();
686  $fields_to_check = Array();
687 
688  foreach ($fields as $fieldid => $type_code) {
689  if (isset($cached_field_names[$fieldid])) {
690  $field_names[$fieldid] = $cached_field_names[$fieldid];
691  } else {
692  $fields_to_check[] = $fieldid;
693  }
694  }
695  $new_field_names = $GLOBALS['SQ_SYSTEM']->am->getAssetInfo($fields_to_check, 'metadata_field', FALSE, 'name');
696  $field_names += $new_field_names;
697 
698  foreach ($fields as $fieldid => $type_code) {
699  if (!isset($cached_field_names[$fieldid])) {
700  $cached_field_names[$fieldid] = $field_names[$fieldid];
701  }
702 
703  $default_values[$fieldid] = Array(
704  'name' => $field_names[$fieldid],
705  'value' => $this->getMetadataFieldDefaultValue($fieldid, $contextid),
706  );
707  }
708 
709  return $default_values;
710 
711  }//end getSchemaDefaultValues()
712 
713 
723  function loadMetadataFile($assetid, $metadata_filename)
724  {
725  $metadata = Array();
726  $asset = $GLOBALS['SQ_SYSTEM']->am->getAsset($assetid);
727  $contextid = $GLOBALS['SQ_SYSTEM']->getContextId();
728 
729  // include the file but must not display anything
730  ob_start();
731  include $metadata_filename;
732  ob_end_clean();
733 
734  $metadata['values'] = $metadata_values;
735  $metadata['value_components'] = $metadata_value_components;
736  $metadata['warnings'] = $metadata_warnings;
737 
738  return $metadata;
739 
740  }//end loadMetadata
741 
742 
755  function getMetadataFieldValues($assetid, $field_names=Array(), $contextid=NULL)
756  {
757  if ($contextid === NULL) {
758  $contextid = $GLOBALS['SQ_SYSTEM']->getContextId();
759  }
760 
761  if ($contextid === 0) {
762  $metadata_basename = 'metadata.php';
763  } else {
764  $metadata_basename = 'metadata.'.$contextid.'.php';
765  }
766 
767  // Change the context here so the asset is retrieved in the right context
768  // (particularly if a custom context is requested)
769  $GLOBALS['SQ_SYSTEM']->changeContext($contextid);
770 
771  $am =& $GLOBALS['SQ_SYSTEM']->am;
772  $asset = $am->getAsset($assetid);
773  $field_values = Array();
774 
775  if (is_null($asset)) {
776  trigger_localised_error('SYS0038', E_USER_WARNING, $assetid);
777  $GLOBALS['SQ_SYSTEM']->restoreContext();
778  return $field_values;
779  }
780 
781  $schemas = $this->getSchemas($asset->id, TRUE);
782  if (empty($schemas)) {
783  $GLOBALS['SQ_SYSTEM']->restoreContext();
784  return $field_values;
785  }
786 
787  // we suppose that the metadata values are stored in the file called metadata.php
788  // if the file does not exists it means that not metadata was generated because
789  // no metatadata schema was applied to the asset
790  // this will enhance the speed of this function and will replace any keyword
791  $_metadata_filename = $asset->data_path.'/'.$metadata_basename;
792 
793  if (!is_file($_metadata_filename)) {
794  $GLOBALS['SQ_SYSTEM']->restoreContext();
795  return $field_values;
796  }
797 
798  $metadata = $this->loadMetadataFile($assetid, $_metadata_filename);
799 
800  if (isset($metadata['values'])) {
801  $metadata_values = $metadata['values'];
802 
803  // if the field_names is not empty return the value asked
804  // else return all the values
805  if (!empty($field_names)) {
806  foreach ($field_names as $key => $value) {
807  if (isset($metadata_values[$value])) {
808  $field_values[$value] = $metadata_values[$value];
809  } else if (isset($metadata_values[str_replace('_', ' ', $value)])) {
810  $field_values[$value] = $metadata_values[str_replace('_', ' ',$value)];
811  } else {
812  $field_values[$value] = '';
813  }
814  }
815  } else {
816  $field_values = $metadata_values;
817  }
818  }
819 
820  $am->forgetAsset($asset);
821  unset($asset);
822 
823  $GLOBALS['SQ_SYSTEM']->restoreContext();
824 
825  return $field_values;
826 
827  }//end getMetadataFieldValues()
828 
829 
842  function setMetadata($assetid, $metadata, $contextid=NULL, $update_asset=TRUE, $broadcast_all_fields=FALSE, $ignore_editable=FALSE)
843  {
844  if ($contextid === NULL) {
845  $contextid = $GLOBALS['SQ_SYSTEM']->getContextId();
846  }
847 
848  $asset = $GLOBALS['SQ_SYSTEM']->am->getAsset($assetid);
849  if (is_null($asset)) {
850  trigger_localised_error('SYS0043', E_USER_WARNING, $assetid);
851  return FALSE;
852  }
853 
854  if (!$asset->writeAccess('metadata')) {
855  trigger_localised_error('SYS0030', E_USER_WARNING, $asset->name);
856  return FALSE;
857  }
858 
859  // open a queue for all messages we are going to be logging
860  $ms = $GLOBALS['SQ_SYSTEM']->getMessagingService();
861  $ms->openLog();
862 
863  $GLOBALS['SQ_SYSTEM']->changeDatabaseConnection('db2');
864  $GLOBALS['SQ_SYSTEM']->doTransaction('BEGIN');
865 
866  $contextable_fields = Array(
867  0 => Array(),
868  1 => Array(),
869  );
870 
871  // Make sure all the fields exist and are editable
872  foreach (array_keys($metadata) as $fieldid) {
873  $flag_match_found = FALSE;
874  $field = $GLOBALS['SQ_SYSTEM']->am->getAsset($fieldid);
875  if (is_null($field) || !($ignore_editable || $field->attr('editable'))) {
876  unset($metadata[$fieldid]);
877  continue;
878  } else {
879  // Check for metadata section restrictions
880  $current_links = $GLOBALS['SQ_SYSTEM']->am->getLinks($field->id, SQ_LINK_TYPE_2, 'metadata_section', FALSE, 'minor', NULL, TRUE);
881  foreach ($current_links as $link) {
882  $section = $GLOBALS['SQ_SYSTEM']->am->getAsset($link['majorid'], $link['major_type_code']);
883  if (is_null($section)) continue;
884  $restrictions = $section->attr('restrict');
885  if (!empty($restrictions)) {
886  foreach ($restrictions as $type_code_restricted => $inherit_it) {
887  if ($inherit_it && !$flag_match_found) {
888  $asset_type_with_parents = $GLOBALS['SQ_SYSTEM']->am->getAssetTypeInfo(Array($asset->id));
889  foreach($asset_type_with_parents[$asset->id] as $index => $asset_type) {
890  if (array_key_exists($asset_type[0], $restrictions) && !$flag_match_found) {
891  $flag_match_found = TRUE;
892  }
893  }
894  } else if (array_key_exists($asset->type(), $restrictions)){
895  $flag_match_found = TRUE;
896  }
897 
898  }
899  if (!$flag_match_found) {
900  unset($metadata[$fieldid]);
901  }
902  }
903  }//end foreach
904 
905  // If the field is still being tested, check whether it's
906  // contextable or not, so it's appropriately handled
907  if (array_key_exists($fieldid, $metadata)) {
908  // A field is non-contextatble if its attribute says so
909  // or it is a Metadata Select Field
910  $contextable_value = (!$field->attr('is_contextable') || ($field instanceof Metadata_Field_Select)) ? 0 : 1;
911  $contextable_fields[$contextable_value][] = (string)$fieldid;
912  }
913  continue;
914  }
915 
916  }//end foreach
917 
918  // log a message for the asset - this wont get logged until we close the queue
919  $metadata_updated = Array();
920  foreach ($metadata as $fieldid => $value) {
921  // Set default
922  $mdata_name = 'Unknown Metadata Field';
923 
924  // Go and get the field name
925  if ($fieldid > 0) {
926  $mdata_field = $GLOBALS['SQ_SYSTEM']->am->getAsset($fieldid);
927  $mdata_name = $mdata_field->name;
928  }
929 
930  // Get the old value
931  $mdata_values = $this->getMetadataFieldValues($asset->id);
932  $old_value = ''; // Default to nothing set
933  foreach ($mdata_values as $old_key => $old_val) {
934  if ($old_key == $mdata_name) {
935  $old_value = $old_val;
936  }
937  }
938 
939  // If the field is set to 'use default', it wouldn't be set to any value,
940  if (!isset($value[0]['value'])) {
941  $value[0]['value'] = $this->getMetadataFieldDefaultValue($fieldid, $contextid);
942  }
943 
944  // By pass if the new and old are the same (we don't need the message saying we made no changes!)
945  if (!($old_value == $value[0]['value'])) {
946  // This is for the trigger metadata updated
947  $metadata_updated[$fieldid] = $value;
948 
949  // Message replacements
950  $msg_reps = Array(
951  'asset_name' => $asset->name,
952  'metadata_field' => $mdata_name,
953  'metadata_old' => $old_value,
954  'metadata_new' => $value[0]['value'],
955  );
956  $msg_type = 'asset.metadata.set.fulllog';
957  $message = $ms->newMessage(Array(), $msg_type, $msg_reps);
958  $message->parameters['assetid'] = $asset->id;
959  $ms->logMessage($message);
960  }
961  }//end foreach
962 
963  // Delete from mdata_val table where necessary
964  $delete_fieldids = Array();
965  $remaining = Array();
966  foreach ($metadata as $fieldid => $details) {
967  if ($details[0]['value'] === NULL) {
968  // we want to revert this field to default, done by deleting it from the mdata_val table
969  $delete_fieldids[] = (string) $fieldid;
970  } else {
971  $remaining[] = $fieldid;
972  }
973  }
974 
975  // We want to remove all non-contextable fields and then insert them again instead of updating
976  // because we want to add new records for contexts that do not have metadata fields set yet
977  // e.g. set metadata the first time for default context and alternate contexts still use metadata default values
978  $delete_fieldids = array_merge($delete_fieldids, $contextable_fields[0]);
979  // Get unique field IDs because non-contextable fields can be set to default value ('Use default' option in Metadata screen)
980  $delete_fieldids = array_unique($delete_fieldids);
981 
982  if (!empty($delete_fieldids)) {
983  try {
984  // Find the contextable metadata fields in the lot - and delete
985  // only this context for them
986  if (count(array_intersect($delete_fieldids, $contextable_fields[1])) > 0) {
987  $bind_vars = Array (
988  'assetid' => $assetid,
989  'fieldid' => array_intersect($delete_fieldids, $contextable_fields[1]),
990  'contextid' => $contextid,
991  );
992  $result = MatrixDAL::executeQuery('core', 'deleteMetadataValueForAsset', $bind_vars);
993  }
994 
995  // Non-contextable metadata fields - delete the whole lot!aa
996  if (count(array_intersect($delete_fieldids, $contextable_fields[0])) > 0) {
997  $bind_vars = Array (
998  'assetid' => $assetid,
999  'fieldid' => array_intersect($delete_fieldids, $contextable_fields[0]),
1000  'contextid' => NULL,
1001  );
1002  $result = MatrixDAL::executeQuery('core', 'deleteMetadataValueForAsset', $bind_vars);
1003  }
1004  } catch (Exception $e) {
1005  // SYS0341 = Unable to revert fields to default due to DB error on delete
1006  throw new Exception(translate_error('SYS0341', implode(', ', $delete_fieldids), $asset->id, $contextid, $e->getMessage()));
1007  }//end try catch
1008  }
1009 
1010  if (!empty($remaining)) {
1011  // Find any fields that have existing entries...so we know what to update and what to insert
1012  $sql = 'SELECT
1013  fieldid
1014  FROM
1015  '.SQ_TABLE_RUNNING_PREFIX.'ast_mdata_val';
1016  $where = ' assetid = :assetid AND contextid = :contextid';
1017  $where = $GLOBALS['SQ_SYSTEM']->constructRollbackWhereClause($where);
1018 
1019  try {
1020  $query = MatrixDAL::preparePdoQuery($sql.$where);
1021  MatrixDAL::bindValueToPdo($query, 'assetid', $asset->id);
1022  MatrixDAL::bindValueToPdo($query, 'contextid', $contextid);
1023  $updates = MatrixDAL::executePdoAssoc($query, 0);
1024  } catch (Exception $e) {
1025  // SYS0338 = Unable to get current values due to DB error
1026  throw new Exception(translate_error('SYS0338', $asset->id, $contextid, $e->getMessage()));
1027  }
1028 
1029  // Insert or update the remaining metadata fields as required
1030  foreach ($remaining as $fieldid) {
1031  // If the field is not contextable, set the context ID to null,
1032  // so it will be copied to all applicable contexts.
1033  if (array_search($fieldid, $contextable_fields[0]) !== FALSE) {
1034  $do_contextid = NULL;
1035  } else {
1036  $do_contextid = $contextid;
1037  }
1038 
1039  $bind_vars = Array (
1040  'assetid' => $asset->id,
1041  'fieldid' => $fieldid,
1042  'value' => $metadata[$fieldid][0]['value'],
1043  'contextid' => $do_contextid,
1044  );
1045 
1046  if (!in_array($fieldid, $updates)) {
1047  // for non contextable field, delete all entries first to avoid duplicate insertion error
1048  if(!isset($do_contextid)){
1049  try {
1050  $result = MatrixDAL::executeQuery('core', 'deleteMetadataValueForAsset', $bind_vars);
1051  } catch (Exception $e) {
1052  throw new Exception(translate_error('SYS0339', $fieldid, $metadata[$fieldid][0]['value'], $asset->id, $contextid, $e->getMessage()));
1053  }
1054  }
1055  // insert values of contextable field in current context or insert values of non-contextable for all contexts
1056  try {
1057  $result = MatrixDAL::executeQuery('core', 'setMetadataValueForAsset', $bind_vars);
1058  } catch (Exception $e) {
1059  // SYS0339 = Cannot set new value of metadata due to DB error
1060  throw new Exception(translate_error('SYS0339', $fieldid, $metadata[$fieldid][0]['value'], $asset->id, $contextid, $e->getMessage()));
1061  }//end try catch
1062 
1063  // we are updating
1064  } else {
1065  try {
1066  $result = MatrixDAL::executeQuery('core', 'updateMetadataValueForAsset', $bind_vars);
1067  } catch (Exception $e) {
1068  // SYS0340 = Cannot update value of metadata due to DB error
1069  throw new Exception(translate_error('SYS0340', $fieldid, $metadata[$fieldid][0]['value'], $asset->id, $contextid, $e->getMessage()));
1070  }//end try catch
1071 
1072  }//end if
1073 
1074  }//end for
1075 
1076  }//end if
1077 
1078  $GLOBALS['SQ_SYSTEM']->doTransaction('COMMIT');
1079  $GLOBALS['SQ_SYSTEM']->restoreDatabaseConnection();
1080  $ms->closeLog();
1081 
1082  $asset = $GLOBALS['SQ_SYSTEM']->am->getAsset($assetid);
1083  if ($update_asset) $asset->_updated();
1084  $em = $GLOBALS['SQ_SYSTEM']->getEventManager();
1085  // broadcasted the assetids of the updated fields
1086  $updated_fields = Array('fieldids' => array_keys($metadata_updated));
1087  $em->broadcastEvent($asset, 'MetadataUpdate', $broadcast_all_fields ? Array('all') : Array('fieldids' => array_keys($metadata)));
1088  $GLOBALS['SQ_SYSTEM']->broadcastTriggerEvent('trigger_event_metadata_updated', $asset, $updated_fields);
1089 
1090  return TRUE;
1091 
1092 
1093  }//end setMetadata()
1094 
1095 
1096 //-- (RE)GENERATE METADATA --//
1097 
1098 
1113  function generateContentFile($assetid, $regenerate=FALSE, $contextid=NULL, $update_asset=TRUE)
1114  {
1115  if ($contextid === NULL) {
1116  $contextid = $GLOBALS['SQ_SYSTEM']->getContextId();
1117  }
1118 
1119  if ($contextid === 0) {
1120  $metadata_filename = 'metadata.php';
1121  } else {
1122  $metadata_filename = 'metadata.'.$contextid.'.php';
1123  }
1124 
1125  // Change to the context specified, before the asset is retrieved
1126  if ($contextid === 'default') {
1127  $regenerate = FALSE;
1128  $GLOBALS['SQ_SYSTEM']->changeContext(0);
1129  } else {
1130  $GLOBALS['SQ_SYSTEM']->changeContext($contextid);
1131  }
1132 
1133  $asset = $GLOBALS['SQ_SYSTEM']->am->getAsset($assetid);
1134  if (is_null($asset)) {
1135  trigger_localised_error('SYS0034', E_USER_WARNING, $assetid);
1136  $GLOBALS['SQ_SYSTEM']->restoreContext();
1137  return FALSE;
1138  }
1139 
1140  $schemas = $this->getSchemas($asset->id, TRUE);
1141  if (empty($schemas)) {
1142  $GLOBALS['SQ_SYSTEM']->restoreContext();
1143  return FALSE;
1144  }
1145 
1146  // an array of all metadata tag values
1147  $tag_values = Array();
1148 
1149  // an array of keyword replacements that we are going to have to write some PHP code to produce
1150  $keywords = Array();
1151 
1152  // get the values without any replacements or special processing
1153  // Also used if we are regenerating
1154  if ($contextid === 'default') {
1155  $metadata = Array();
1156  } else {
1157  $metadata = $this->getMetadata($asset->id);
1158  }
1159 
1160  ob_start();
1161  foreach ($schemas as $schemaid) {
1162  $schema = $GLOBALS['SQ_SYSTEM']->am->getAsset($schemaid);
1163  if (is_null($schema)) {
1164  trigger_localised_error('SYS0035', E_USER_WARNING, $schemaid);
1165  $GLOBALS['SQ_SYSTEM']->restoreContext();
1166  return FALSE;
1167  }
1168 
1169  if (!($schema instanceof Metadata_Schema)) {
1170  trigger_localised_error('SYS0033', E_USER_WARNING, $schema->name, $schemaid);
1171  $GLOBALS['SQ_SYSTEM']->restoreContext();
1172  return FALSE;
1173  }
1174 
1175  $edit_fns = $schema->getEditFns();
1176  $edit_fns->generateMetadata($schema, $metadata, $tag_values, $keywords, $asset->type());
1177 
1178  $GLOBALS['SQ_SYSTEM']->am->forgetAsset($schema);
1179  }
1180 
1181  $metadata_str = ob_get_contents();
1182  ob_end_clean();
1183 
1184  ob_start();
1185  echo '<'.'?php'."\n";
1186  if (!empty($keywords)) {
1187  require_once SQ_FUDGE_PATH.'/general/text.inc';
1188  echo '$am =& $GLOBALS[\'SQ_SYSTEM\']->am;'."\n";
1189  echo '$metadata_asset = $am->getAsset('.$asset->id.', \'\', TRUE);'."\n\n";
1190  echo '/* 1 */', "\n";
1191  echo '$metadata_replacements = Array();'."\n";
1192  foreach ($keywords as $keyword) {
1193  if (!preg_match('/^metadata_field_/', $keyword)) {
1194  echo '$metadata_replacements["'.addslashes($keyword).'"] = $metadata_asset->getKeywordReplacement("'.addslashes($keyword).'");'."\n";
1195  }
1196  }
1197  echo '/* 2 */', "\n";
1198  replace_keywords($tag_values, $replacements);
1199  echo '/* 3 */', "\n";
1200  echo "\n\n";
1201  }
1202 
1203 
1204  // the following handles the replacement of the %metadata_field_xxxxx% keywords by
1205  // looping over the copy of tag_values (field_list) - if the value doesn't have
1206  // any metadata_field keywords, shift it over to the "replaced" list
1207 
1208  // if the value does contain keywords, however, for each keyword check whether or not
1209  // replaced_list contains the desired field; do this until all possible keyword
1210  // replacements have been made (if everything is replaced, leaving no keywords, this
1211  // value will be picked up in the next pass and added to replaced_list)
1212 
1213  // if a pass is completed without any modifications to field_list or replaced_list being
1214  // made, we bail out and leave any circular references unreplaced
1215  $field_list = $tag_values;
1216  $replaced_list = Array();
1217 
1218  $field_replacements = Array();
1219 
1220  // keep looping until we run out of items to shift over to $replaced_list
1221  do {
1222  $fields_modified = FALSE;
1223  foreach ($field_list as $n => $v) {
1224 
1225  // get all the %metadata_field_xxxxx% keywords in $v
1226  $value_keywords = retrieve_keywords_replacements($v);
1227 
1228  // cull any keywords that aren't in the format %metadata_field_xxxxx%
1229  $metadata_keywords = Array();
1230  foreach ($value_keywords as $keyword) {
1231  if (preg_match('/^metadata_field_/', $keyword)) {
1232  $metadata_keywords[] = $keyword;
1233  }
1234  }
1235  $metadata_keywords = array_unique($metadata_keywords);
1236 
1237  // if no metadata_field, put it directly on the $replaced stack,
1238  if (empty($metadata_keywords)) {
1239  // muck around with the stack; don't touch the original $metadata_values
1240  $replaced_list[$n] = $v;
1241  $field_replacements['metadata_field_'.$n] = $v;
1242 
1243  unset($field_list[$n]);
1244 
1245  $fields_modified = TRUE;
1246 
1247  } else {
1248  // Apply keyword modifiers
1249  foreach($metadata_keywords as $full_keyword) {
1250  if (!isset($field_replacements[$full_keyword])) {
1251  $modifiers = NULL;
1252  $part_keyword = parse_keyword($full_keyword, $modifiers);
1253  if ($part_keyword != $full_keyword && isset($field_replacements[$part_keyword])) {
1254  $keyword_value = $field_replacements[$part_keyword];
1255  apply_keyword_modifiers($keyword_value, $modifiers, Array('assetid' => $assetid));
1256  $field_replacements[$full_keyword] = $keyword_value;
1257  }
1258  }
1259  }//end foreach
1260 
1261  // replace all the field references with their replaced_list counterparts
1262  // if everything is successfully replaced, leave until next time
1263  // to move to replaced_list
1264  $pre_replacement = $field_list[$n];
1265  replace_keywords($field_list[$n], $field_replacements);
1266 
1267  // if keywords were replaced...
1268  if ($pre_replacement != $field_list[$n]) {
1269  // mirror value changes back to the original
1270  // $metadata_values list, and the keyword replacement list
1271  $tag_values[$n] = $field_list[$n];
1272  $fields_modified = TRUE;
1273  }
1274  }//end else (empty($field_refs))
1275 
1276  }//end foreach ($metadata_values)
1277  } while ($fields_modified);
1278 
1279  // print the values, to be referenced by the meta tags later
1280  echo '$metadata_values = Array('."\n";
1281  foreach ($tag_values as $n => $v) {
1282  $n = addslashes($this->escapeMetadata($n, TRUE));
1283  Metadata_Field::decodeValueString($v, $v2, $vc);
1284  // escape single quotes and backslashes
1285  $v2 = str_replace("'", "\'", str_replace("\\", "\\\\", $v2));
1286 
1287  // unescape metadata_replacements
1288  // leave metadata_values for later - unescape them at runtime
1289  $v2 = preg_replace('/%([^%\' ]+)%/', '\'.(isset($metadata_replacements[\'\1\']) ? $metadata_replacements[\'\1\'] : \'%\1%\' ).\'', $v2);
1290  echo "'$n' => '$v2',\n";
1291  }
1292  echo ");\n\n";
1293 
1294  // print the value components, to be referenced by the meta tags later
1295  echo '$metadata_value_components = Array('."\n";
1296  foreach ($tag_values as $n => $v) {
1297  $vc = Array();
1298  $n = addslashes($this->escapeMetadata($n, TRUE));
1299  Metadata_Field::decodeValueString($v, $v2, $vc);
1300 
1301  echo "'$n' => Array(";
1302 
1303  // Value components
1304  if (!empty($vc)) {
1305  foreach ($vc as $vc_key => $vc_value) {
1306  $vc_key = addslashes($this->escapeMetadata($vc_key, TRUE));
1307  $vc_value = addslashes($this->escapeMetadata($vc_value, TRUE));
1308  echo "'$vc_key' => '".$vc_value."', ";
1309  }
1310  }
1311 
1312  // Close the array
1313  echo "),\n";
1314  }
1315  echo ");\n\n";
1316 
1317  // print the metadata manager reference for value encoding
1318  echo '$mm = $GLOBALS[\'SQ_SYSTEM\']->getMetadataManager();'."\n";
1319 
1320  // print the warnings
1321  echo '$metadata_warnings = Array();'."\n";
1322 
1323  // if the field_list is empty, it means we still have keywords left to replace
1324  if (!empty($field_list)) {
1325  echo '$metadata_warnings[\'keyword_circular_references\'] = Array('."\n";
1326  foreach ($field_list as $n => $v) {
1327  $n = $this->escapeMetadata($n, TRUE);
1328  echo "'$n',\n";
1329  }
1330  echo ");\n";
1331  }
1332 
1333  echo '?'.'>';
1334  $php_str = ob_get_contents();
1335  ob_end_clean();
1336 
1337 
1338  $metadata_str = $php_str."\n\n".$metadata_str;
1339 
1340  require_once SQ_FUDGE_PATH.'/general/file_system.inc';
1341  if (!create_directory($asset->data_path)) {
1342  $GLOBALS['SQ_SYSTEM']->restoreContext();
1343  return FALSE;
1344  }
1345 
1346  if (!string_to_file($metadata_str, $asset->data_path.'/'.$metadata_filename)) {
1347  $GLOBALS['SQ_SYSTEM']->restoreContext();
1348  return FALSE;
1349  }
1350 
1351  // Content regenerated, so clear the _tmp vars for metadata
1352  // Otherwise old values will stay in effect until the asset is reloaded
1353  if (isset($asset->_tmp['mm_replacements'])) {
1354  unset($asset->_tmp['mm_replacements']);
1355  }//end if
1356 
1357  // Content regenerated fire in the hole!
1358  $GLOBALS['SQ_SYSTEM']->broadcastTriggerEvent('trigger_event_after_metadata_updated', $asset);
1359 
1360  $result = FALSE;
1361  if (!$regenerate) {
1362  $result = TRUE;
1363  } else {
1364  $result = $this->setMetadata($assetid, $metadata, $contextid, $update_asset, TRUE);
1365  }
1366 
1367  if ($result) {
1368  $result = $this->_generateMetadataFieldFile($asset);
1369  }
1370 
1371  $GLOBALS['SQ_SYSTEM']->restoreContext();
1372 
1373  return $result;
1374 
1375  }//end generateContentFile()
1376 
1377 
1392  private function _generateMetadataFieldFile(Asset &$metadata_asset)
1393  {
1394  $contextid = $GLOBALS['SQ_SYSTEM']->getContextId();
1395 
1396  if ($contextid === 0) {
1397  $filename = 'metadata_field_values.php';
1398  } else {
1399  $filename = 'metadata_field_values.'.$contextid.'.php';
1400  }
1401 
1402  $schemas = $this->getSchemas($metadata_asset->id, TRUE);
1403  if (empty($schemas)) return FALSE;
1404 
1405  $metadata_field_values = $this->getMetadata($metadata_asset->id);
1406 
1407  foreach ($schemas as $schema_id) {
1408  $default_values = $this->getSchemaDefaultValues($schema_id);
1409 
1410  // Allocate default value if not "manually" supplied
1411  foreach ($default_values as $field_id => $field) {
1412  if (!isset($metadata_field_values[$field_id])) {
1413  $metadata_field_values[$field_id][0] = NULL;
1414  }
1415  }
1416  }
1417 
1418  ob_start();
1419  echo serialize($metadata_field_values);
1420  $metadata_str = ob_get_contents();
1421  ob_end_clean();
1422 
1423  require_once SQ_FUDGE_PATH.'/general/file_system.inc';
1424  if (!create_directory($metadata_asset->data_path)) return FALSE;
1425  if (!string_to_file($metadata_str, $metadata_asset->data_path.'/'.$filename)) {
1426  return FALSE;
1427  }
1428 
1429  return TRUE;
1430 
1431  }//end _generateMetadataFieldFile()
1432 
1433 
1451  function generateKeywordReplacements(&$metadata_asset, $keywords, $generating=TRUE)
1452  {
1453  $metadata_replacements = Array();
1454  $keywords = array_unique($keywords);
1455 
1456  if (!empty($keywords) && $generating) {
1457  echo '$metadata_replacements = Array();'."\n";
1458  }
1459 
1460  $thumbnail_generated = FALSE;
1461 
1462  foreach ($keywords as $keyword) {
1463 
1464  if ($generating) {
1465  $metadata_replacements[$keyword] = '$metadata_replacements['.var_export($keyword, 1).']';
1466  } else {
1467  ob_start();
1468  echo '$am =& $GLOBALS[\'SQ_SYSTEM\']->am;'."\n";
1469  }
1470 
1471  // Date/Time keywords are processed first.
1472  $replaced = FALSE;
1473  $prefix = Array(
1474  'asset_created',
1475  'asset_updated',
1476  'asset_status_changed',
1477  'asset_published',
1478  );
1479  foreach ($prefix as $name) {
1480  if (strpos($keyword, $name) === 0) {
1481  // NOTE: These format strings contain an escape '\' character
1482  // unlike the ones in getKeywordReplecement() asset.inc since they
1483  // will be concatenated within eval string.
1484  if ($keyword == $name) {
1485  $default_format = 'Y-m-d H:i:s';
1486  if ($keyword == 'asset_published') {
1487  echo '$metadata_replacements['.var_export($keyword, 1).'] = (is_null($metadata_asset->published)) ? \'Never\' : date(\''.$default_format.'\', $metadata_asset->published);'."\n";
1488  } else {
1489  echo '$metadata_replacements['.var_export($keyword, 1).'] = date(\''.$default_format.'\', $metadata_asset->'.substr($keyword,6).');'."\n";
1490  }
1491  $replaced = TRUE;
1492  } else {
1493  // Does the keyword match a certain date format? If so, replace
1494  // here; if not, then it will gets replaced further down (using date()
1495  // function).
1496  $date_formats = get_date_formats();
1497  $format_name = substr($keyword, strlen($name.'_'));
1498  if (array_key_exists($format_name, $date_formats)) {
1499  $format_expr = str_replace('/', '//', $date_formats[$format_name]);
1500  if ($keyword == 'asset_published') {
1501  echo '$metadata_replacements['.var_export($keyword, 1).'] = (is_null($metadata_asset->published)) ? \'Never\' : format_date($metadata_asset->published, \''.$format_name.'\');'."\n";
1502  } else {
1503  if ($format_name == 'iso8601') {
1504  echo '$metadata_replacements['.var_export($keyword, 1).'] = date(\''.$format_expr.'\', $metadata_asset->'.substr($keyword, strlen('asset_'), strlen($keyword) - strlen('_'.$format_name) - strlen('asset_')).').substr(date(\'O\'),0,3).\':\'.substr(date(\'O\'),-2);'."\n";
1505  } else {
1506  echo '$metadata_replacements['.var_export($keyword, 1).'] = format_date($metadata_asset->'.substr($keyword, strlen('asset_'), strlen($keyword) - strlen('_'.$format_name) - strlen('asset_')).', \''.$format_name.'\');'."\n";
1507  }
1508  }
1509  $replaced = TRUE;
1510  }
1511  }
1512  }//end if
1513  }//end foreach which loops through $prefix array
1514 
1515  $base_contextid = NULL;
1516  $full_keyword = $keyword;
1517  if (0 === strpos($keyword, 'asset_url_')) {
1518  // get the context id required from the name specified in the keyword
1519  // if there is a '_' in the context name, take it as a space. so, 'Default Context' and 'Default_Context' are treated as the same.
1520  $context_name = substr($keyword, 10);
1521  $context_name = str_replace('_', ' ', $context_name);
1522  $context_data = MatrixDAL::executeAll('core', 'getContextByName', Array('name' => Array($context_name)));
1523 
1524  // set the base contextid used later to get a correct URL and re-set the keyword without the context name to retrieve the replacement value later
1525  if (!empty($context_data)) {
1526  $base_contextid = $context_data[0]['contextid'];
1527  $keyword = 'asset_url';
1528  }
1529  }
1530 
1531  if (!$replaced) {
1532  switch ($keyword) {
1533  case 'asset_assetid' :
1534  echo '$metadata_replacements['.var_export($keyword, 1).'] = $metadata_asset->id;'."\n";
1535  break;
1536  case 'asset_name' :
1537  case 'asset_short_name' :
1538  case 'asset_version' :
1539  echo '$metadata_replacements['.var_export($keyword, 1).'] = $metadata_asset->'.substr($keyword,6).';'."\n";
1540  break;
1541 
1542  // version cases: if the version is undefined (eg. shadow assets), then make it expand
1543  // something that would result in all version components returning a blank
1544  case 'asset_version_major' :
1545  echo 'list($metadata_replacements['.var_export($keyword, 1).'],,) = explode(\'.\',empty($metadata_asset->version) ? \'..\' : $metadata_asset->version);'."\n";
1546  break;
1547 
1548  case 'asset_version_minor' :
1549  echo 'list(,$metadata_replacements['.var_export($keyword, 1).'],) = explode(\'.\',empty($metadata_asset->version) ? \'..\' : $metadata_asset->version);'."\n";
1550  break;
1551 
1552  case 'asset_version_micro' :
1553  echo 'list(,,$metadata_replacements['.var_export($keyword, 1).']) = explode(\'.\',empty($metadata_asset->version) ? \'..\' : $metadata_asset->version);'."\n";
1554  break;
1555 
1556  case 'asset_url' :
1557  echo '$metadata_replacements['.var_export($full_keyword, 1).'] = $metadata_asset->getURL(NULL, FALSE, $base_contextid);'."\n";
1558  break;
1559 
1560  case 'asset_name_linked' :
1561  echo '$url = $metadata_asset->getURL();'."\n";
1562  echo '$keyword = "";'."\n";
1563  echo 'if (!empty($url)) $keyword = "<a href=\"".$url."\">".$metadata_asset->name."</a>";'."\n";
1564  echo '$metadata_replacements['.var_export($keyword, 1).'] = $keyword;'."\n";
1565  break;
1566 
1567  case 'asset_short_name_linked' :
1568  echo '$url = $metadata_asset->getURL();'."\n";
1569  echo '$keyword = "";'."\n";
1570  echo 'if (!empty($url) && isset($metadata_asset->short_name)) $keyword = "<a href=\"".$url."\">".$metadata_asset->short_name."</a>";'."\n";
1571  echo '$metadata_replacements['.var_export($keyword, 1).'] = $keyword;'."\n";
1572  break;
1573 
1574  case 'asset_href' :
1575  echo '$metadata_replacements['.var_export($keyword, 1).'] = $metadata_asset->getHref();'."\n";
1576  break;
1577 
1578  case 'asset_thumbnail' :
1579  case 'asset_thumbnail_url' :
1580  case 'asset_thumbnail_width' :
1581  case 'asset_thumbnail_height' :
1582  case 'asset_thumbnail_alt' :
1583  case 'asset_thumbnail_caption' :
1584  case 'asset_thumbnail_assetid' :
1585  case 'asset_thumbnail_title' :
1586  case 'asset_thumbnail_name' :
1587  if (!$thumbnail_generated) {
1588  echo '$thumbnail = null;';
1589  echo 'if ($metadata_asset->useSystemVersion()) {'."\n";
1590  echo ' $notice_links = unserialize(file_to_string($metadata_asset->data_path.\'/.sq_notice_links\'));'."\n";
1591  echo ' foreach ($notice_links as $link) {'."\n";
1592  echo ' if ($link[\'value\'] == \'thumbnail\') {'."\n";
1593  echo ' $thumbnail = $GLOBALS[\'SQ_SYSTEM\']->am->getAsset($link[\'minorid\']);'."\n";
1594  echo ' break;'."\n";
1595  echo ' }'."\n";
1596  echo ' }'."\n";
1597  echo '} else {'."\n";
1598  echo ' if ($metadata_asset->id) {';
1599  echo ' $link = $GLOBALS[\'SQ_SYSTEM\']->am->getLink($metadata_asset->id, SQ_LINK_NOTICE, \'image\', FALSE, \'thumbnail\');'."\n";
1600  echo ' if (!empty($link)) {'."\n";
1601  echo ' $thumbnail = $GLOBALS[\'SQ_SYSTEM\']->am->getAsset($link[\'minorid\'], $link[\'minor_type_code\']);'."\n";
1602  echo ' }'."\n";
1603  echo ' }'."\n";
1604  echo '}'."\n";
1605  }
1606  switch ($keyword) {
1607  case 'asset_thumbnail' :
1608  echo '$metadata_replacements['.var_export($keyword, 1).'] = (is_null($thumbnail)) ? \'\' : $thumbnail->printImageTag(\'\', \'\', TRUE);'."\n";
1609  break;
1610  case 'asset_thumbnail_url' :
1611  echo '$metadata_replacements['.var_export($keyword, 1).'] = (is_null($thumbnail)) ? \'\' : $thumbnail->getURL();'."\n";
1612  break;
1613  case 'asset_thumbnail_width' :
1614  case 'asset_thumbnail_height' :
1615  case 'asset_thumbnail_alt' :
1616  case 'asset_thumbnail_caption' :
1617  case 'asset_thumbnail_title' :
1618  case 'asset_thumbnail_name' :
1619  $sub_keyword = substr($keyword, 16);
1620  echo '$metadata_replacements['.var_export($keyword, 1).'] = (is_null($thumbnail)) ? \'\' : $thumbnail->attr(\''.$sub_keyword.'\');'."\n";
1621  break;
1622  case 'asset_thumbnail_assetid' :
1623  echo '$metadata_replacements['.var_export($keyword, 1).'] = (is_null($thumbnail)) ? \'\' : $thumbnail->id;'."\n";
1624  break;
1625  }
1626  break;
1627 
1628  case 'asset_created_by_assetid' :
1629  case 'asset_created_by_url' :
1630  case 'asset_created_by_name' :
1631  case 'asset_updated_by_name' :
1632  case 'asset_status_changed_by_name':
1633  $pattern = '/^asset_(.*?)_by_(.*)$/';
1634  preg_match($pattern, $keyword, $matches);
1635  $field_name = $matches[1];
1636  $user_member = $matches[2];
1637  switch ($user_member) {
1638  case 'assetid':
1639  $user_member = 'id';
1640  break;
1641  case 'url':
1642  $user_member = 'getURL()';
1643  break;
1644  }
1645  echo 'if (!isset($metadata_'.$field_name.'_by_user) && !empty($metadata_asset->'.$field_name.'_userid)) {'."\n";
1646  echo ' $metadata_'.$field_name.'_by_user = $GLOBALS[\'SQ_SYSTEM\']->am->getAsset($metadata_asset->'.$field_name.'_userid, \'\', TRUE);'."\n";
1647  echo '}'."\n";
1648  echo 'if (!empty($metadata_'.$field_name.'_by_user)) {'."\n";
1649  echo ' $metadata_replacements['.var_export($keyword, 1).'] = $metadata_'.$field_name.'_by_user->'.$user_member.";\n";
1650  echo '} else {'."\n";
1651  echo ' $metadata_replacements['.var_export($keyword, 1).'] = \''.translate('unknown').'\';'."\n";
1652  echo '}'."\n";
1653  break;
1654 
1655  case 'asset_created_by_first_name' :
1656  case 'asset_created_by_last_name' :
1657  case 'asset_created_by_email' :
1658  case 'asset_updated_by_first_name' :
1659  case 'asset_updated_by_last_name' :
1660  case 'asset_updated_by_email' :
1661  echo 'if (!isset($metadata_'.substr($keyword,6,7).'_by_user) && !empty($metadata_asset->'.substr($keyword,6,7).'_userid)) {
1662  $metadata_'.substr($keyword,6,7).'_by_user = $GLOBALS[\'SQ_SYSTEM\']->am->getAsset($metadata_asset->'.substr($keyword,6,7).'_userid,\'\', TRUE);'."\n}\n";
1663  echo 'if (!empty($metadata_'.substr($keyword,6,7).'_by_user)) { ';
1664  echo '$metadata_replacements['.var_export($keyword, 1).'] = $metadata_'.substr($keyword,6,7).'_by_user->attr(\''.substr($keyword,17).'\');'."\n";
1665  echo '} else {'."\n";
1666  echo '$metadata_replacements['.var_export($keyword, 1).'] = \''.translate('unknown').'\';'."\n";
1667  echo '}'."\n";
1668 
1669  break;
1670 
1671  // can't handle 'last published' stuff in the same way as created/updated because
1672  // there is a chance that it has never been published
1673  case 'asset_published_by_name' :
1674  echo 'if (empty($metadata_asset->published_userid)) {'."\n";
1675  echo '$metadata_replacements['.var_export($keyword, 1).'] = \'Never Published\';'."\n";
1676  echo '} else { if (!isset($metadata_published_by_user)) {
1677  $metadata_published_by_user = $GLOBALS[\'SQ_SYSTEM\']->am->getAsset($metadata_asset->published_userid, \'\', TRUE);'."\n}\n";
1678  echo 'if (!empty($metadata_published_by_user)) { ';
1679  echo '$metadata_replacements['.var_export($keyword, 1).'] = $metadata_published_by_user->name;'."\n";
1680  echo '} else {'."\n";
1681  echo '$metadata_replacements['.var_export($keyword, 1).'] = \''.translate('unknown').'\';'."\n";
1682  echo '}}'."\n";
1683  break;
1684 
1685  case 'asset_published_by_first_name' :
1686  case 'asset_published_by_last_name' :
1687  case 'asset_published_by_email' :
1688  echo 'if (empty($metadata_asset->published_userid)) {'."\n";
1689  echo '$metadata_replacements['.var_export($keyword, 1).'] = \'\';'."\n";
1690  echo '} else { if (!isset($metadata_published_by_user)) {
1691  $metadata_published_by_user = $GLOBALS[\'SQ_SYSTEM\']->am->getAsset($metadata_asset->published_userid, \'\', TRUE);'."\n}\n";
1692  echo 'if (!empty($metadata_published_by_user)) { ';
1693  echo '$metadata_replacements['.var_export($keyword, 1).'] = $metadata_published_by_user->attr(\''.substr($keyword,19).'\');'."\n";
1694  echo '} else {'."\n";
1695  echo '$metadata_replacements['.var_export($keyword, 1).'] = \''.translate('unknown').'\';'."\n";
1696  echo '}}'."\n";
1697 
1698  break;
1699 
1700  case 'asset_read_permission' :
1701  case 'asset_write_permission' :
1702  case 'asset_admin_permission' :
1703  case 'asset_read_permission_assetid' :
1704  case 'asset_write_permission_assetid' :
1705  case 'asset_admin_permission_assetid' :
1706  case 'asset_read_permission_email' :
1707  case 'asset_write_permission_email' :
1708  case 'asset_admin_permission_email' :
1709  case 'asset_read_permission_email_linked' :
1710  case 'asset_write_permission_email_linked' :
1711  case 'asset_admin_permission_email_linked' :
1712  $perm_type = preg_match('/asset_([^_]*)_.*$/', $keyword, $matches);
1713  $perm_type = $matches[1];
1714  echo '$metadata_'.$perm_type.'_perms = $am->getPermission($metadata_asset->id, SQ_PERMISSION_'.strtoupper($perm_type).', TRUE, FALSE, TRUE);'."\n";
1715  echo '$metadata_'.$perm_type.'_perm_info = Array();'."\n";
1716  echo 'foreach ($metadata_'.$perm_type.'_perms as $userid) {'."\n";
1717  echo ' $user = $am->getAsset($userid);'."\n";
1718  echo ' if (is_null($user) || !$am->isTypeDecendant($user->type(), \'user\')) {'."\n";
1719  echo ' continue;'."\n";
1720  echo ' }'."\n";
1721  if (preg_match('/.*_assetid$/', $keyword)) {
1722  echo '$metadata_'.$perm_type.'_perm_info[] = $user->id;'."\n";
1723  }
1724  else if (preg_match('/.*_email$/', $keyword)) {
1725  echo '$metadata_'.$perm_type.'_perm_info[] = $user->attr(\'email\');'."\n";
1726  } else if (preg_match('/.*_email_linked/', $keyword)) {
1727  echo '$email = $user->attr(\'email\');'."\n";
1728  echo '$metadata_'.$perm_type.'_perm_info[] = \'<a href="mailto:\'.$email.\'">\'.$email.\'</a>\';'."\n";
1729  } else {
1730  echo '$metadata_'.$perm_type.'_perm_info[] = $user->name;'."\n";
1731  }
1732  echo '}'."\n";
1733  echo '$metadata_replacements['.var_export($keyword, 1).'] = implode(\', \', $metadata_'.$perm_type.'_perm_info);'."\n";
1734  break;
1735  case 'system_name' :
1736  case 'system_owner' :
1737  case 'default_email' :
1738  case 'tech_email' :
1739  echo '$metadata_replacements['.var_export($keyword, 1).'] = SQ_CONF_'.strtoupper($keyword).';'."\n";
1740  break;
1741 
1742  default :
1743  if (substr($keyword, 0, 11) == 'asset_role_') {
1744  echo '$metadata_roles_info = Array();'."\n";
1745  if (preg_match('/asset_role_([0-9]+)(.*)$/', $keyword, $matches)) {
1746  $fetch_global_roles = (SQ_CONF_ENABLE_GLOBAL_ROLES == '1');
1747  $role_assetid = $matches[1];
1748  echo '$metadata_roles = $am->getRole($metadata_asset->id, '.$role_assetid.', NULL, FALSE, '.(($fetch_global_roles)?'TRUE':'FALSE').', TRUE);'."\n";
1749  echo 'if (!empty($metadata_roles)) {'."\n";
1750  echo ' foreach ($metadata_roles['.$role_assetid.'] as $role_userid) {'."\n";
1751  echo ' $user = $GLOBALS[\'SQ_SYSTEM\']->am->getAsset($role_userid);'."\n";
1752  echo ' if (is_null($user) || !$am->isTypeDecendant($user->type(), \'user\')) {'."\n";
1753  echo ' continue;'."\n";
1754  echo ' }'."\n";
1755  echo ' $email = $user->attr(\'email\');'."\n";
1756  if (!empty($matches[2]) && $matches[2] == '_email') {
1757  echo ' $metadata_roles_info[] = $email;'."\n";
1758  } else if (!empty($matches[2]) && $matches[2] == '_email_linked') {
1759  echo ' $metadata_roles_info[] = \'<a href="mailto:\'.$email.\'">\'.$email.\'</a>\';'."\n";
1760  } else {
1761  echo ' $metadata_roles_info[] = $user->name;'."\n";
1762  }
1763  echo ' $am->forgetAsset($user);'."\n";
1764  echo ' }'."\n";
1765  echo '}'."\n";
1766  }
1767  echo ' $metadata_replacements['.var_export($keyword, 1).'] = implode(\', \', $metadata_roles_info);'."\n";
1768 
1769  // searching for keywords that replace the content of another field
1770  } else if (substr($keyword, 0, 15) == 'metadata_field_') {
1771  // avoid replacing metadata_field_xxxxx keywords until later
1772  // override the default replacement with the original keyword
1773  $metadata_replacements[$keyword] = '%'.$keyword.'%';
1774 
1775  } else if (substr($keyword, 0, 18) == 'asset_thumbnail_v_') {
1776  // Print the asset variety of a thumbnail
1777  $variety_name = substr($keyword, 18);
1778  if (!$thumbnail_generated) {
1779  echo '$thumbnail = null;'."\n";
1780  echo 'if ($metadata_asset->useSystemVersion()) {'."\n";
1781  echo ' $notice_links = unserialize(file_to_string($metadata_asset->data_path.\'/.sq_notice_links\'));'."\n";
1782  echo ' foreach ($notice_links as $link) {'."\n";
1783  echo ' if ($link[\'value\'] == \'thumbnail\') {'."\n";
1784  echo ' $thumbnail = $GLOBALS[\'SQ_SYSTEM\']->am->getAsset($link[\'minorid\']);'."\n";
1785  echo ' break;'."\n";
1786  echo ' }'."\n";
1787  echo ' }'."\n";
1788  echo '} else {'."\n";
1789  echo ' if ($metadata_asset->id) {'."\n";
1790  echo ' $link = $GLOBALS[\'SQ_SYSTEM\']->am->getLink($metadata_asset->id, SQ_LINK_NOTICE, \'image\', FALSE, \'thumbnail\');'."\n";
1791  echo ' if (!empty($link)) {'."\n";
1792  echo ' $thumbnail = $GLOBALS[\'SQ_SYSTEM\']->am->getAsset($link[\'minorid\'], $link[\'minor_type_code\']);'."\n";
1793  echo ' }'."\n";
1794  echo ' }'."\n";
1795  echo '}'."\n";
1796  }
1797 
1798  echo '$metadata_replacements['.var_export($keyword, 1).'] = (is_null($thumbnail)) ? \'\' : $thumbnail->getKeywordReplacement(\'image_v_'.$variety_name.'\');';
1799 
1800  } else {
1801  // searching for special date format keywords
1802  $original = $keyword;
1803  $keyword = substr($keyword, 6);
1804  $key = substr($keyword, 0, strpos($keyword, '_'));
1805  $extras = substr($keyword, strpos($keyword, '_') +1);
1806 
1807  if (strpos($extras, '_') === FALSE) {
1808  $format = $extras;
1809  $offset = '';
1810  } else {
1811  list ($format, $offset) = explode('_', $extras);
1812  }
1813  $format = str_replace('~', ' ', $format);
1814 
1815  switch ($key) {
1816  case 'created':
1817  case 'updated':
1818  case 'published':
1819  if (empty($offset)) {
1820  $date = '$metadata_asset->'.$key;
1821  } else {
1822  $date = 'strtotime(\''.$offset.'\', $metadata_asset->'.$key.')';
1823  }
1824  echo '$metadata_replacements[\''.$original.'\'] = date(\''.$format.'\', '.$date.');'."\n";
1825  break;
1826  }
1827  }//end if
1828  break;
1829  }//end switch
1830  }//end if
1831 
1832  if (!$generating) {
1833  eval(ob_get_contents());
1834  ob_end_clean();
1835  }
1836  }//end foreach
1837 
1838  return $metadata_replacements;
1839 
1840  }//end generateKeywordReplacements()
1841 
1842 
1857  function regenerateMetadata($assetid, $contextid=NULL, $update_asset=TRUE)
1858  {
1859  if ($contextid === NULL) {
1860  $contextid = $GLOBALS['SQ_SYSTEM']->getContextId();
1861  }
1862 
1863  if ($contextid === 'all') {
1864  $all_contexts = $GLOBALS['SQ_SYSTEM']->getAllContexts();
1865  $last_contextid = end(array_keys($all_contexts));
1866  $ok = TRUE;
1867 
1868  // Since we're doing this for all contexts, and search indexing events should ideally
1869  // be handled once for all contexts to avoid num_contexts * num_contexts iterations,
1870  // we need to ensure search reindexing is "fast tracked".
1871  //
1872  // We ensure reindex tasks are fast tracked for all but the last context, so the reindex
1873  // events will be handled correctly once at the end.
1874  foreach ($all_contexts as $contextid => $context_data) {
1875 
1876  // Get the asset in each context
1877  $GLOBALS['SQ_SYSTEM']->changeContext($contextid);
1878  $temp_asset = $GLOBALS['SQ_SYSTEM']->am->getAsset($assetid);
1879 
1880  // If we're not the last context, fast track!
1881  if ($contextid != $last_contextid) {
1882  $temp_asset->fastTrack(Array('search_manager_reindex_metadata', 'trigger_event_metadata_updated'));
1883  }
1884 
1885  $ok = $ok && $this->generateContentFile($assetid, TRUE, $contextid, $update_asset);
1886 
1887  // Reset fast tracked tasks.
1888  if ($contextid != $last_contextid) {
1889  $temp_asset->unFastTrack(Array('search_manager_reindex_metadata', 'trigger_event_metadata_updated'));
1890  }
1891 
1892  $GLOBALS['SQ_SYSTEM']->restoreContext();
1893  }
1894  } else {
1895  $ok = $this->generateContentFile($assetid, TRUE, $contextid, $update_asset);
1896  }
1897 
1898  return $ok;
1899 
1900  }//end regenerateMetadata()
1901 
1902 
1911  function purgeMetadata($assetid)
1912  {
1913  $GLOBALS['SQ_SYSTEM']->changeDatabaseConnection('db2');
1914  $GLOBALS['SQ_SYSTEM']->doTransaction('BEGIN');
1915 
1916  $bind_vars = Array (
1917  'assetid' => $assetid,
1918  );
1919  try {
1920  $result = MatrixDAL::executeQuery('core', 'purgeMetadataSchema', $bind_vars);
1921  } catch (Exception $e) {
1922  throw new Exception('Unable to purge metadata schema for assetid #'.$assetid.' due to the following database error:'.$e->getMessage());
1923  }
1924 
1925  try {
1926  $result = MatrixDAL::executeQuery('core', 'purgeMetadataValue', $bind_vars);
1927  } catch (Exception $e) {
1928  throw new Exception('Unable to purge metadata value for assetid #'.$assetid.' due to the following database error:'.$e->getMessage());
1929  }
1930 
1931  $GLOBALS['SQ_SYSTEM']->doTransaction('COMMIT');
1932  $GLOBALS['SQ_SYSTEM']->restoreDatabaseConnection();
1933 
1934  return TRUE;
1935 
1936  }//end purgeMetadata()
1937 
1938 
1956  function getMetadataInterfaceValueByAssetid($assetid, $field_assetid, $mute_errors=FALSE, &$has_errors=FALSE, $contextid=NULL)
1957  {
1958  if (empty($assetid)) return NULL;
1959 
1960  // is this actually a metadata field or what?!
1961  if (!$this->isMetadataFieldAssetid($field_assetid)) {
1962  $has_errors = TRUE;
1963  if (!$mute_errors) {
1964  trigger_localised_error('SYS0308', E_USER_WARNING, $field_assetid);
1965  }
1966  return NULL;
1967  }
1968 
1969  if ($contextid === NULL) {
1970  $contextid = $GLOBALS['SQ_SYSTEM']->getContextId();
1971  }
1972 
1973  // get the parent schema of this metadata field
1974  $schemaid = $GLOBALS['SQ_SYSTEM']->am->getParents($field_assetid, 'metadata_schema');
1975 
1976  // get the schemas that apply to this asset
1977  $schemas = $this->getSchemas($assetid, TRUE);
1978 
1979  if (array_intersect($schemas, array_keys($schemaid)) == Array()) {
1980  $has_errors = TRUE;
1981  if (!$mute_errors) {
1982  // SYS0307: Asset #<assetid> does not have the schema for field #<field assetid> applied
1983  trigger_localised_error('SYS0307', E_USER_WARNING, $assetid, $field_assetid);
1984  }
1985  return NULL;
1986  }
1987 
1988  $sql = 'SELECT
1989  value
1990  FROM
1991  '.SQ_TABLE_RUNNING_PREFIX.'ast_mdata_val mdv';
1992  $where = 'mdv.assetid = :assetid
1993  AND mdv.fieldid = :field_assetid
1994  AND mdv.contextid = :contextid';
1995  $where = $GLOBALS['SQ_SYSTEM']->constructRollbackWhereClause($where, 'mdv');
1996 
1997  try {
1998  $query = MatrixDAL::preparePdoQuery($sql.$where);
1999  MatrixDAL::bindValueToPdo($query, 'assetid', $assetid);
2000  MatrixDAL::bindValueToPdo($query, 'field_assetid', $field_assetid);
2001  MatrixDAL::bindValueToPdo($query, 'contextid', $contextid);
2002  $value = MatrixDAL::executePdoOne($query);
2003  } catch (Exception $e) {
2004  // Unable to get metadata interface value due to DB error
2005  throw new Exception(translate_error('SYS0343', $field_assetid, $assetid, $contextid, $e->getMessage()));
2006  }//end try catch
2007 
2008 
2009  // Matrix DAL returns FALSE when no rows found, for consistancy we should return NULL
2010  if ($value === FALSE) {
2011  $value = NULL;
2012  }
2013 
2014  return $value;
2015 
2016  }//end getMetadataInterfaceValueByAssetid()
2017 
2018 
2038  function getMetadataValueByAssetid($assetid, $field_assetid, $mute_errors=FALSE, $replace_nested_keyword=FALSE, $contextid=NULL)
2039  {
2040  // Could change the context here, but the asset isn't used for anything
2041  // other than getting a data path, so will refrain for now
2042  if ($contextid === NULL) {
2043  $contextid = $GLOBALS['SQ_SYSTEM']->getContextId();
2044  }
2045 
2046  if ($contextid === 0) {
2047  $metadata_basename = 'metadata.php';
2048  } else {
2049  $metadata_basename = 'metadata.'.$contextid.'.php';
2050  }
2051 
2052  $value = '';
2053 
2054  // sometimes there are nested keywords in the value of the metadata field
2055  // We are asked to replace these nested keywords
2056  if ($replace_nested_keyword) {
2057 
2058  // get the metadata value from the generated metadata.php file
2059  $am =& $GLOBALS['SQ_SYSTEM']->am;
2060  $asset = $am->getAsset($assetid);
2061  $_metadata_filename = $asset->data_path.'/'.$metadata_basename;
2062 
2063  // if the file exists then retrieve the value of the metadata field
2064  if (is_file($_metadata_filename)) {
2065  $metadata = $this->loadMetadataFile($assetid, $_metadata_filename);
2066 
2067  if (isset($metadata['values'])) {
2068  $metadata_values = $metadata['values'];
2069  $field_names = $GLOBALS['SQ_SYSTEM']->am->getAssetInfo(Array($field_assetid), 'metadata_field', FALSE, 'name');
2070  $value = $metadata_values[$field_names[$field_assetid]];
2071  }
2072  }
2073  }
2074 
2075  if ($value === '') {
2076  $value = $this->getMetadataInterfaceValueByAssetid($assetid, $field_assetid, $mute_errors, $has_errors, $contextid);
2077 
2078  //if there is no error such as the field ID is not a metadata field ID or the metadata schema containing
2079  //that field is not applied to the asset
2080  if (!$has_errors && is_null($value)) {
2081  // not set - need the default value
2082  $value = $this->getMetadataFieldDefaultValue($field_assetid, $contextid);
2083  }
2084  }
2085 
2086  return $value;
2087 
2088  }//end getMetadataValueByAssetid()
2089 
2090 
2100  function isMetadataFieldAssetid($field_assetid)
2101  {
2102  static $cached_tests = Array();
2103 
2104  if (!isset($cached_tests[$field_assetid])) {
2105  $sql = 'SELECT
2106  COUNT(*)
2107  FROM
2108  sq_ast_typ_inhd ati
2109  JOIN '.SQ_TABLE_RUNNING_PREFIX.'ast a ON ati.type_code = a.type_code';
2110  $where = 'a.assetid = :field_assetid
2111  AND ati.inhd_type_code = :inhd_type_code';
2112  $where = $GLOBALS['SQ_SYSTEM']->constructRollbackWhereClause($where, 'a');
2113 
2114  try {
2115  $query = MatrixDAL::preparePdoQuery($sql.$where);
2116  MatrixDAL::bindValueToPdo($query, 'field_assetid', $field_assetid);
2117  MatrixDAL::bindValueToPdo($query, 'inhd_type_code', 'metadata_field');
2118  $count = MatrixDAL::executePdoOne($query);
2119  } catch (Exception $e) {
2120  throw new Exception('Unable to determine whether the asset is a metadata field due to the following database error:'.$e->getMessage());
2121  }//end try catch
2122 
2123  $cached_tests[$field_assetid] = ($count > 0);
2124  }
2125 
2126  return $cached_tests[$field_assetid];
2127 
2128  }//end isMetadataFieldAssetid()
2129 
2130 
2141  function getMetadataFieldDefaultValue($field_assetid, $contextid=NULL)
2142  {
2143  if ($contextid === NULL) {
2144  $contextid = $GLOBALS['SQ_SYSTEM']->getContextId();
2145  }
2146 
2147  // Whoops, the asset ID passed isn't a metadata field
2148  if (!$this->isMetadataFieldAssetid($field_assetid)) {
2149  trigger_localised_error('SYS0308', E_USER_WARNING, $field_assetid);
2150  }
2151 
2152  // If the current context is the default context, this has to get the default value in
2153  // the default context, so, it doesn't matter if the field is contextable or not.
2154  // If this is not a contextable metadata field, then grab the default value from context zero.
2155  if ($contextid != 0) {
2156  // If the asset is already in asset cache, get the attribute from the cached asset - it's quicker than connecting to the db
2157  $asset = $GLOBALS['SQ_SYSTEM']->am->_asset_cache->get($contextid.'\\'.$field_assetid);
2158  if (empty($asset)) {
2159  // Try Deja vu
2160  $deja_vu = $GLOBALS['SQ_SYSTEM']->getDejaVu();
2161  if ($deja_vu) {
2162  $asset = $deja_vu->recall(SQ_DEJA_VU_ASSET, $field_assetid);
2163  }
2164  }
2165 
2166  if (!empty($asset)) {
2167  $is_contextable = (boolean)$asset->attr('is_contextable');
2168  } else {
2169  $is_contextable = $GLOBALS['SQ_SYSTEM']->am->getAttributeValuesByName('is_contextable', 'metadata_field', Array($field_assetid));
2170  $is_contextable = (boolean)$is_contextable[$field_assetid];
2171  }
2172 
2173  if ($is_contextable === FALSE) {
2174  $contextid = 0;
2175  }
2176  }
2177 
2178  static $cached_defaults = Array();
2179  $recache_value = TRUE;
2180  if (in_array($contextid, array_keys($cached_defaults)) === TRUE) {
2181  if (in_array($field_assetid, array_keys($cached_defaults[$contextid])) === TRUE) {
2182  $recache_value = FALSE;
2183  }
2184  }
2185 
2186  // We should recache the value
2187  if ($recache_value === TRUE) {
2188  $sql = 'SELECT
2189  default_val
2190  FROM
2191  '.SQ_TABLE_RUNNING_PREFIX.'ast_mdata_dflt_val mdv';
2192  $where = 'mdv.assetid = :field_assetid AND mdv.contextid = :contextid';
2193  $where = $GLOBALS['SQ_SYSTEM']->constructRollbackWhereClause($where, 'mdv');
2194 
2195  try {
2196  $query = MatrixDAL::preparePdoQuery($sql.$where);
2197  MatrixDAL::bindValueToPdo($query, 'field_assetid', $field_assetid);
2198  MatrixDAL::bindValueToPdo($query, 'contextid', $contextid);
2199  $default_val = MatrixDAL::executePdoOne($query);
2200  } catch (Exception $e) {
2201  throw new Exception(translate_error('SYS0335', $field_assetid, $contextid, $e->getMessage()));
2202  }//end try catch
2203 
2204  $cached_defaults[$contextid][$field_assetid] = $default_val;
2205  }
2206 
2207  return $cached_defaults[$contextid][$field_assetid];
2208 
2209  }//end getMetadataFieldDefaultValue()
2210 
2211 
2223  function setMetadataFieldDefaultValue($field_assetid, $value, $contextid=NULL)
2224  {
2225  if ($contextid === NULL) {
2226  $contextid = $GLOBALS['SQ_SYSTEM']->getContextId();
2227  }
2228 
2229  // is this actually a metadata field or what?!
2230  if (!$this->isMetadataFieldAssetid($field_assetid)) {
2231  trigger_localised_error('SYS0308', E_USER_WARNING, $field_assetid);
2232  }
2233 
2234  // If the current context is the default context, this has to get the default value in
2235  // the default context, so, it doesn't matter if the field is contextable or not.
2236  // If this is not a contextable metadata field, then grab the default value from context zero.
2237  if ($contextid != 0) {
2238  // If the asset is already in asset cache, get the attribute from the cached asset - it's quicker than connecting to the db
2239  $asset = $GLOBALS['SQ_SYSTEM']->am->_asset_cache->get($contextid.'\\'.$field_assetid);
2240  if (empty($asset)) {
2241  // Try Deja vu
2242  $deja_vu = $GLOBALS['SQ_SYSTEM']->getDejaVu();
2243  if ($deja_vu) {
2244  $asset = $deja_vu->recall(SQ_DEJA_VU_ASSET, $field_assetid);
2245  }
2246  }
2247 
2248  if (!empty($asset)) {
2249  $is_contextable = (boolean)$asset->attr('is_contextable');
2250  } else {
2251  $is_contextable = $GLOBALS['SQ_SYSTEM']->am->getAttributeValuesByName('is_contextable', 'metadata_field', Array($field_assetid));
2252  $is_contextable = (boolean)$is_contextable[$field_assetid];
2253  }
2254 
2255  if ($is_contextable === FALSE) {
2256  $contextid = 0;
2257  }
2258  }
2259 
2260  $sql = 'SELECT
2261  default_val
2262  FROM
2263  '.SQ_TABLE_RUNNING_PREFIX.'ast_mdata_dflt_val mdv';
2264  $where = 'mdv.assetid = :field_assetid
2265  AND mdv.contextid = :contextid';
2266  $where = $GLOBALS['SQ_SYSTEM']->constructRollbackWhereClause($where, 'mdv');
2267 
2268  try {
2269  $query = MatrixDAL::preparePdoQuery($sql.$where);
2270  MatrixDAL::bindValueToPdo($query, 'field_assetid', $field_assetid);
2271  MatrixDAL::bindValueToPdo($query, 'contextid', $contextid);
2272  $row = MatrixDAL::executePdoAll($query);
2273  if (isset($row[0]) && !empty($row[0])) {
2274  $row = $row[0];
2275  }
2276  } catch (Exception $e) {
2277  // "Cannot get default value of field in context, DB error"
2278  throw new Exception(translate_error('SYS0336', $field_assetid, $contextid, $e->getMessage()));
2279  }
2280 
2281  $GLOBALS['SQ_SYSTEM']->changeDatabaseConnection('db2');
2282  $GLOBALS['SQ_SYSTEM']->doTransaction('BEGIN');
2283 
2284  try {
2285  // does the default value exist yet, then?
2286  if (is_null($row) || empty($row)) {
2287  // "Cannot set default value of field in context, DB error"
2288  $message = 'SYS0336';
2289  $bind_vars = Array (
2290  'field_assetid' => $field_assetid,
2291  'contextid' => $contextid,
2292  'value' => $value,
2293  );
2294  $value = MatrixDAL::executeQuery('core', 'setMetadataFieldDefaultValue', $bind_vars);
2295  } else {
2296  // "Cannot update default value of field in context, DB error"
2297  $message = 'SYS0337';
2298  $bind_vars = Array (
2299  'field_assetid' => $field_assetid,
2300  'contextid' => $contextid,
2301  'default_val' => $value,
2302  );
2303  $value = MatrixDAL::executeQuery('core', 'updateMetadataFieldDefaultValue', $bind_vars);
2304  }
2305  } catch (Exception $e) {
2306  throw new Exception(translate_error($message, $field_assetid, $contextid, $e->getMessage()));
2307  }//end try catch
2308 
2309 
2310  $GLOBALS['SQ_SYSTEM']->doTransaction('COMMIT');
2311  $GLOBALS['SQ_SYSTEM']->restoreDatabaseConnection();
2312 
2313  return TRUE;
2314 
2315  }//end setMetadataFieldDefaultValue()
2316 
2317 
2328  function escapeMetadata($value, $escape_single=FALSE)
2329  {
2330  if ($escape_single) {
2331  $value = str_replace("'", "\'", $value);
2332  }
2333 
2334  // For the thesaurus metadata, using commas to separate values
2335  // We need to replace the commas in the thesaurus back.
2336  $value = str_replace('&#44;', ',', $value);
2337 
2338  // escape only html-specific chars for the moment
2339  $value = htmlspecialchars($value);
2340 
2341  // escape everything else (chars > 126)
2342  $result = '';
2343 
2344  // if default character set is utf-8 we dont wanna mess around the characters
2345  // we are for now just checking for it not to be utf-8 but can append other encoding
2346  // we might want to skip later on
2347  if (strtolower(SQ_CONF_DEFAULT_CHARACTER_SET) != 'utf-8') {
2348  // escape everything else (chars > 126)
2349  for ($i = 0; $i < strlen($value); ++$i) {
2350  $ord = ord($value[$i]);
2351  if ($ord > 126) {
2352  $result .= '&#'.$ord.';';
2353  } else {
2354  $result .= $value[$i];
2355  }
2356  }// end for
2357  }
2358 
2359  return $result ? $result : $value;
2360 
2361  }//end escapeMetadata()
2362 
2363 
2379  public function getFieldAssetIdFromName($assetid, $target_field_name)
2380  {
2381  assert_valid_assetid($assetid);
2382  assert_true(is_string($target_field_name));
2383 
2384  // Get a list of the applied schemas' field assets - first their IDs,
2385  // then their names
2386  $schemaids = $this->getSchemas($assetid, TRUE);
2387  $fields = $this->getMetadataFields($schemaids);
2388 
2389  $field_assetids = array_keys($fields);
2390  $field_names = $GLOBALS['SQ_SYSTEM']->am->getAssetInfo($field_assetids, 'metadata_field', FALSE, 'name');
2391 
2392  // Is the field name we want in this list?
2393  // If found, it will return the key (asset ID) that we want. If not,
2394  // it will return FALSE. Either way, return this to the function
2395  $assetid = array_search($target_field_name, $field_names);
2396 
2397  return $assetid;
2398 
2399  }//end getFieldAssetIdFromName()
2400 
2401 
2402 
2418  public function getMetadataFieldTypeValues($assetid, $metadata_field_type, $contextid=NULL)
2419  {
2420  $schemas = $this->getSchemas($assetid, TRUE);
2421  if (empty($schemas)) return Array();
2422 
2423  $metadata_field_type = strtolower($metadata_field_type);
2424  $field_values = Array();
2425 
2426  foreach($schemas as $schemaid) {
2427  $fields = $this->getMetadataFields($schemaid);
2428 
2429  foreach($fields as $fieldid => $field_type) {
2430  if ($field_type[0]['type_code'] != $metadata_field_type) continue;
2431  $field_info = $GLOBALS['SQ_SYSTEM']->am->getAssetInfo($fieldid);
2432  if (empty($field_info)) continue;
2433 
2434  $field_values[$field_info[$fieldid]['name']] = $this->getMetadataValueByAssetid($assetid, $fieldid, FALSE, FALSE, $contextid);
2435  }
2436  }
2437 
2438  return $field_values;
2439  }
2440 
2441 
2442 }//end class
2443 ?>