Squiz Matrix  4.12.2
 All Data Structures Namespaces Functions Variables Pages
trim_saved_search.inc
1 <?php
2 
19 require_once SQ_INCLUDE_PATH.'/asset.inc';
20 require_once SQ_CORE_PACKAGE_PATH.'/data_source/data_source/data_source.inc';
21 require_once SQ_LIB_PATH.'/html_form/html_form.inc';
22 require_once SQ_PACKAGES_PATH.'/trim/lib/trim_common.inc';
23 
37 {
38 
39 
46  function __construct($assetid=0)
47  {
48  parent::__construct($assetid);
49 
50  $this->_ser_attrs = TRUE;
51  $this->search_clauses = NULL;
52 
53  }//end constructor
54 
55 
66  protected function _createAdditional(Array &$link, $args=Array())
67  {
68 
69  if (!parent::_createAdditional($link)) return FALSE;
70  $this->setAttrValue('shadow_name', '%ds__recTitle%');
71 
72  return TRUE;
73 
74  }//end _createAdditional()
75 
76 
90  public function _getAllowedLinks()
91  {
92  // any link is allowed
93  $allowed_link['asset']['card'] = 'M';
94  $allowed_link['asset']['exclusive'] = FALSE;
95 
96  $links[SQ_LINK_TYPE_1] = $allowed_link;
97  $links[SQ_LINK_TYPE_2] = $allowed_link;
98  $links[SQ_LINK_TYPE_3] = $allowed_link;
99  $links[SQ_LINK_NOTICE] = $allowed_link;
100 
101  return $links;
102 
103  }//end _getAllowedLinks()
104 
105 
112  public function &getResultSet()
113  {
114  $hash = $this->getHashKey();
115 
116  $result = $this->getCachedResults($hash);
117  if (empty($result)) {
118  try {
119  // Not cached at all, so lets send a request
120  $res = Array();
121  $connection = $this->getConnection();
122  $object_list = '';
123  if (!empty($connection['wsdl'])) {
124  $object_list = $this->getTRIMRecords($connection);
125 
126  // Only download files if we are asked to
127  if ($this->attr('download_files')) {
128  foreach ($object_list as &$record_info) {
129  $this->storeDocumentList($connection, $record_info);
130  }//end foreach
131  }//end if
132  unset($record_info);
133  }//end if
134 
135  if (!isset($res[0]['error'])) {
136  $result = $object_list;
137  if (!empty($result)) {
138  $this->cacheResult($result, $hash);
139  }//end if
140  } else if (isset($res[0]['FoundCount']) && $res[0]['FoundCount'] != 0) {
141  // We got some result, but there is error, lets throw an error.
142  }//end else if
143  } catch (Exception $sf) {
144  //trigger_error($res['error'], E_USER_WARNING);
145  }//end try catch
146  }//end else
147 
148  return $result;
149 
150  }//end getResultSet()
151 
152 
153  public function getCachedResults($hash_key)
154  {
155  $result = $this->attr('cached_result');
156  if (isset($result[$hash_key])) {
157  return $result[$hash_key];
158  }//end if
159 
160  return Array();
161 
162  }//end cacheResult()
163 
164 
165  public function cacheResult($result, $hash_key)
166  {
167  $cached_result = $this->attr('cached_result');
168  $cached_result[$hash_key] = $result;
169 
170  $GLOBALS['SQ_SYSTEM']->am->acquireLock($this->id, 'attributes');
171  if ($this->setAttrValue('cached_result', $cached_result) && $this->saveAttributes()) {
172  return TRUE;
173  }//end if
174  $GLOBALS['SQ_SYSTEM']->am->releaseLock($this->id, 'attributes');
175 
176  return FALSE;
177 
178  }//end cacheResult()
179 
180 
187  public function updateCachedResult($forced=FALSE)
188  {
189  $hash = $this->getHashKey();
190 
191  // Check the cache
192  $result = $this->getCachedResults($hash);
193  if (!empty($result)) {
194  $ordered_result = Array(); // A new result array with the new order if the order has been changed.
195 
196  // Now we have cache. Lets get the records
197  $connection = $this->getConnection();
198  if (!empty($connection['wsdl'])) {
199  $new_object_list = $this->getTRIMRecords($connection);
200  }//end if
201 
202  $updated = FALSE;
203 
204  $result_uris = $this->resultUris($result);
205  $new_result_uris = $this->resultUris($new_object_list);
206 
207  // Delete, Update, Integrity, New
208 
209  // Delete
210 
211  $uris_to_delete = array_diff($result_uris, $new_result_uris);
212  foreach ($result as $index => $record_info) {
213  if (isset($record_info['Uri']) && in_array($record_info['Uri'], $uris_to_delete)) {
214  // Unlink file first
215  $dir_path = $this->data_path.'/'.$record_info['Uri'];
216  $files_stored = glob($dir_path.'/*');
217  foreach ($files_stored as $file_name) {
218  unlink($file_name);
219  }//end foreach
220 
221  // Unlink the directory
222  if (is_dir($dir_path)) {
223  rmdir($dir_path);
224  }//end if
225 
226  // Remove it from the cache
227  unset($result[$index]);
228  $updated = TRUE;
229  }//end if
230  }//end foreach
231  // We have something to delete
232 
233 
234  // Update & Integrity
235  foreach ($result as $index => $record_info) {
236  foreach ($new_object_list as $new_index => $new_record_info) {
237  // Comparing the same record based on the URI
238  if ($record_info['Uri'] == $new_record_info['Uri']) {
239  // If Forced, dont even care about version number, update anyway.
240  if ($record_info['Version'] !== $new_record_info['Version'] || $forced) {
241  // UPDATE Check
242  if ($this->attr('download_files')) {
243  $this->storeDocumentList($connection, $new_record_info);
244  }//end if
245  $ordered_result[$new_index] = $new_record_info;
246  } else {
247  // If this is the same version
248  $ordered_result[$new_index] = $new_record_info;
249 
250  // INTEGRITY Check
251  if (isset($new_record_info['recDocumentType']) && $new_record_info['recDocumentType'] != 'Record has no document attached.') {
252  // We have a file here, have to check whether it is still in the system
253  $final_file_path = $this->data_path.'/'.$new_record_info['Uri'];
254  $files_stored = glob($final_file_path.'/*');
255  // If there is no file in there
256  if (empty($files_stored)) {
257 
258  $this->storeDocumentList($connection, $new_record_info);
259  } else if (!isset($record_info['download_url'])) {
260 
261  $ordered_result[$new_index]['document_url'] = $this->getURL().'?Uri='.$new_record_info['Uri'];
262  }//end else if
263  }//end if
264 
265  }//end else
266  $updated = TRUE;
267  }//end if
268  }//end foreach
269  }//end foreach
270 
271  $ordered_result_uris = $this->resultUris($result);
272 
273  // New
274  if (count($new_object_list) > count($ordered_result)) {
275  $uris_to_add = array_diff($new_result_uris, $ordered_result_uris);
276  foreach ($new_object_list as $index => $new_record_info) {
277  if (in_array($new_record_info['Uri'], $uris_to_add)) {
278  // We are taking it out again so we can modify it by reference
279  if ($this->attr('download_files')) {
280  $this->storeDocumentList($connection, $new_record_info);
281  }//end if
282  $ordered_result[$index] = $new_record_info;
283  $updated = TRUE;
284  }//end if
285  }//end foreach
286  }//end if
287 
288  // We would have to sort the keys of the array first so array_values would not sort by pointer instead of index magnitude
289  ksort($ordered_result);
290 
291  // Since we would have holes in our array keys as some entries is deleted, we need to reset the keys back to 0 onward.
292  // Data source expect the key values to be correctly sorted.
293  $result = array_values($ordered_result);
294  if ($updated) {
295  if (!empty($result)) {
296  $this->cacheResult($result, $hash);
297  return TRUE;
298  }//end if
299  }//end if
300  return FALSE;
301  } else {
302  $this->getResultSet();
303  return TRUE;
304  }//end else
305 
306  }//end updateCachedResult()
307 
308 
312  public function resultUris($result)
313  {
314  $new_result = Array();
315  foreach ($result as $index => $record_info) {
316  $new_result[$record_info['Uri']] = $record_info;
317  }//end foreach
318 
319  return array_keys($new_result);
320 
321  }//end convertResultToAssoc
322 
323 
330  public function getAttachedFile($uri)
331  {
332  require_once SQ_FUDGE_PATH.'/standards_lists/mime_types.inc';
333 
334  $GLOBALS['SQ_SYSTEM']->setGlobalDefine('SQ_REPLACE_MYSOURCE_LEVEL_KEYWORDS', FALSE);
335 
336  $dir_path = $this->data_path.'/'.$uri;
337  $path_parts = Array();
338  if (file_exists($dir_path)) {
339  if(defined("RecursiveDirectoryIterator::SKIP_DOTS"))
340  {
341  $dir = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($dir_path, RecursiveDirectoryIterator::SKIP_DOTS));
342  }
343  else {
344  $dir = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($dir_path));
345  }
346 
347  if (empty($dir)) return FALSE;
348  $pre_mtime = 0;
349  foreach ($dir as $file) {
350  $mtime = $file->getMTime();
351  if($mtime > $pre_mtime) {
352  $file_path = $file->getPathname();
353  $path_parts = pathinfo($file_path);
354  break;
355  }
356  }//end foreach
357  } else {
358  return FALSE;
359  }//end else
360 
361  if (empty($path_parts)) {
362  return FALSE;
363  }//end if
364 
365  $ext = strtolower($path_parts['extension']);
366  $type = (empty($standards_lists_mime_types[$ext])) ? 'text/plain' : $standards_lists_mime_types[$ext];
367 
368  // Fix for IE caching
369  header("Pragma: public");
370  header("Expires: 0");
371  header("Cache-Control: must-revalidate, post-check=0, pre-check=0");
372  header("Cache-Control: private",false);
373 
374  // We'll be outputting a file
375  header('Content-Type: '.$type);
376 
377  // Set the name of the file
378  header('Content-Disposition: attachment; filename="'.$path_parts['basename'].'";');
379  header('Content-Length: '.filesize($file_path));
380 
381  // Get the source file
382  readfile($file_path);
383 
384  return TRUE;
385  @ob_flush();
386 
387  }//end getAttachment()
388 
389 
396  public function getTRIMRecords($connection)
397  {
398 
399  $containers = Array();
400 
401  $string_search_clause = $this->getDynamicVariableValue('search_clauses');
402  $parent_container_record_number = $this->getDynamicVariableValue('search_parent_container');
403  $classification_title = $this->attr('classification');
404  $classification_include_sub = $this->attr('classification_sub');
405 
406  // Fetch information
407  $record_properties = $this->getDynamicVariableValue('result_fields');
408  $search_limit = $this->getDynamicVariableValue('limit');
409 
410  if(array_key_exists('recContainerTitle', $record_properties) && !array_key_exists('recContainer', $record_properties)) {
411  $record_properties['recContainer'] = 'Container';
412  }
413 
414  // Get classification and sub-classification structure
415  $classifications = Array();
416  if(!empty($classification_title)) {
417  $classification_uris = TRIM_Common::getURIsFromClassification($connection, trim($classification_title));
418 
419  foreach ($classification_uris as $classification) {
420  // filter out inrelevent classifications
421  if($classification_include_sub) {
422  if (!preg_match ('/^'.$classification_title.'( - )?/',$classification['plnTitle'])) continue;
423  }
424  else {
425  if ($classification['plnTitle'] != $classification_title) continue;
426  }
427  $classifications[$classification['Uri']] = $classification['plnTitle'];
428  }
429  // make sure classification is in the returned results
430  $record_properties['recClassification'] = 'Classification';
431  }
432 
433  // Search clauses will be directly inserted to xml request
434  // Because TRIM convertToXml will mess up the order
435  $search_clauses_xml = TRIM_Common::constructRecordSearchClauseGroupedXml($string_search_clause, $classifications);
436 
437  $search_clauses = Array();
438  if (!empty($parent_container_record_number)) {
439  $parent_container_uri = TRIM_Common::getURIFromRecordNumber($connection, $parent_container_record_number);
440  $search_clauses['RecordContainerAltClause'] = TRIM_Common::constructRecordContainerAltClause($parent_container_uri);
441  }//end if
442 
443  $record_search_options = $this->getRecordSearchOptions();
444 
445  $operations = Array (
446  'Fetch' => TRIM_Common::constructFetch($record_properties, $search_limit),
447  'RecordSearch' => TRIM_Common::constructRecordSearch($search_clauses, $record_search_options),
448  );
449 
450  $file_path = NULL;
451 
452  $object_list = TRIM_Common::executeRequest($connection, $operations, 'Fetch', $search_clauses_xml);
453 
454  // inserting classification grouping keywords
455  if(!empty($classification_title)) {
456  foreach ($object_list as $index => $record_info) {
457  if (!isset($classifications[$record_info['recClassification']])) continue;
458  $record_classification = $classifications[$record_info['recClassification']];
459  $object_list[$index]['classification_title'] = $record_classification;
460  $object_list[$index]['classification_title_1'] = $classification_title;
461 
462  if ($record_classification !== $classification_title) {
463  $record_classification = preg_replace('/^'.$classification_title.' - /', '', $record_classification, 1);
464  $record_classification_level = explode (' - ', $record_classification);
465  $i = 2;
466  foreach ($record_classification_level as $level_title) {
467  $object_list[$index]['classification_title_'.$i] = $level_title;
468  $i++;
469  }
470  }
471  }
472  }
473 
474  $record_type_uris = Array();
475  foreach ($object_list as $index => $record_info) {
476  foreach ($record_info as $key => $value) {
477  // Convert GMT Datetime to Local Time
478  if($this->attr('convert_timezone') && preg_match('/ GMT$/', $value)) {
479  $local_datetime = date('D, d M Y H:i:s', strtotime($value));
480  $object_list[$index][$key] = empty($local_datetime) ? $value : $local_datetime;
481  }
482 
483  // Make sure the field name is matrix keyword friendly
484  if(preg_match('/[^a-zA-Z0-9_-]/', $key)) {
485  $new_key = preg_replace('/[^a-zA-Z0-9_-]+/', '', $key);
486  $new_value = $object_list[$index][$key];
487  unset($object_list[$index][$key]);
488  $object_list[$index][$new_key] = $new_value;
489  }
490 
491  // Prapare to convert Record Type uri field to readable Record Type name
492  if($key === 'recRecordType') {
493  $record_type_uris[] = $value;
494  }
495  }
496  }
497 
498  // Convert Record Type from uri to name
499  if(!empty($record_type_uris)) {
500  //if we dont already know all record types, we have to send extra queries to get their names
501  $retrieved_info = $this->attr('retrieved_fields');
502  if(isset($retrieved_info['record_types'])) {
503  $record_names_data = $retrieved_info['record_types'];
504  }
505  else {
506  $record_names_data = TRIM_Common::getRecordTypeNamesFromUris($connection, $record_type_uris);
507  }
508 
509  foreach ($object_list as $index => $record_info) {
510  foreach ($record_info as $key => $value) {
511  if($key === 'recRecordType') {
512  $new_value = isset($record_names_data[$value]) ? $record_names_data[$value] : $value;
513  $object_list[$index][$key] = $new_value;
514  }
515  }
516  }
517  }
518 
519  if(array_key_exists('recContainerTitle', $record_properties)) {
520  $record_properties = Array('recTitle' => 1 );
521  foreach ($object_list as $index => $record_info) {
522  if($record_info['recContainer']!='') {
523  if(!array_key_exists($record_info['recContainer'], $containers)) {
524  $results = TRIM_Common::getRecordPropertiesFromUri($connection, $record_info['recContainer'], $record_properties);
525  foreach($results as $r) {
526  $containers[$record_info['recContainer']] = $r['recTitle'];
527  }
528  }
529  $object_list[$index]['recContainerTitle'] = $containers[$record_info['recContainer']];
530  } else {
531  $object_list[$index]['recContainerTitle'] = '';
532  }
533  }
534  }
535 
536  return $object_list;
537 
538  }//end getTRIMRecords();
539 
540 
547  function getHashKey() {
548 
549  // Hash Key was used before when this asset uses the Cache Manager to manage its cache
550  // Since attribute is used now, it's hard to go back and clear the cache for different configuration
551  // so lets just use one cache set instead of multiple sets like before
552  /*
553  $search_kw = $this->getDynamicVariableValue('search_keyword');
554  $string_search_type = $this->getDynamicVariableValue('string_search_type');
555  $parent_container_record_number = $this->getDynamicVariableValue('search_parent_container');
556 
557  $unhashed_key = $search_kw
558  .$parent_container_record_number
559  .$this->getDynamicVariableValue('limit')
560  .$string_search_type
561  .implode('-',$this->getDynamicVariableValue('fields'))
562  .$this->getDynamicVariableValue('fileTypes');
563 
564  $hash = md5($unhashed_key);*/
565  $hash = md5('resultSet');
566 
567  return $hash;
568 
569  }//end getHashKey()
570 
571 
578  function getConnection()
579  {
580  $connector_link = $GLOBALS['SQ_SYSTEM']->am->getLink($this->id, SQ_LINK_NOTICE, 'trim_connector', FALSE, 'trim_connector');
581  if (!empty($connector_link)) {
582  $connector = $GLOBALS['SQ_SYSTEM']->am->getAsset($connector_link['minorid']);
583  } else {
584  $connector = $this;
585  }//end else
586 
587  $connection = Array();
588  $connection['wsdl'] = $connector->attr('wsdl');
589  $connection['authentication'] = Array (
590  'login' => $connector->attr('username'),
591  'password' => $connector->attr('password'),
592  'trace' => TRUE,
593  'exceptions' => TRUE,
594  );
595  // add proxy
596  if(method_exists($connector, 'getProxy')) {
597  $proxy = $connector->getProxy();
598  $connection['authentication'] = array_merge($connection['authentication'], $proxy);
599  }
600 
601  return $connection;
602 
603  }//end getConnection()
604 
605 
613  {
614  $record_search_options = Array();
615  $record_search_options['limit'] = $this->getDynamicVariableValue('limit');
616  $record_search_options['file_types'] = $this->getDynamicVariableValue('fileTypes');
617  $record_search_options['sort_1'] = $this->getDynamicVariableValue('search_sort_1');
618  $record_search_options['sort_2'] = $this->getDynamicVariableValue('search_sort_2');
619  $record_search_options['sort_3'] = $this->getDynamicVariableValue('search_sort_3');
620  $record_search_options['sort_1_descending'] = $this->getDynamicVariableValue('sort_1_descending');
621  $record_search_options['sort_2_descending'] = $this->getDynamicVariableValue('sort_2_descending');
622  $record_search_options['sort_3_descending'] = $this->getDynamicVariableValue('sort_3_descending');
623  $record_search_options['record_type_filter'] = is_array($this->getDynamicVariableValue('record_type_filter')) ? array_keys ($this->getDynamicVariableValue('record_type_filter')) : '';
624 
625  return $record_search_options;
626 
627  }//end getRecordSearchOptions()
628 
629 
636  function storeDocumentList($connection, &$record_info)
637  {
638 
639  if (isset($record_info['Uri']) && $record_info['Uri'] != 0 && (!isset($record_info['error']))) {
640  $record_info['document_url'] = '';
641 
642  if (isset($record_info['recDocumentType']) && $record_info['recDocumentType'] != 'Record has no document attached.') {
643  // We got a file here.
644  $operations = Array (
645  'Download' => TRIM_Common::constructDownload($this->attr('download_limit')),
646  'ShortcutRecordUri' => TRIM_Common::constructShortcutRecordUri($record_info['Uri']),
647  );
648 
649  $hash_key = $GLOBALS['SQ_SYSTEM']->user->attr('username').time();
650  $final_file_path = $this->data_path.'/'.$record_info['Uri'];
651  require_once SQ_FUDGE_PATH.'/general/file_system.inc';
652  create_directory($final_file_path);
653 
654  $res = TRIM_Common::executeRequest($connection, $operations, 'Download', '', $hash_key, $final_file_path);
655 
656  $record_info['document_url'] = $this->getURL().'?Uri='.$record_info['Uri'];
657  }//end if
658  }//end if
659 
660  }//end storeDocumentList()
661 
662 
671  public function getDynamicVariableValue($variable_name)
672  {
673  $dynamic_vars = $this->attr('dynamic_vars');
674  if (!isset($dynamic_vars[$variable_name])) return '';
675 
676  $parameter_map = $this->getAttribute('parameter_map');
677  $value = $parameter_map->getParameterValue($variable_name);
678 
679  if (empty($value)) {
680  $value = array_get_index($dynamic_vars, $variable_name, '');
681  }//end if
682 
683  return $value;
684 
685  }//end getDynamicVariableValue()
686 
687 
688 
689 
696  public function printFrontend()
697  {
698 
699  if ($this->readAccess()) {
700  $connection = $this->getConnection();
701  if (isset($_GET['Uri']) && !empty($_GET['Uri'])) {
702  $download_result = $this->getAttachedFile(($_GET['Uri']));
703  if (!$download_result) {
704  trigger_error('Unable to retrieve file', E_USER_WARNING);
705  }//end if
706  } else if (isset($_GET['check_update']) && !empty($_GET['check_update'])) {
707  if ($this->adminAccess()) {
708  echo 'var numUpdate = false;';
709  $new_object_list = $this->getTRIMRecords($connection);
710 
711  $hash = $this->getHashKey();
712  $result = $this->getCachedResults($hash);
713 
714  if (!empty($result)) {
715  // We have some cache. Lets check them one by one.
716  $i = 0;
717  foreach ($result as $index => $record_info) {
718  foreach ($new_object_list as $new_index => $new_record_info) {
719  // Comparing the same record based on the URI
720  if ($record_info['Uri'] == $new_record_info['Uri']) {
721  if ($record_info['Version'] !== $new_record_info['Version']) {
722  $i++;
723  }//end if
724  }//end if
725  }//end foreach
726  }//end foreach
727 
728  // If we have records to add or delete, have to account for them as well
729  $final_count = $i+abs(count($result) - count($new_object_list));
730  echo 'var numUpdate = '.$final_count.';';
731  } else {
732  // We have no cache. Just return the count in object_list
733  echo 'var numUpdate = '.count($new_object_list).';';
734  }//end else
735 
736  }//end if
737  } else if (isset($_GET['synch_now']) && !empty($_GET['synch_now'])) {
738  if ($this->adminAccess()) {
739  if ($this->updateCachedResult()) {
740  echo '1';
741  } else {
742  echo '0';
743  }//end if
744  }//end if
745  }//end else if
746  }//end if
747  }//end printFrontend()
748 
749 
763  public function setAttrValue($name, $value)
764  {
765  if ($name == 'download_files') {
766  $res_val = parent::setAttrValue($name, $value);
767  $this->updateCachedResult(TRUE);
768  return $res_val;
769  } else {
770  return parent::setAttrValue($name, $value);
771  }//end if
772  }//end setAttrValue()
773 
774 
789  public function getAsset($assetid, $type_code='', $mute_errors=FALSE)
790  {
791  $asset = parent::getAsset($assetid, $type_code='', $mute_errors=FALSE);
792  if (isset($_REQUEST['a']) && isset($_REQUEST['a']) == $assetid) {
793  // Now we are looking for shadow assets to download
794  if (!is_null($asset)) {
795  if (isset($asset->vars['Uri']) && !empty($asset->vars['Uri'])) {
796  if ($this->getAttachedFile(($asset->vars['Uri']))) {
797  exit();
798  }
799  }//end if
800  }//end if
801  }//end if
802 
803  return $asset;
804  }//end getAsset()
805 
806 
815  public function getRetrievedFields($type = 'all')
816  {
817  $fields = $this->attr('retrieved_fields');
818  if(empty($fields)) return Array();
819 
820  if ($type == 'additional') {
821  return $fields['additional_fields'];
822  }
823  else if ($type == 'standard') {
824  return $fields['standard_fields'];
825  }
826  else {
827  return (array_merge($fields['standard_fields'], $fields['additional_fields']));
828  }
829  }
830 
839  public function getRetrievedFieldType($field)
840  {
841  $fields = $this->attr('retrieved_fields');
842  if(empty($fields) || !isset($fields['field_types'])) return '';
843  $field_types = $fields['field_types'];
844  return (isset($field_types[$field]) ? $field_types[$field] : '');
845  }
846 
847 }//end class
848 ?>