Squiz Matrix  4.12.2
 All Data Structures Namespaces Functions Variables Pages
paint_layout_bodycopy.inc
1 <?php
17 require_once SQ_CORE_PACKAGE_PATH.'/bodycopy/bodycopy/bodycopy.inc';
18 require_once 'include/conditions_list.inc';
19 require_once SQ_FUDGE_PATH.'/general/file_system.inc';
20 
50 {
51 
52  var $asset_to_paint = NULL;
53 
54  var $conditions_list = NULL;
55 
56  var $keyword_replacements = Array();
57 
58 
65  function __construct($assetid=0)
66  {
67  $this->_ser_attrs = TRUE;
68  parent::__construct($assetid);
69 
70  }//end constructor
71 
72 
79  public function _updated()
80  {
81  // Use bodycopy's save functionality to store any notice links our containers have,
82  // and to store the original content before any substitutions take place
83  if (!parent::_updated()) return FALSE;
84 
85  $this->_generateContentFile();
86 
87  return TRUE;
88 
89  }//end _updated()
90 
91 
98  protected function _generateContentFile()
99  {
100  require_once SQ_FUDGE_PATH.'/general/text.inc';
101  $php_begin = '<'.'?'.'php ';
102  $php_end = ' ?'.'>';
103  $content_file = '';
104  $required_substitution_keywords = Array();
105  $required_substitution_asset_keywords = Array();
106 
107  $containers = $this->getContainers();
108  foreach (array_keys($containers) as $i) {
109  ob_start();
110  $container =& $containers[$i]; // need this by reference
111  $edit = $container->getEditFns();
112  $edit->paint($container, FALSE, TRUE);
113  $content = ob_get_contents();
114  ob_end_clean();
115 
116  $required_keywords = retrieve_keywords_replacements($content);
117  $keyword_replacements = Array();
118  $additional_keywords = Array();
119 
120  // find all the required keywords and replace the condition-block keywords by PHP code
121  foreach ($required_keywords as $keyword) {
122  if (!isset($keyword_replacements[$keyword])) {
123  $value = NULL;
124 
125  if (preg_match('/^('.SQ_KEYWORD_CONDITION_BEGIN.'|'.SQ_KEYWORD_CONDITION_END.'|'.SQ_KEYWORD_CONDITION_ELSE.')_(.*)$/', $keyword, $condition_parts)) {
126  if (count($condition_parts) == 3) {
127  $test_keyword = $condition_parts[2];
128  switch ($condition_parts[1]) {
129  case SQ_KEYWORD_CONDITION_BEGIN :
130  $this->_addRequiredKeywordsFromEvaluatedKeyword($test_keyword, $required_substitution_keywords);
131  $value = 'if (!empty($paint_layout_keywords[\''.$test_keyword.'\']) && trim($paint_layout_keywords[\''.$test_keyword.'\']) != \'\') {';
132  break;
133  case SQ_KEYWORD_CONDITION_ELSE :
134  $value = '} else {';
135  break;
136  case SQ_KEYWORD_CONDITION_END :
137  $value = '} // end '.$test_keyword;
138  break;
139  }
140 
141  if (!empty($value)) {
142  $value = $php_begin.$value.$php_end;
143  }
144  }
145  }
146 
147  if (isset($value)) {
148  $keyword_replacements[$keyword] = $value;
149  } else {
150  $required_substitution_asset_keywords[$keyword] = 1;
151  }
152  }
153  }//end foreach
154 
155  // Replace all the conditional keywords in our content with valid PHP code
156  replace_keywords($content, $keyword_replacements);
157 
158  // Change each ./?a= url to reference the sq_asset_url_list array, which
159  // is built from our container's notice links when content is printed.
160  $e = '|\./\?a=([0-9:]+)([^0-9])|';
161  $with = '<'.'?php echo ((strpos("\\1", ":") !== FALSE) ? "./?a=\\1" : $sq_asset_url_list["\\1"]); ?'.'>\\2';
162  $content = preg_replace($e, $with, $content);
163 
164  $content_file .= '
165  $container = $GLOBALS["SQ_SYSTEM"]->am->getAsset('.$container->id.', "'.$container->type().'");
166  if ($container->readAccess()) {
167  '.$php_end.$content.$php_begin.'
168  }//end if read access for container '.$container->id.'
169  ';
170 
171  }//end foreach container
172 
173  $content_file = $php_begin.$content_file.$php_end;
174 
175  // Flatten line endings to a common one, as the sections of content file
176  // generated by Matrix and that by the database may have different
177  $content_file = str_replace("\r\n","\n", $content_file);
178  $content_file = str_replace("\r","\n", $content_file);
179 
180  // ...but that ending should really be \r\n; when sent to a browser,
181  // text/html MIME-type requires \r\n line endings
182  $content_file = str_replace("\n","\r\n", $content_file);
183 
184  // save the contents of the bodycopy
185  if (!is_dir($this->data_path)) {
186  create_directory($this->data_path);
187  }
188 
189  $contextid = (int)$GLOBALS['SQ_SYSTEM']->getContextId();
190  $file_name = 'content_file'.(($contextid === 0) ? '' : ('.'.$contextid)).'.php';
191  $keyword_name = 'keywords'.(($contextid === 0) ? '' : ('.'.$contextid));
192 
193  if (!string_to_file($content_file, $this->data_path.'/'.$file_name)) {
194  trigger_localised_error('CORE0047', E_USER_WARNING, $this->name);
195  return FALSE;
196  }
197 
198  // Save the substitution keywords we will need to lookup for each asset display
199  create_directory($this->data_path);
200  if (!string_to_file(serialize(array_merge($required_substitution_keywords, $required_substitution_asset_keywords)), $this->data_path.'/keywords')) {
201  trigger_localised_error('CORE0048', E_USER_WARNING, $this->name);
202  return FALSE;
203  }
204 
205  if (!string_to_file(serialize($required_substitution_keywords), $this->data_path.'/conditional_keywords_to_eval')) {
206  trigger_localised_error('CORE0048', E_USER_WARNING, $this->name);
207  return FALSE;
208  }
209 
210  }//end _generateContentFile()
211 
212 
221  public function paintAsset(Asset $asset)
222  {
223  /*
224  * Possible keywords:
225  *
226  * SUBSTITUTION_KEYWORDS:
227  *
228  * 1. any asset keywords
229  * 2. %asset_content%
230  *
231  * CONDITIONAL KEYWORDS:
232  *
233  * 3. %begin_SUBSTITUTION_KEYWORD% ... %end_SUBSTITUTION_KEYWORD%
234  *
235  */
236  // start performance mode timer
237  $GLOBALS['SQ_SYSTEM']->pm->startTimer($this);
238  $ret = '';
239 
240  $this->asset_to_paint = $asset;
241 
242  $contextid = (int)$GLOBALS['SQ_SYSTEM']->getContextId();
243  $context_suffix = ($contextid === 0) ? '' : ('.'.$contextid);
244  $content_file_name = 'content_file'.$context_suffix.'.php';
245  $default_content_file_name = 'content_file.php';
246  $content_path = $this->data_path.'/'.$content_file_name;
247  if (file_exists($content_path) === FALSE) {
248  $content_path = $this->data_path.'/'.$default_content_file_name;
249  }
250 
251  // Retrieve any assets referenced in this bodycopy, and get their urls for lookup
252  if (file_exists($this->data_path.'/.notice_links')) {
253  $linked_assets = unserialize(file_to_string($this->data_path.'/.notice_links'));
254  } else {
255  // nothing cached out from the Bodycopy asset level (ie. not in safe edit) so
256  // need to grab our notice links ourselves
257  $linked_assets = Array();
258  $containers = $this->getContainers();
259 
260  foreach ($containers as $container) {
261  $links = $GLOBALS['SQ_SYSTEM']->am->getLinks($container->id, SQ_LINK_NOTICE);
262  foreach ($links as $link) {
263  $linked_assets[] = $link['minorid'];
264  }
265  }
266  $linked_assets = array_unique($linked_assets);
267  }
268  $sq_asset_url_list = $GLOBALS['SQ_SYSTEM']->am->getAssetHref($linked_assets);
269 
270  // Find stored keyword replacements
271  $paint_layout_keywords = Array();
272  if (file_exists($this->data_path.'/conditional_keywords_to_eval')) {
273  $required_keywords = array_keys(unserialize(file_to_string($this->data_path.'/conditional_keywords_to_eval')));
274  $paint_layout_keywords = $this->_getAssetKeywordReplacements($asset, $required_keywords);
275  }
276 
277  // Read in content file, find keyword replacements, spit out the results
278  $content = '';
279  if (file_exists($content_path)) {
280  ob_start();
281  include($content_path);
282  $content = ob_get_contents();
283  $keywords_in_condition = extract_keywords($content);
284  $paint_layout_keywords = array_merge($paint_layout_keywords, $this->_getAssetKeywordReplacements($asset, $keywords_in_condition));
285  replace_keywords($content, $paint_layout_keywords);
286  ob_end_clean();
287  } else {
288  $this->setKeywordReplacements($this->_getAssetKeywordReplacements($asset, $this->getKeywords()));
289  ob_start();
290  $this->printBody();
291  $content = ob_get_contents();
292  ob_end_clean();
293  }
294  // end performance mode timer
295  $GLOBALS['SQ_SYSTEM']->pm->stopTimer($this);
296 
297  return $content;
298 
299  }//end paintAsset()
300 
301 
312  protected function _addRequiredKeywordsFromEvaluatedKeyword($evaluated_keyword, Array &$required_keywords)
313  {
314  // if the evaluated keyword is a logical condition, then gets the logical keywords it is relying on
315  $condition_list = new Conditions_List($this, 'conditional_keywords');
316  foreach ($condition_list->getRequiredKeywords($evaluated_keyword) as $required_keyword) {
317  $required_keywords[$required_keyword] = 1;
318  }
319 
320  // add at least the keyword that will be evaluated
321  $required_keywords[$evaluated_keyword] = 1;
322 
323  }//end _addRequiredKeywordsFromEvaluatedKeyword()
324 
325 
335  protected function _evaluateKeyword($keyword_name)
336  {
337  if (!isset($this->keyword_replacements[$keyword_name])) {
338  return FALSE;
339  }
340 
341  $value = trim($this->keyword_replacements[$keyword_name]);
342 
343  return ($value != '');
344 
345  }//end _evaluateKeyword()
346 
347 
356  protected function _getKeywordValue($keyword)
357  {
358  // TODO: must optimise getAssetKeywordReplacements() with a cache
359  $ret = $this->_getAssetKeywordReplacements($this->asset_to_paint, Array($keyword));
360 
361  $ret = isset($ret[$keyword]) ? $ret[$keyword] : '';
362 
363  return $ret;
364 
365  }//end _getKeywordValue()
366 
367 
378  protected function &_getAssetKeywordReplacements(Asset &$asset, Array $required_keywords)
379  {
380  $ret = Array();
381 
382  foreach ($required_keywords as $required_keyword) {
383  $full_keyword = $required_keyword;
384  $required_keyword = parse_keyword($required_keyword, $modifiers);
385  $context_array = extract_context_modifier($modifiers, 'both');
386  $contextid = $context_array['id'];
387 
388  if ($contextid !== NULL) {
389  // Save the required keyword with the context name
390  $required_keyword .= '^context:'.$context_array['name'];
391  $GLOBALS['SQ_SYSTEM']->changeContext($contextid);
392  $contexted_asset = $GLOBALS['SQ_SYSTEM']->am->getAsset($asset->id);
393  } else {
394  $contexted_asset = $asset;
395  }
396 
397  // 1. asset content
398  if ($required_keyword == 'asset_contents') {
399  if (!isset($ret['asset_contents'])) {
400  ob_start();
401  $contexted_asset->printBody();
402  $ret['asset_contents'] = ob_get_contents();
403  ob_end_clean();
404  }
405  } else if (substr($required_keyword, 0, 21) == 'asset_contents_paint_') {
406  $paint_layout_name = substr($required_keyword, 21);
407 
408  // If a paint layout name has been specified, change that to an id
409  if (assert_valid_assetid($paint_layout_name, '', TRUE, FALSE)) {
410  $paint_layout_id = $paint_layout_name;
411  } else {
412  $paint_layout_id = $GLOBALS['SQ_SYSTEM']->am->getValueFromURL(preg_replace('/^[^:]*:\/\//', '', $asset->getURL()), 'paint_layout::user::'.$paint_layout_name);
413  }
414 
415  if (assert_valid_assetid($paint_layout_id, 'Invalid paint layout specified in bodycopy #' . $this->id . ': ' . $paint_layout_name, FALSE, FALSE)) {
416  $paint_layout = $GLOBALS['SQ_SYSTEM']->am->getAsset($paint_layout_id, 'paint_layout_page');
417  if (!empty($paint_layout)) {
418  // A safeguard to mitigate users from easily creating a loop: check that the
419  // paint layout we're painting with is not the current one. If it is, just print
420  // the contents without painting again.
421  $type_formats = $paint_layout->getFormats();
422  if (!isset($type_formats[$this->id])) {
423  ob_start();
424  $contexted_asset->printBodyWithPaintLayout($paint_layout_id);
425  $ret[$required_keyword] = ob_get_contents();
426  ob_end_clean();
427  } else {
428  ob_start();
429  $contexted_asset->printBody();
430  $ret[$required_keyword] = ob_get_contents();
431  ob_end_clean();
432  }
433  }
434  }
435  } else {
436  $ret[$required_keyword] = $contexted_asset->getKeywordReplacement($required_keyword);
437  }//end else
438 
439  // If we have keyword modifiers AND
440  // the keyword is not starting with 'globals_' which will be taken care at the end of execution of start() in mysource.ini
441  if (($full_keyword != $required_keyword) && (0 !== strpos($required_keyword, 'globals_'))) {
442  // Start with the plain keyword without modifier
443  $ret[$full_keyword] = $ret[$required_keyword];
444  apply_keyword_modifiers($ret[$full_keyword], $modifiers, Array('assetid' => $contexted_asset->id));
445  }
446 
447  if ($contextid !== NULL) {
448  $GLOBALS['SQ_SYSTEM']->am->forgetAsset($contexted_asset);
449  $GLOBALS['SQ_SYSTEM']->restoreContext();
450  }
451 
452  unset($contexted_asset);
453 
454  }//end foreach
455 
456  // asset lineage
457  if (in_array('asset_lineage', $required_keywords) || in_array('asset_lineage_linked', $required_keywords)) {
458 
459  preg_match('|^([^:]*)://(.*)|', $asset->getURL(), $matches);
460  $url = !empty($matches[1]) ? $matches[1] : NULL;
461  $protocol = !empty($matches[2]) ? $matches[2] : NULL;
462  $asset_lineage = $GLOBALS['SQ_SYSTEM']->am->getLineageFromURL($url, $protocol);
463 
464  $ret['asset_lineage'] = '';
465  $ret['asset_lineage_linked'] = '';
466  $lineage_separator = ' > ';
467  $lineage_separator = $this->attr('lineage_separator');
468 
469  foreach ($asset_lineage as $asset_lineage_item) {
470  if (!empty($ret['asset_lineage'])) {
471  $ret['asset_lineage'] .= $lineage_separator;
472  $ret['asset_lineage_linked'] .= $lineage_separator;
473  }
474  $ret['asset_lineage'] .= $asset_lineage_item['short_name'];
475  $ret['asset_lineage_linked'].='<a href="'.$asset_lineage_item['protocol'].'://'.$asset_lineage_item['url'].'">'.$asset_lineage_item['short_name'].'</a>';
476  }
477  }
478 
479  // 3. Conditions
480  // TODO:
481  // This will make this harder once the $required_keywords will be really applied by getAssetKeywords()
482  // function, because the logical conditions may need other keywords which are not in $required_keywords
483  $condition_list = new Conditions_List($this, 'conditional_keywords');
484  $ret = array_merge($ret, $condition_list->evaluate($asset, $required_keywords, $ret, Array(FALSE, TRUE)));
485  return $ret;
486 
487  }//end _getAssetKeywordReplacements()
488 
489 
498  public function setAssociatedAssetType($asset_type='')
499  {
500  $this->setAttrValue('associated_asset_type', $asset_type);
501 
502  }//end setAssociatedAssetType()
503 
504 
511  public function getAssociatedAssetType()
512  {
513  return $this->attr('associated_asset_type');
514 
515  }//end getAssociatedAssetType()
516 
517 
527  public function getKeywordsDescription(Array &$keywords, $asset_type_code='')
528  {
529  if (is_array($keywords)) {
530 
531  // 1. asset content
532  $keywords['asset_contents'] = translate('asset_contents');
533 
534  // 2. asset keywords (includes attributes)
535  if (!empty($asset_type_code)) {
536  $GLOBALS['SQ_SYSTEM']->am->includeAsset($asset_type_code);
537  $asset = new $asset_type_code();
538  } else {
539  $asset = new Asset();
540  }
541 
542  $asset_keywords = $asset->getAvailableKeywords();
543  foreach ($asset_keywords as $keyword_name => $description) {
544  $keywords[$keyword_name] = (empty($description)) ? ucwords(str_replace('_', ' ', $keyword_name)) : $description;
545  }
546 
547  unset($asset);
548 
549  // lineage
550  $keywords['asset_lineage'] = translate('asset_lineage');
551  $keywords['asset_lineage_linked'] = translate('asset_lineage_linked');
552 
553  // 3. asset metadata
554  $keywords['asset_metadata_'] = translate('asset_metadata_x');
555 
556  // 4. conditions
557  $condition_list = new Conditions_List($this, 'conditional_keywords');
558  $condition_names = $condition_list->getConditionsNames();
559 
560  foreach ($condition_names as $condition_name) {
561  $keywords[$condition_name] = ucwords(str_replace('_', ' ', $condition_name));
562  $keywords['begin_'.$condition_name] = translate('core_paint_layout_bodycopy_begin').' '.ucwords(str_replace('_', ' ', $condition_name));
563  $keywords['else_'.$condition_name] = translate('core_paint_layout_bodycopy_else').' '.ucwords(str_replace('_', ' ', $condition_name));
564  $keywords['end_'.$condition_name] = translate('core_paint_layout_bodycopy_end').' '.ucwords(str_replace('_', ' ', $condition_name));
565  $keywords['begin_'.$condition_name.'%<br />%else_'.$condition_name.'%<br />%end_'.$condition_name] = translate('core_paint_layout_bodycopy_full').' '.ucwords(str_replace('_', ' ', $condition_name));
566  }
567 
568  ksort($keywords);
569 
570  }//end if
571 
572  }//end getKeywordsDescription()
573 
574 
581  public function linksUpdated()
582  {
583  unset($this->_tmp['containers']);
584  parent::linksUpdated();
585  if(!$this->_updated()) return FALSE;
586  return TRUE;
587 
588  }// end linksUpdated()
589 
590 
591 }//end class
592 
593 ?>