00001 <?php
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028 class Mage_Core_Model_Layout_Update
00029 {
00030
00031
00032
00033 const LAYOUT_GENERAL_CACHE_TAG = 'LAYOUT_GENERAL_CACHE_TAG';
00034
00035
00036
00037
00038
00039
00040 protected $_elementClass;
00041
00042
00043
00044
00045 protected $_packageLayout;
00046
00047
00048
00049
00050
00051
00052 protected $_cacheId;
00053
00054
00055
00056
00057
00058
00059 protected $_cachePrefix;
00060
00061
00062
00063
00064
00065
00066 protected $_updates = array();
00067
00068
00069
00070
00071
00072
00073 protected $_handles = array();
00074
00075
00076
00077
00078
00079
00080 protected $_subst = array();
00081
00082 public function __construct()
00083 {
00084 $subst = Mage::getConfig()->getPathVars();
00085 foreach ($subst as $k=>$v) {
00086 $this->_subst['from'][] = '{{'.$k.'}}';
00087 $this->_subst['to'][] = $v;
00088 }
00089 }
00090
00091 public function getElementClass()
00092 {
00093 if (!$this->_elementClass) {
00094 $this->_elementClass = Mage::getConfig()->getModelClassName('core/layout_element');
00095 }
00096 return $this->_elementClass;
00097 }
00098
00099 public function resetUpdates()
00100 {
00101 $this->_updates = array();
00102 return $this;
00103 }
00104
00105 public function addUpdate($update)
00106 {
00107 $this->_updates[] = $update;
00108 return $this;
00109 }
00110
00111 public function asArray()
00112 {
00113 return $this->_updates;
00114 }
00115
00116 public function asString()
00117 {
00118 return implode('', $this->_updates);
00119 }
00120
00121 public function resetHandles()
00122 {
00123 $this->_handles = array();
00124 return $this;
00125 }
00126
00127 public function addHandle($handle)
00128 {
00129 if (is_array($handle)) {
00130 foreach ($handle as $h) {
00131 $this->_handles[$h] = 1;
00132 }
00133 } else {
00134 $this->_handles[$handle] = 1;
00135 }
00136 return $this;
00137 }
00138
00139 public function removeHandle($handle)
00140 {
00141 unset($this->_handles[$handle]);
00142 return $this;
00143 }
00144
00145 public function getHandles()
00146 {
00147 return array_keys($this->_handles);
00148 }
00149
00150
00151
00152
00153
00154
00155 public function getCacheId()
00156 {
00157 if (!$this->_cacheId) {
00158 $this->_cacheId = Mage::app()->getStore()->getId().'_'.md5(join('__', $this->getHandles()));
00159 }
00160 return $this->_cacheId;
00161 }
00162
00163
00164
00165
00166
00167
00168
00169 public function setCacheId($cacheId)
00170 {
00171 $this->_cacheId = $cacheId;
00172 return $this;
00173 }
00174
00175 public function loadCache()
00176 {
00177 if (!Mage::app()->useCache('layout')) {
00178 return false;
00179 }
00180
00181 if (!$result = Mage::app()->loadCache($this->getCacheId())) {
00182 return false;
00183 }
00184
00185 $this->addUpdate($result);
00186
00187 return true;
00188 }
00189
00190 public function saveCache()
00191 {
00192 if (!Mage::app()->useCache('layout')) {
00193 return false;
00194 }
00195 $str = $this->asString();
00196 $tags = $this->getHandles();
00197 $tags[] = self::LAYOUT_GENERAL_CACHE_TAG;
00198 return Mage::app()->saveCache($str, $this->getCacheId(), $tags, null);
00199 }
00200
00201
00202
00203
00204
00205
00206
00207 public function load($handles=array())
00208 {
00209 if (is_string($handles)) {
00210 $handles = array($handles);
00211 } elseif (!is_array($handles)) {
00212 throw Mage::exception('Mage_Core', Mage::helper('core')->__('Invalid layout update handle'));
00213 }
00214
00215 foreach ($handles as $handle) {
00216 $this->addHandle($handle);
00217 }
00218
00219 if ($this->loadCache()) {
00220 return $this;
00221 }
00222
00223 foreach ($this->getHandles() as $handle) {
00224 $this->merge($handle);
00225 }
00226
00227 $this->saveCache();
00228 return $this;
00229 }
00230
00231 public function asSimplexml()
00232 {
00233 $updates = trim($this->asString());
00234 $updates = '<'.'?xml version="1.0"?'.'><layout>'.$updates.'</layout>';
00235 return simplexml_load_string($updates, $this->getElementClass());
00236 }
00237
00238
00239
00240
00241
00242
00243
00244 public function merge($handle)
00245 {
00246 if (!$this->fetchPackageLayoutUpdates($handle)
00247 && !$this->fetchDbLayoutUpdates($handle)) {
00248 #$this->removeHandle($handle);
00249 }
00250 return $this;
00251 }
00252
00253 public function fetchFileLayoutUpdates()
00254 {
00255 $elementClass = $this->getElementClass();
00256
00257 $design = Mage::getSingleton('core/design_package');
00258 $area = $design->getArea();
00259 $storeId = Mage::app()->getStore()->getId();
00260 $cacheKey = 'LAYOUT_'.$area.'_STORE'.$storeId.'_'.$design->getPackageName().'_'.$design->getTheme('layout');
00261 #echo "TEST:".$cacheKey;
00262 $cacheTags = array('layout');
00263
00264 if (Mage::app()->useCache('layout') && ($layoutStr = Mage::app()->loadCache($cacheKey))) {
00265 $this->_packageLayout = simplexml_load_string($layoutStr, $elementClass);
00266 }
00267
00268 if (empty($layoutStr)) {
00269 $updatesRoot = Mage::app()->getConfig()->getNode($area.'/layout/updates');
00270 Mage::dispatchEvent('core_layout_update_updates_get_after', array('updates' => $updatesRoot));
00271 $updateFiles = array();
00272 foreach ($updatesRoot->children() as $updateNode) {
00273 if ($updateNode->file) {
00274 $module = $updateNode->getAttribute('module');
00275 if ($module && Mage::getStoreConfigFlag('advanced/modules_disable_output/' . $module)) {
00276 continue;
00277 }
00278 $updateFiles[] = (string)$updateNode->file;
00279 }
00280 }
00281
00282
00283 $updateFiles[] = 'local.xml';
00284
00285 $layoutStr = '';
00286 #$layoutXml = new $elementClass('<layouts/>');
00287 foreach ($updateFiles as $file) {
00288 $filename = $design->getLayoutFilename($file);
00289 if (!is_readable($filename)) {
00290 continue;
00291 }
00292 $fileStr = file_get_contents($filename);
00293 $fileStr = str_replace($this->_subst['from'], $this->_subst['to'], $fileStr);
00294 $fileXml = simplexml_load_string($fileStr, $elementClass);
00295 if (!$fileXml instanceof SimpleXMLElement) {
00296 continue;
00297 }
00298 $layoutStr .= $fileXml->innerXml();
00299
00300 #$layoutXml->appendChild($fileXml);
00301 }
00302 $layoutXml = simplexml_load_string('<layouts>'.$layoutStr.'</layouts>', $elementClass);
00303
00304 $this->_packageLayout = $layoutXml;
00305
00306 if (Mage::app()->useCache('layout')) {
00307 Mage::app()->saveCache($this->_packageLayout->asXml(), $cacheKey, $cacheTags, null);
00308 }
00309 }
00310
00311 return $this;
00312 }
00313
00314 public function fetchPackageLayoutUpdates($handle)
00315 {
00316 $_profilerKey = 'layout/package_update: '.$handle;
00317 Varien_Profiler::start($_profilerKey);
00318
00319 if (empty($this->_packageLayout)) {
00320 $this->fetchFileLayoutUpdates();
00321 }
00322 foreach ($this->_packageLayout->$handle as $updateXml) {
00323 #echo '<textarea style="width:600px; height:400px;">'.$handle.':'.print_r($updateXml,1).'</textarea>';
00324 $this->fetchRecursiveUpdates($updateXml);
00325
00326 $this->addUpdate($updateXml->innerXml());
00327 }
00328
00329 Varien_Profiler::stop($_profilerKey);
00330
00331 return true;
00332 }
00333
00334 public function fetchDbLayoutUpdates($handle)
00335 {
00336 $_profilerKey = 'layout/db_update: '.$handle;
00337 Varien_Profiler::start($_profilerKey);
00338
00339 try {
00340 $updateStr = Mage::getResourceModel('core/layout')->fetchUpdatesByHandle($handle);
00341 if (!$updateStr) {
00342 return false;
00343 }
00344 $updateStr = str_replace($this->_subst['from'], $this->_subst['to'], $updateStr);
00345 $updateXml = simplexml_load_string($updateStr, $this->getElementClass());
00346 $this->fetchRecursiveUpdates($updateXml);
00347
00348 $this->addUpdate($update);
00349 } catch (PDOException $e) {
00350 throw $e;
00351 } catch (Exception $e) {
00352
00353 }
00354
00355 Varien_Profiler::stop($_profilerKey);
00356 return true;
00357 }
00358
00359 public function fetchRecursiveUpdates($updateXml)
00360 {
00361 foreach ($updateXml->children() as $child) {
00362 if (strtolower($child->getName())=='update' && isset($child['handle'])) {
00363 $this->merge((string)$child['handle']);
00364 }
00365 }
00366 return $this;
00367 }
00368 }