Squiz Matrix  4.12.2
 All Data Structures Namespaces Functions Variables Pages
design_area_edit_fns.inc
1 <?php
18 require_once SQ_INCLUDE_PATH.'/asset_edit/asset_edit_fns.inc';
19 
32 {
33 
38  public $tag_name = 'MySource';
39 
40 
45  function __construct()
46  {
47  $this->static_screens['details']['lock_type'] = 'parsing';
48  parent::__construct();
49 
50  }//end constructor
51 
52 
63  public function paintIdName(Design_Area $asset, Backend_Outputter $o, $prefix)
64  {
65  echo $asset->attr('id_name');
66  return TRUE;
67 
68  }//end paintIdName()
69 
70 
79  public function _parseString($file_contents)
80  {
81  // lets just make sure that they are all UNIX new lines
82  $file_contents = str_replace(Array("\r\n", "\r"), "\n", $file_contents);
83 
84  // replace any image roots with a print operation for the image prefix
85  $e = '|mysource_files\/([a-zA-Z0-9\._\-]+)|i';
86  $file_contents = preg_replace($e, '<'.$this->tag_name.'_PRINT id_name=\'__global__\' var=\'file_path\' filename=\'\\1\' />', $file_contents);
87 
88  // replace any css roots with a print operation for the css prefix
89  $e = '|mysource_css\/([a-zA-Z0-9\._\-]+)|i';
90  $file_contents = preg_replace($e, '<'.$this->tag_name.'_PRINT id_name=\'__global__\' var=\'css_path\' filename=\'\\1\' />', $file_contents);
91 
92  // replace any './[folder/filename]' with '[folder/filename]'
93  $e = '/(<link[^>]*href=")\\.\\//i';
94  $file_contents = preg_replace($e, '\\1', $file_contents);
95 
96  // lets just make sure they aren't trying to be tricky and do some processing we don't know about
97  $file_contents = preg_replace('/<\?(?!xml)(.*)(?=\?>)\?>/ims', '&lt;?$1?&gt;', $file_contents);
98  $file_contents = preg_replace('|<\?(?=xml)(.+?)(?=\?>)\?>|', '<?php echo "<"."?"; ?>\\1<?php echo "?".">"; ?>', $file_contents);
99 
100  // Lets make all occurances of the open cnd close tags the
101  // same case as the constant just to make it easier to parse
102  $file_contents = preg_replace('/<'.$this->tag_name.'/i', '<'.$this->tag_name, $file_contents);
103  $file_contents = preg_replace('/<\\/'.$this->tag_name.'/i', '</'.$this->tag_name, $file_contents);
104 
105  // create the super array from the tags
106  $cur_pos = 0;
107  $nest_level = 0;
108  $contents = $this->_parseStringContents($file_contents, $cur_pos, $nest_level);
109 
110  return $contents;
111 
112  }//end _parseString()
113 
114 
128  protected function _parseStringContents(&$file_contents, &$cur_pos, &$nest_level)
129  {
130  $start_pos = $cur_pos;
131  $parsed = Array();
132  $tag = Array(); // the currently processed tag
133 
134  $is_nested = ($nest_level > 0);
135 
136  while ($next_tag = $this->_tagToParse($file_contents, $cur_pos)) {
137  // append the string before this current pos to the array
138  $parsed[] = Array(
139  '_type' => 'HTML',
140  'contents' => substr($file_contents, $start_pos, $cur_pos - $start_pos),
141  );
142 
143  if ($next_tag == 'terminate') {
144  // if this instance is nested then we have found our parents end tag
145  if ($is_nested) {
146  // hey we found a terminate tag so decrement the nest counter
147  $nest_level--;
148  return $parsed;
149  // else are in the root level and we have found a stray ternminate tag
150  // so remove it
151  } else {
152  $this->_parseTerminateTag($file_contents, $cur_pos);
153  }
154 
155  // its an open tag
156  } else {
157 
158  $tag = $this->_parseOpenTag($file_contents, $cur_pos);
159 
160  // if this tag terminates then blank array for it's contents
161  if ($tag['self_terminating']) {
162  $tag['contents'] = Array();
163 
164  // else this tag doesn't terminate the we need to allow for its contents
165  } else {
166  $this_nest_level = $nest_level;
167  // because we are going to the next level increment
168  $nest_level++;
169  $tag['contents'] = $this->_parseStringContents($file_contents, $cur_pos, $nest_level);
170  // if something went wrong, bail out
171  if (is_null($tag['contents'])) return NULL;
172 
173  // if this instance of the functions nest level is the same as the global one
174  // then the recursive call found e terminate tag, so remove it
175  if ($this_nest_level == $nest_level) {
176  $this->_parseTerminateTag($file_contents, $cur_pos);
177 
178  // else we're missing a terminate tag, so die screaming
179  } else {
180  $die_str = $this->tag_name;
181  $die_str .= (empty($tag['operation'])) ? '' : '_'.$tag['operation'];
182 
183  foreach ($tag['attributes'] as $name => $value) {
184  $die_str .= ' '.$name.'="'.$value.'"';
185  }
186 
187  trigger_localised_error('CORE0213', E_USER_WARNING, $this->tag_name, $die_str);
188  return NULL;
189 
190  }// end if
191  }// end if
192 
193  $parsed[] = $tag;
194 
195  }//end else if next tag
196 
197  // end parsing the tag
198 
199  $start_pos = $cur_pos;
200 
201  }//end while
202 
203  // if this instance opf the funciton is not nested
204  // then it must be the root level
205  if (!$is_nested) {
206  // so append the rest of the html code to the array
207  $parsed[] = Array(
208  '_type' => 'HTML',
209  'contents' => substr ($file_contents, $cur_pos),
210  );
211 
212  }//end if
213 
214  return $parsed;
215 
216  }//end _parseStringContents()
217 
218 
230  protected function _tagToParse(&$file_contents, &$cur_pos)
231  {
232  // get the next terminate and open tag locations
233  $next_open_pos = strpos($file_contents, '<'.$this->tag_name, $cur_pos);
234  $next_open_tag = ($next_open_pos !== FALSE);
235  $next_terminate_pos = strpos($file_contents, '</'.$this->tag_name, $cur_pos);
236 
237  // if there is a terminate tag
238  if ($next_terminate_pos !== FALSE) {
239  // if there is no open tag
240  // or if there is a open tag and its located after the terminate tag
241  // then parse the terminate tag
242  if (!$next_open_tag || ($next_open_tag && ($next_terminate_pos < $next_open_pos))) {
243  $cur_pos = $next_terminate_pos;
244  return 'terminate';
245  }
246  }
247 
248  // if there is a open tag then use it
249  if ($next_open_tag) {
250  $cur_pos = $next_open_pos;
251  return 'open';
252  }
253 
254  // if they got this far there isn't anything left
255  return '';
256 
257  }//end _tagToParse()
258 
259 
271  protected function _parseOpenTag(&$file_contents, &$cur_pos)
272  {
273  $cur_pos += strlen('<'.$this->tag_name);
274 
275  $in_quote = '';
276  $escape_slash = FALSE;
277 
278  $currently_getting = ''; // name or value
279  $current_name = ''; // attribute name
280  $current_value = ''; // attribute value
281 
282  // used to reverse any HTML encoding that has taking place
283  $trans = array_flip(get_html_translation_table(HTML_ENTITIES));
284 
285  $tag = Array('_type' => 'TAG', 'attributes' => Array());
286 
287  // if the next character is an underscore then we have a special operation tag
288  if ($file_contents{$cur_pos} == '_') {
289  $cur_pos++;
290  $tag['operation'] = '';
291  // while this isn't the end of the tag and it's not some white space,
292  // append to operation
293  while ($file_contents{$cur_pos} != '>' && !$this->_isWhitespace($file_contents{$cur_pos})) {
294  $tag['operation'] .= $file_contents{$cur_pos};
295  $cur_pos++;
296 
297  }//end while
298 
299  $tag['operation'] = strtolower($tag['operation']);
300 
301  }//end if specific operation
302 
303  while ($file_contents{$cur_pos} != '>' || $in_quote) {
304 
305  $escape_slash = (!$in_quote && $file_contents{$cur_pos} == '/');
306  if (!$escape_slash) {
307  // if we are not currenly getting any thing and we happen to fall upon
308  // a non-whitespace charater then let's assume its an attribute name
309  // and start getting it
310  if (!$currently_getting && !$this->_isWhitespace($file_contents{$cur_pos})) {
311  $currently_getting = 'name';
312  }
313 
314 
315  if ($currently_getting == 'name') {
316  // if this is the equals sign then time to change to getting the value
317  if ($file_contents{$cur_pos} == '=') {
318  $currently_getting = 'value';
319  $current_value = '';
320 
321  // if its whitespace, discard this name
322  } else if ($this->_isWhitespace($file_contents{$cur_pos})) {
323  $currently_getting = '';
324  $current_name = '';
325  // must be a character, append to name
326  } else {
327  $current_name .= $file_contents{$cur_pos};
328  }
329 
330  } else if ($currently_getting == 'value') {
331 
332  // if the current value is blank, we are not in a quote and this char is a quote
333  // then we must be starting a new value
334  $is_quote = ($file_contents{$cur_pos} == '\'' || $file_contents{$cur_pos} == '"');
335  if (!$current_value && !$in_quote && $is_quote) {
336  $in_quote = $file_contents{$cur_pos};
337 
338  // if we're not in a quote, then this value doesn't have quotes around it
339  // so just keep going until we hit some whitespace
340  } else if (!$in_quote && !$this->_isWhitespace($file_contents{$cur_pos})) {
341  $current_value .= $file_contents{$cur_pos};
342 
343  // if we are in a quote and this char is not that quote, append
344  } else if ($in_quote && $file_contents{$cur_pos} != $in_quote) {
345  $current_value .= $file_contents{$cur_pos};
346 
347  // else we are either not in a quote and have hit some white space
348  // or we are in a quote and have found a another quote of the same char
349  // SO, we have finished this value, assign to tag and start over
350  } else {
351  $tag['attributes'][strtolower($current_name)] = strtr($current_value, $trans);
352  $currently_getting = '';
353  $current_name = '';
354  $current_value = '';
355  $in_quote = '';
356 
357  }// end if
358 
359  }// end if
360 
361  }//end if not escape slash
362 
363 
364  $cur_pos++;
365 
366  }//end while
367  $cur_pos++;
368 
369  // if the last char before the close bracket is an foreslash
370  // then this tag does not have a matching termination tag
371  $tag['self_terminating'] = $escape_slash;
372 
373  return $tag;
374 
375  }//end _parseOpenTag()
376 
377 
387  protected function _parseTerminateTag(&$file_contents, &$cur_pos)
388  {
389  $cur_pos += strlen('</'.$this->tag_name);
390  // go to the next close bracket
391  $cur_pos = strpos($file_contents, '>', $cur_pos);
392  // go to char after it
393  $cur_pos++;
394 
395  }//end _parseTerminateTag()
396 
397 
406  protected function _isWhitespace($str)
407  {
408  return preg_match('/^[[:space:]]*$/', $str);
409 
410  }//end _isWhitespace()
411 
412 
422  public function _processContents(Design_Area $asset, Array $contents)
423  {
424  if ($this->_setVariables($asset, $contents)) {
425  $GLOBALS['SQ_PROCESSED_DESIGN_AREAS'][$asset->attr('id_name')] = TRUE;
426  return $asset->setAttrValue('contents', $contents);
427  } else {
428  return FALSE;
429  }
430 
431  }//end _processContents()
432 
433 
448  protected function _setVariables(Design_Area &$asset, Array &$contents)
449  {
450  // process the set operations of the element
451  $remove_indexes = Array();
452  // Holds all attributes that have been set in the parse file for this design area
453  $set_attrs = Array();
454  $var_references = Array();
455  foreach ($contents as $index => $element) {
456 
457  if ($element['_type'] != 'TAG' || $element['operation'] != 'set') {
458  continue;
459  }
460 
461  // Is this a reference to another variable ?
462  if (!empty($element['attributes']['id_name']) && !empty($element['attributes']['var'])) {
463 
464  // just set this so we remember what is happening when it comes to painting
465  $var_references[$element['attributes']['name']] = Array(
466  'id_name' => $element['attributes']['id_name'],
467  'var' => $element['attributes']['var'],
468  );
469 
470  // Do we want a whole design areas value ?
471  } else if (!empty($element['attributes']['id_name'])) {
472 
473  // just set this so we remember what is happening when it comes to painting
474  $var_references[$element['attributes']['name']] = Array(
475  'id_name' => $element['attributes']['id_name'],
476  'var' => '',
477  );
478 
479  // we must be a normal value, so set it
480  } else if (isset($element['attributes']['value'])) {
481  // if this holds an image, then remove any image roots before saving
482  if (stristr($element['attributes']['name'], 'image')) {
483  $element['attributes']['value'] = $this->_removeFileRoot($element['attributes']['value']);
484  }
485 
486  if (!$asset->setAttrValue($element['attributes']['name'], $element['attributes']['value'])) {
487  trigger_localised_error('CORE0189', E_USER_WARNING, $element['attributes']['name'], $asset->attr('id_name'));
488  return FALSE;
489  }
490  $set_attrs[] = $element['attributes']['name'];
491 
492  // else something is amiss and we don't know what we can do
493  } else {
494  trigger_localised_error('CORE0188', E_USER_WARNING, $element['attributes']['name'], $asset->attr('id_name'));
495 
496 
497  }// endif
498 
499  $remove_indexes[] = $index;
500  }//end foreach
501 
502  if (!$asset->setAttrValue('var_references', $var_references)) {
503  return FALSE;
504  }
505  // Now remove the elems
506  // reverse the order so we don't throw the numbers out of whack by removing one from the start
507  rsort($remove_indexes, SORT_NUMERIC);
508  foreach ($remove_indexes as $i) {
509  array_splice($contents, $i, 1);
510  }
511 
512  // Now we need to ensure that any attributes that weren't set in the parse file
513  // are returned to their default values
514  // Design Area attributes that shouldn't be reset
515 
516  $not_setable_attrs = $asset->getProtectedAttrs();
517  $current_asset_attrs = $GLOBALS['SQ_SYSTEM']->am->getAssetTypeAttributes($asset->type(), Array('name'));
518 
519  // Now compute the remaining attributes, by subtracting all that shouldn't be deleted
520  // and all that are set in the parse file
521  $set_to_default = array_diff($current_asset_attrs, $not_setable_attrs, $set_attrs);
522 
523  // Now iterate through each variable that is setable and doesn't exist in the parse file,
524  // find and retrieve its attribute and set its current value to the default
525  foreach ($set_to_default as $i => $attr_name) {
526  $attr_to_set = $GLOBALS['SQ_SYSTEM']->am->getAttribute($asset->vars[$attr_name]['attrid']);
527  $default_val = $attr_to_set->_default_value;
528  if ($attr_to_set instanceof Asset_Attribute_Serialise) {
529  $default_val = unserialize($default_val);
530  }
531  $asset->setAttrValue($attr_name, $default_val);
532  $attr_to_set = NULL;
533  }
534  return TRUE;
535 
536  }//end _setVariables()
537 
538 
549  protected function _removeFileRoot($str)
550  {
551  return preg_replace('/^(\\.\\/)?mysource_files\/(.*)/i', '\\2', $str);
552 
553  }//end _removeFileRoot()
554 
555 
569  protected function _getDefaultContents(Design_Area $asset, $content_type)
570  {
571  $parent_types = $asset->getTypeAncestors(FALSE);
572  array_unshift($parent_types, $asset->type());
573  for ($i = 0, $total = count($parent_types); $i < $total; $i++) {
574 
575  $file = SQ_SYSTEM_ROOT.'/'.$GLOBALS['SQ_SYSTEM']->am->getTypeInfo($parent_types[$i], 'dir').'/default_'.$content_type.'_contents.html';
576  if (file_exists($file)) {
577  require_once SQ_FUDGE_PATH.'/general/file_system.inc';
578  $contents = $this->_parseString(file_to_string($file));
579  return $contents;
580  }//end if
581 
582  // we don't need to go any higher than this class
583  if ($parent_types[$i] == 'design_area') break;
584 
585  }//end for
586 
587  return Array();
588 
589  }//end _getDefaultContents()
590 
591 
592 }//end class
593 ?>