Squiz Matrix  4.12.2
 All Data Structures Namespaces Functions Variables Pages
design_css.inc
1 <?php
18 require_once SQ_CORE_PACKAGE_PATH.'/designs/design/design.inc';
19 
33 class Design_Css extends Design
34 {
35 
36 
43  function __construct($assetid=0)
44  {
45  parent::__construct($assetid);
46  // We store a temp var that indicates whether the cache has been updated
47  // on this request
48  $this->_tmp['updated_cache'] = FALSE;
49 
50  }//end constructor
51 
52 
56  function __wakeup()
57  {
58  // Ensure this is reinitialised when restored from a serialised state.
59  $this->_tmp['updated_cache'] = FALSE;
60 
61  }//end wakeup
62 
63 
74  protected function _preCreateCheck(Array &$link)
75  {
76  if (!parent::_preCreateCheck($link)) return FALSE;
77 
78  $new_name = strtolower(trim($this->attr('id_name')));
79 
80  // no ampersands in css file name
81  $new_name = str_replace('&', SQ_CONF_WEB_PATH_SEPARATOR.'and'.SQ_CONF_WEB_PATH_SEPARATOR, $new_name);
82 
83  // no spaces in css file name
84  $new_name = preg_replace('/\\s+/', SQ_CONF_WEB_PATH_SEPARATOR, $new_name);
85 
86  // taken (in part) from info here -> http://www.w3.org/Addressing/URL/5_URI_BNF.html
87  $new_name = preg_replace('/[^a-zA-Z0-9\-$_@.!*~(),]/', '', $new_name);
88 
89  // ensure a virtual .css file extension
90  if (substr($new_name, -4) != '.css') {
91  $new_name .= '.css';
92  }
93 
94  $this->setAttrValue('id_name', $new_name);
95 
96  return TRUE;
97 
98  }//end _preCreateCheck()
99 
100 
111  protected function _createAdditional(Array &$link)
112  {
113  if (!parent::_createAdditional($link)) return FALSE;
114 
115  // set an initial web path
116  $initial_path = strtolower($this->attr('id_name'));
117  require_once SQ_INCLUDE_PATH.'/general_occasional.inc';
118  $valid_paths = make_valid_web_paths(Array($initial_path));
119  $good_paths = $GLOBALS['SQ_SYSTEM']->am->webPathsInUse($link['asset'], $valid_paths, $this->id, TRUE);
120  $this->saveWebPaths($good_paths);
121 
122  $this->_createCacheFile();
123  return TRUE;
124 
125  }//end _createAdditional()
126 
127 
135  public function _getAllowedLinks()
136  {
137  return Array(
138  SQ_LINK_TYPE_1 => Array(),
139  SQ_LINK_TYPE_2 => Array(
140  'design_css_customisation' => Array(
141  'card' => 'M',
142  'exclusive' => FALSE,
143  ),
144  'file' => Array(
145  'card' => 'M',
146  'exclusive' => FALSE,
147  ),
148  ),
149  SQ_LINK_TYPE_3 => Array(
150  'design_area' => Array(
151  'card' => 'M',
152  'exclusive' => FALSE,
153  ),
154  'file' => Array(
155  'card' => 'M',
156  'exclusive' => FALSE,
157  ),
158  ),
159  SQ_LINK_NOTICE => Array(),
160  );
161 
162  }//end _getAllowedLinks()
163 
164 
182  public function createLink(Asset $minor, $link_type, $value='', $sort_order=NULL, $dependant='0', $exclusive='0')
183  {
184  $GLOBALS['SQ_SYSTEM']->changeDatabaseConnection('db2');
185  $GLOBALS['SQ_SYSTEM']->doTransaction('BEGIN');
186 
187  $linkid = parent::createLink($minor, $link_type, $value, $sort_order, $dependant, $exclusive);
188  if (!$linkid) {
189  $GLOBALS['SQ_SYSTEM']->doTransaction('ROLLBACK');
190  $GLOBALS['SQ_SYSTEM']->restoreDatabaseConnection();
191  return FALSE;
192  }
193 
194  // special processing if we are creating a TYPE_2 linked file (inherited by customisations)
195  if ($minor instanceof File) {
196 
197  $am = $GLOBALS['SQ_SYSTEM']->am;
198 
199  $customisation_links = $GLOBALS['SQ_SYSTEM']->am->getLinks($this->id, SQ_LINK_TYPE_2, 'design_css_customisation', TRUE, 'major', 'customisation');
200  foreach ($customisation_links as $link) {
201  $customisation = $am->getAsset($link['minorid'], $link['minor_type_code']);
202  if (is_null($customisation)) continue;
203 
204  $file_link_ids = Array();
205  $file_links = $GLOBALS['SQ_SYSTEM']->am->getLinks($customisation->id, SQ_LINK_TYPE_2, 'file', FALSE);
206  foreach ($file_links as $link) {
207  $file_link_ids[] = $link['minorid'];
208  }
209  $file_link_info = $am->getAssetInfo(array_unique($file_link_ids));
210 
211  // is there already a direct file with the same name
212  $insert_link = TRUE;
213  foreach ($file_link_info as $info) {
214  if ($info['name'] == $minor->name) {
215  $insert_link = FALSE;
216  }
217  }
218 
219  if ($insert_link) {
220  if (!$customisation->createLink($minor, SQ_LINK_TYPE_3, '', NULL, 1)) {
221  trigger_localised_error('CORE0162', E_USER_WARNING);
222  $am->forgetAsset($customisation);
223  $GLOBALS['SQ_SYSTEM']->doTransaction('ROLLBACK');
224  $GLOBALS['SQ_SYSTEM']->restoreDatabaseConnection();
225  return FALSE;
226  }
227  }
228 
229  $am->forgetAsset($customisation);
230 
231  }//end foreach customisation
232 
233  }//end if is_a file
234 
235  $GLOBALS['SQ_SYSTEM']->doTransaction('COMMIT');
236  $GLOBALS['SQ_SYSTEM']->restoreDatabaseConnection();
237  return $linkid;
238 
239  }//end createLink()
240 
241 
250  public function deleteLink($linkid)
251  {
252  // first, we should try and find the link
253  $delete_link = $GLOBALS['SQ_SYSTEM']->am->getLinkById($linkid, $this->id);
254  if (empty($delete_link)) {
255  trigger_localised_error('CORE0155', E_USER_WARNING, $linkid);
256  return FALSE;
257  }
258 
259  $am = $GLOBALS['SQ_SYSTEM']->am;
260  $minor = $am->getAsset($delete_link['minorid'], $delete_link['minor_type_code']);
261 
262  $GLOBALS['SQ_SYSTEM']->changeDatabaseConnection('db2');
263  $GLOBALS['SQ_SYSTEM']->doTransaction('BEGIN');
264 
265  // special processing if we are deleting a TYPE_2 linked file (a file overridding a design file)
266  if ($minor instanceof File) {
267 
268  $customisation_links = $GLOBALS['SQ_SYSTEM']->am->getLinks($this->id, SQ_LINK_TYPE_2, 'design_css_customisation', TRUE, 'major', 'customisation');
269  foreach ($customisation_links as $link) {
270  $customisation = $am->getAsset($link['minorid'], $link['minor_type_code']);
271  if (is_null($customisation)) continue;
272 
273  $file_link_ids = Array();
274  $file_links = $GLOBALS['SQ_SYSTEM']->am->getLinks($customisation->id, SQ_LINK_TYPE_3, 'file', FALSE);
275 
276  foreach ($file_links as $link) {
277  if ($link['minorid'] == $delete_link['minorid']) {
278  // found the link to delete
279  if (!$customisation->deleteLink($link['linkid'])) {
280  trigger_localised_error('CORE0165', E_USER_WARNING);
281  $am->forgetAsset($customisation);
282  $GLOBALS['SQ_SYSTEM']->doTransaction('ROLLBACK');
283  $GLOBALS['SQ_SYSTEM']->restoreDatabaseConnection();
284  return FALSE;
285  }
286  }
287  }//end foreach $file_links
288 
289  $am->forgetAsset($customisation);
290 
291  }//end foreach customisation
292  } //end is_a file
293 
294  if (!parent::deleteLink($linkid)) {
295  $GLOBALS['SQ_SYSTEM']->doTransaction('ROLLBACK');
296  $GLOBALS['SQ_SYSTEM']->restoreDatabaseConnection();
297  return FALSE;
298  }
299 
300  $GLOBALS['SQ_SYSTEM']->doTransaction('COMMIT');
301  $GLOBALS['SQ_SYSTEM']->restoreDatabaseConnection();
302  return TRUE;
303 
304  }//end deleteLink()
305 
306 
319  public function deleteExistingLink($linkid)
320  {
321  // first, we should try and find the link
322  $delete_link = $GLOBALS['SQ_SYSTEM']->am->getLinkById($linkid, $this->id);
323  if (empty($delete_link)) {
324  trigger_localised_error('CORE0155', E_USER_WARNING, $linkid);
325  return FALSE;
326  }
327 
328  $am = $GLOBALS['SQ_SYSTEM']->am;
329  $minor = $am->getAsset($delete_link['minorid'], $delete_link['minor_type_code']);
330 
331  $GLOBALS['SQ_SYSTEM']->changeDatabaseConnection('db2');
332  $GLOBALS['SQ_SYSTEM']->doTransaction('BEGIN');
333 
334  if (!parent::deleteLink($linkid)) {
335  $GLOBALS['SQ_SYSTEM']->doTransaction('ROLLBACK');
336  $GLOBALS['SQ_SYSTEM']->restoreDatabaseConnection();
337  return FALSE;
338  }
339 
340  $GLOBALS['SQ_SYSTEM']->doTransaction('COMMIT');
341  $GLOBALS['SQ_SYSTEM']->restoreDatabaseConnection();
342 
343  return TRUE;
344 
345  }//end deleteExistingLink()
346 
347 
355  public function printFrontend()
356  {
357  if (!$this->readAccess()) {
358  $GLOBALS['SQ_SYSTEM']->paintLogin(translate('login'), translate('cannot_access_asset', $this->name));
359  return;
360  }
361  $this->paint($this);
362 
363  }//end printFrontend()
364 
365 
372  public function getParentDesign()
373  {
374  // a css file is its own customisation
375  return $this;
376 
377  }//end getParentDesign()
378 
379 
389  public function printVar($var, Array $args)
390  {
391  switch ($var) {
392  case 'css_header' :
393 echo '/*
394  Running Squiz Matrix
395  Developed by Squiz - http://www.squiz.net
396  Squiz, Squiz Matrix, MySource, MySource Matrix and Squiz.net are registered Trademarks of Squiz Pty Ltd
397  Page generated: <?php echo date(\'d F Y H:i:s\')."\n"; ?>
398 */
399 
400 ';
401  break;
402 
403  default :
404  parent::printVar($var, $args);
405 
406  }//end switch
407 
408  }//end printVar()
409 
410 
417  public function _getDesignFileHeader()
418  {
419  return '<?php header("Content-type: text/css"); ?>
420  '.parent::_getDesignFileHeader();
421 
422  }//end _getDesignFileHeader()
423 
424 
434  public function processBackend(Backend_Outputter $o, Array &$link)
435  {
436  $public_userid = $GLOBALS['SQ_SYSTEM']->am->getSystemAssetid('public_user');
437 
438  //store old attributes, status and public read permission that can affect the regeneration of static cache file
439  $cache = $this->attr('cache_css');
440  $strip = $this->attr('strip_whitespace');
441  //status and public read permission can make the URLs of child assets changed, so we will need to regenerate cache file
442  $status = $this->status;
443  $read_access = $this->_checkPermissionAccess(SQ_PERMISSION_READ, Array($public_userid));
444 
445  if (!parent::processBackend($o, $link)) return FALSE;
446 
447  //URLs only changed if status is changed from or to live, and/or when public read permission is changed
448  $status_changed = ($status != $this->status) && (($status == SQ_STATUS_LIVE) || ($this->status == SQ_STATUS_LIVE));
449  $read_access_changed = ($read_access != $this->_checkPermissionAccess(SQ_PERMISSION_READ, Array($public_userid)));
450 
451  $regen = $this->attr('cache_css') && (($cache != $this->attr('cache_css')) || ($strip != $this->attr('strip_whitespace')) || $status_changed
452  || $read_access_changed);
453  // Okay, if after processing everything in the backend, and the
454  // status of the cache_css attribute is TRUE (use static cache file) and either the cache_css attribute, the strip_whitespace attribute,
455  // the status (changed to or from live), or the public read permission is changed,
456  // we've gotta update the static cache to reflect that this has changed.
457  if ($regen && !$this->_tmp['updated_cache']) {
458  $this->_updateCacheFile();
459  $am = $GLOBALS['SQ_SYSTEM']->am;
460  $customisation_links = $am->getLinks($this->id, SQ_LINK_TYPE_2, 'design_css_customisation', TRUE, 'major', 'customisation');
461 
462  foreach ($customisation_links as $link) {
463  $customisation = $am->getAsset($link['minorid'], $link['minor_type_code']);
464  if (is_null($customisation)) continue;
465  $customisation->_updateCacheFile();
466  }// end foreach
467  }
468 
469  return TRUE;
470 
471  }//end processBackend()
472 
473 
482  public function generateDesignFile($do_customisations=TRUE)
483  {
484  $success = TRUE;
485  $success &= parent::generateDesignFile($do_customisations);
486 
487  if ($this->attr('cache_css')) {
488  $success &= $this->_updateCacheFile();
489  }
490  return $success;
491  }//end generateDesignFile()
492 
493 
500  public function updateCustomisations()
501  {
502  $customisation_links = $GLOBALS['SQ_SYSTEM']->am->getLinks($this->id, SQ_LINK_TYPE_2, 'design_css_customisation', TRUE, 'major', 'customisation');
503  $am = $GLOBALS['SQ_SYSTEM']->am;
504  foreach ($customisation_links as $link) {
505  $customisation = $am->getAsset($link['minorid'], $link['minor_type_code']);
506  if (is_null($customisation)) continue;
507  if ($acquired = $GLOBALS['SQ_SYSTEM']->am->acquireLock($customisation->id, 'all')) {
508  $customisation->updateFromParent($this);
509  if ($acquired != 2) {
510  $GLOBALS['SQ_SYSTEM']->am->releaseLock($customisation->id, 'all');
511  }
512  }
513  }// end foreach
514 
515  }//end updateCustomisations()
516 
517 
524  public function _updateCacheFile()
525  {
526  $am = $GLOBALS['SQ_SYSTEM']->am;
527 
528  // Generate the CSS static file. Note that we've turned error_reporting off for this
529  // because design_file.php does a whole bunch of define()ing that can cause problems
530  $old_level = error_reporting();
531  error_reporting(0);
532  ob_start();
533  $this->paint($this);
534  $file_contents = ob_get_contents();
535  ob_end_clean();
536  error_reporting($old_level);
537 
538  $cache_link = $am->getLink($this->id, SQ_LINK_TYPE_3, 'file', FALSE, 'css_cache');
539  if (empty($cache_link)) {
540  $cache_asset = $this->_createCacheFile();
541  } else {
542  $cache_asset = $am->getAsset($cache_link['minorid']);
543  }
544  if ($cache_asset == NULL) return FALSE;
545 
546  // Strip excess whitespace
547  if ($this->attr('strip_whitespace')) {
548  $file_contents = preg_replace('/\s+/is', ' ', $file_contents);
549  }
550  $existing = $cache_asset->getExistingFile();
551  string_to_file($file_contents, $existing['path']);
552 
553  $fv = $GLOBALS['SQ_SYSTEM']->getFileVersioning();
554  $file_status = $fv->upToDate($cache_asset->data_path.'/'.$cache_asset->_getName());
555  if (FUDGE_FV_MODIFIED & $file_status) {
556  if (!$fv->commit($cache_asset->data_path.'/'.$cache_asset->_getName())) {
557  trigger_localised_error('CORE0034', E_USER_WARNING);
558  return FALSE;
559  }
560  }
561  $this->_tmp['updated_cache'] = TRUE;
562  return $cache_asset->_updated();
563 
564  }//end _updateCacheFile()
565 
566 
573  public function getCacheFileId()
574  {
575  $am = $GLOBALS['SQ_SYSTEM']->am;
576  $cache_link = $am->getLink($this->id, SQ_LINK_TYPE_3, 'file', true, 'css_cache');
577  if (empty($cache_link)) return 0;
578  return $cache_link['minorid'];
579 
580  }//end getCacheFileId()
581 
582 
589  public function _createCacheFile()
590  {
591  $null = NULL;
592 
593  // check if we need to add the .css extension to the file
594  $filename = $this->_getName();
595  if (substr($filename, -4) != '.css') {
596  $filename .= '.css';
597  }
598  if (!is_dir($this->data_path)) {
599  create_directory($this->data_path);
600  }
601  if (!string_to_file('', $this->data_path.'/'.$filename)) {
602  return $null;
603  }
604 
605  $tmp_file = $this->data_path.'/'.$filename;
606 
607  $import_link = Array('asset' => &$this, 'link_type' => SQ_LINK_TYPE_3, 'value' => 'css_cache', 'sort_order' => 1, 'is_dependant' => 1);
608  $temp_info = Array('name' => $filename, 'tmp_name' => $tmp_file, 'non_uploaded_file' => TRUE);
609 
610  require_once SQ_CORE_PACKAGE_PATH.'/files/file/file.inc';
611  $new_file = new File();
612  $new_file->_tmp['uploading_file'] = TRUE;
613  $new_file->setAttrValue('name', $filename);
614  $new_file->setAttrValue('allow_unrestricted', FALSE);
615 
616  if (!$new_file->create($import_link, $temp_info)) {
617  trigger_localised_error('CORE0058', E_USER_WARNING, $filename);
618  return $null;
619  }
620 
621  $new_file->saveWebPaths(Array());
622 
623  return $new_file;
624 
625  }//end _createCacheFile()
626 
627 
637  public function getDesignAreaLink($id_name='')
638  {
639  if ($id_name) {
640  return @$GLOBALS['SQ_SYSTEM']->am->getLink($this->id, SQ_LINK_TYPE_3, 'design_area', FALSE, $id_name);
641  } else {
642  return @$GLOBALS['SQ_SYSTEM']->am->getLinks($this->id, SQ_LINK_TYPE_3, 'design_area', FALSE);
643  }
644 
645  }//end getDesignAreaLink()
646 
647 
659  public function paint(Asset $ASSET, $FILE_URLS=Array())
660  {
661  // generate an array of all the URLs we are going to need for the files in this design
662  $file_link_ids = Array();
663  $file_links = $GLOBALS['SQ_SYSTEM']->am->getLinks($this->id, SQ_LINK_TYPE_2 | SQ_LINK_TYPE_3, 'file', FALSE);
664 
665  foreach ($file_links as $link) {
666  $file_link_ids[] = $link['minorid'];
667  }
668 
669  $file_link_info = $GLOBALS['SQ_SYSTEM']->am->getAssetInfo(array_unique($file_link_ids));
670  $file_link_urls = $GLOBALS['SQ_SYSTEM']->am->getAssetURL(array_unique($file_link_ids));
671 
672  $system_root_url = sq_web_path('root_url');
673  foreach ($file_link_info as $minorid => $file_info) {
674  $file_url = $file_link_urls[$minorid];
675  if ($file_url == '') {
676  $file_url = $system_root_url.'/?a='.$minorid;
677  } else if ($this->attr('static_url_versioning')){
678  $served_by_apache = strpos($file_url, '/__data/') !== FALSE || (SQ_CONF_STATIC_ROOT_URL && strpos($file_url, SQ_CONF_STATIC_ROOT_URL.'/') !== FALSE);
679  if ($served_by_apache) $file_url .= '?v='.$file_info['version'];
680  }
681  $FILE_URLS[$file_info['name']] = $file_url;
682  }
683 
684  $DATA_PATH = sq_web_path('data'); // this works because we know that all design areas are not going to be restricted
685  $LIB_PATH = sq_web_path('lib');
686 
687  // work out where the design file is
688  if (SQ_ROLLBACK_VIEW) {
689  // get an older version of our design file
690  $fv = $GLOBALS['SQ_SYSTEM']->getFileVersioning();
691  $rep_file = $this->data_path_suffix.'/design_file.php';
692  $then = iso8601_ts($_SESSION['sq_rollback_view']['rollback_time']);
693  $info = $fv->_checkOutCheck($rep_file, NULL, $then);
694  $file_path = $info['source_file'];
695  } else {
696  $file_path = $this->data_path.'/design_file.php';
697  }
698 
699  // design file not found for this asset
700  if (!file_exists($file_path)) {
701  // use the template file of parent design_css asset
702  $parents = $GLOBALS['SQ_SYSTEM']->am->getParents($this->id, 'design_css', FALSE);
703  foreach ($parents as $id => $type) {
704  $parent = $GLOBALS['SQ_SYSTEM']->am->getAsset($id);
705  if ($parent) {
706  $file_path = $parent->data_path.'/design_file.php';
707  $GLOBALS['SQ_SYSTEM']->am->forgetAsset($parent);
708  if (file_exists($file_path)) {
709  break;
710  }
711  }
712  }
713  }
714 
715  // Now we just include the design file to get it to print
716  if (file_exists($file_path)) {
717  require $file_path;
718  } else {
719  trigger_localised_error('CORE0259', E_USER_WARNING, $ASSET->name);
720  }
721 
722  }//end paint()
723 
724 
731  public function saveAttributes()
732  {
733  if (!parent::saveAttributes()) {
734  return FALSE;
735  }
736  if ($this->id) $this->_setCacheFileEnabled($this->attr('cache_css'));
737  return TRUE;
738 
739  }//end saveAttributes()
740 
741 
750  public function _setCacheFileEnabled($enabled)
751  {
752  $cache_id = $this->getCacheFileId();
753  if (empty($cache_id)) {
754  $parents = $GLOBALS['SQ_SYSTEM']->am->getParents($this->id);
755  if (empty($parents)) return;
756  $cache_file = $this->_createCacheFile();
757  $cache_id = $cache_file->id;
758  }
759 
760  $cache_url = $GLOBALS['SQ_SYSTEM']->am->getAssetURL($cache_id);
761  if (empty($cache_url) == $enabled) {
762  // it either has a url but shouldn't or doesn't have a url but should
763  $cache_file = $GLOBALS['SQ_SYSTEM']->am->getAsset($cache_id);
764  $paths = $enabled ? Array($cache_file->name) : Array();
765  $cache_file->saveWebPaths($paths);
766  $cache_file->setAttrValue('allow_unrestricted', $enabled);
767  $cache_file->saveAttributes();
768  }
769 
770  }//end _setCacheFileEnabled()
771 
772 
773 
774 }//end class
775 ?>