├── README.md ├── composer.json ├── modman └── src ├── app └── code │ └── local │ └── Mage │ └── Core │ └── Model │ └── App.php └── lib └── Cti └── Cache └── Cache.php /README.md: -------------------------------------------------------------------------------- 1 | ## Configuration Cache Lock 2 | Add the following settings to your local.xml inside the `````` node. 3 | ```xml 4 | 5 | ... 6 | 7 | 1 8 | 127.0.0.1 9 | 6379 10 | 0 11 | 12 | 2.5 13 | cache_lock 14 | 10 15 | 10000000 16 | 17 | 18 | ``` -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ctidigital/configuration-cache-lock", 3 | "description": "Configuration Cache Lock", 4 | "type": "magento-module", 5 | "license": "MIT", 6 | "authors": [ 7 | { 8 | "name": "CTI Digital", 9 | "email": "sales@ctidigital.com" 10 | } 11 | ], 12 | "require": {} 13 | } -------------------------------------------------------------------------------- /modman: -------------------------------------------------------------------------------- 1 | src/app/code/local/Mage/Core/Model/App.php app/code/local/Mage/Core/Model/App.php 2 | src/lib/Cti/Cache/Cache.php lib/Cti/Cache/Cache.php -------------------------------------------------------------------------------- /src/app/code/local/Mage/Core/Model/App.php: -------------------------------------------------------------------------------- 1 | 35 | */ 36 | class Mage_Core_Model_App 37 | { 38 | 39 | const XML_PATH_INSTALL_DATE = 'global/install/date'; 40 | 41 | const XML_PATH_SKIP_PROCESS_MODULES_UPDATES = 'global/skip_process_modules_updates'; 42 | 43 | /** 44 | * if this node set to true, we will ignore Developer Mode for applying updates 45 | */ 46 | const XML_PATH_IGNORE_DEV_MODE = 'global/skip_process_modules_updates_ignore_dev_mode'; 47 | 48 | const DEFAULT_ERROR_HANDLER = 'mageCoreErrorHandler'; 49 | 50 | const DISTRO_LOCALE_CODE = 'en_US'; 51 | 52 | const XML_PATH_CACHE_LOCK_ENABLE = 'global/cache_lock/enable'; 53 | 54 | /** 55 | * Cache tag for all cache data exclude config cache 56 | * 57 | */ 58 | const CACHE_TAG = 'MAGE'; 59 | 60 | /** 61 | * Default store Id (for install) 62 | */ 63 | const DISTRO_STORE_ID = 1; 64 | 65 | /** 66 | * Default store code (for install) 67 | * 68 | */ 69 | const DISTRO_STORE_CODE = 'default'; 70 | 71 | /** 72 | * Admin store Id 73 | * 74 | */ 75 | const ADMIN_STORE_ID = 0; 76 | 77 | /** 78 | * Application loaded areas array 79 | * 80 | * @var array 81 | */ 82 | protected $_areas = array(); 83 | 84 | /** 85 | * Application store object 86 | * 87 | * @var Mage_Core_Model_Store 88 | */ 89 | protected $_store; 90 | 91 | /** 92 | * Application website object 93 | * 94 | * @var Mage_Core_Model_Website 95 | */ 96 | protected $_website; 97 | 98 | /** 99 | * Application location object 100 | * 101 | * @var Mage_Core_Model_Locale 102 | */ 103 | protected $_locale; 104 | 105 | /** 106 | * Application translate object 107 | * 108 | * @var Mage_Core_Model_Translate 109 | */ 110 | protected $_translator; 111 | 112 | /** 113 | * Application design package object 114 | * 115 | * @var Mage_Core_Model_Design_Package 116 | */ 117 | protected $_design; 118 | 119 | /** 120 | * Application layout object 121 | * 122 | * @var Mage_Core_Model_Layout 123 | */ 124 | protected $_layout; 125 | 126 | /** 127 | * Application configuration object 128 | * 129 | * @var Mage_Core_Model_Config 130 | */ 131 | protected $_config; 132 | 133 | /** 134 | * Application front controller 135 | * 136 | * @var Mage_Core_Controller_Varien_Front 137 | */ 138 | protected $_frontController; 139 | 140 | /** 141 | * Cache object 142 | * 143 | * @var Zend_Cache_Core 144 | */ 145 | protected $_cache; 146 | 147 | /** 148 | * Use Cache 149 | * 150 | * @var array 151 | */ 152 | protected $_useCache; 153 | 154 | /** 155 | * Websites cache 156 | * 157 | * @var array 158 | */ 159 | protected $_websites = array(); 160 | 161 | /** 162 | * Groups cache 163 | * 164 | * @var array 165 | */ 166 | protected $_groups = array(); 167 | 168 | /** 169 | * Stores cache 170 | * 171 | * @var array 172 | */ 173 | protected $_stores = array(); 174 | 175 | /** 176 | * is a single store mode 177 | * 178 | * @var bool 179 | */ 180 | protected $_isSingleStore; 181 | 182 | /** 183 | * @var bool 184 | */ 185 | protected $_isSingleStoreAllowed = true; 186 | 187 | /** 188 | * Default store code 189 | * 190 | * @var string 191 | */ 192 | protected $_currentStore; 193 | 194 | /** 195 | * Request object 196 | * 197 | * @var Zend_Controller_Request_Http 198 | */ 199 | protected $_request; 200 | 201 | /** 202 | * Response object 203 | * 204 | * @var Zend_Controller_Response_Http 205 | */ 206 | protected $_response; 207 | 208 | 209 | /** 210 | * Events cache 211 | * 212 | * @var array 213 | */ 214 | protected $_events = array(); 215 | 216 | /** 217 | * Update process run flag 218 | * 219 | * @var bool 220 | */ 221 | protected $_updateMode = false; 222 | 223 | /** 224 | * Use session in URL flag 225 | * 226 | * @see Mage_Core_Model_Url 227 | * @var bool 228 | */ 229 | protected $_useSessionInUrl = true; 230 | 231 | /** 232 | * Use session var instead of SID for session in URL 233 | * 234 | * @var bool 235 | */ 236 | protected $_useSessionVar = false; 237 | 238 | /** 239 | * Cache locked flag 240 | * 241 | * @var null|bool 242 | */ 243 | protected $_isCacheLocked = null; 244 | 245 | /** 246 | * Constructor 247 | */ 248 | public function __construct() 249 | { 250 | } 251 | 252 | /** 253 | * Initialize application without request processing 254 | * 255 | * @param string|array $code 256 | * @param string $type 257 | * @param string|array $options 258 | * @return Mage_Core_Model_App 259 | */ 260 | public function init($code, $type = null, $options = array()) 261 | { 262 | $this->_initEnvironment(); 263 | if (is_string($options)) { 264 | $options = array('etc_dir'=>$options); 265 | } 266 | 267 | Varien_Profiler::start('mage::app::init::config'); 268 | $this->_config = Mage::getConfig(); 269 | $this->_config->setOptions($options); 270 | $this->_initBaseConfig(); 271 | $this->_initCache(); 272 | $this->_config->init($options); 273 | Varien_Profiler::stop('mage::app::init::config'); 274 | 275 | if (Mage::isInstalled($options)) { 276 | $this->_initCurrentStore($code, $type); 277 | $this->_initRequest(); 278 | } 279 | return $this; 280 | } 281 | 282 | /** 283 | * Common logic for all run types 284 | * 285 | * @param string|array $options 286 | * @return Mage_Core_Model_App 287 | */ 288 | public function baseInit($options) 289 | { 290 | $this->_initEnvironment(); 291 | 292 | $this->_config = Mage::getConfig(); 293 | $this->_config->setOptions($options); 294 | 295 | $this->_initBaseConfig(); 296 | $cacheInitOptions = is_array($options) && array_key_exists('cache', $options) ? $options['cache'] : array(); 297 | $this->_initCache($cacheInitOptions); 298 | 299 | return $this; 300 | } 301 | 302 | /** 303 | * Run light version of application with specified modules support 304 | * 305 | * @see Mage_Core_Model_App->run() 306 | * 307 | * @param string|array $scopeCode 308 | * @param string $scopeType 309 | * @param string|array $options 310 | * @param string|array $modules 311 | * @return Mage_Core_Model_App 312 | */ 313 | public function initSpecified($scopeCode, $scopeType = null, $options = array(), $modules = array()) 314 | { 315 | $this->baseInit($options); 316 | 317 | if (!empty($modules)) { 318 | $this->_config->addAllowedModules($modules); 319 | } 320 | $this->_initModules(); 321 | $this->_initCurrentStore($scopeCode, $scopeType); 322 | 323 | return $this; 324 | } 325 | 326 | /** 327 | * Run application. Run process responsible for request processing and sending response. 328 | * List of supported parameters: 329 | * scope_code - code of default scope (website/store_group/store code) 330 | * scope_type - type of default scope (website/group/store) 331 | * options - configuration options 332 | * 333 | * @param array $params application run parameters 334 | * @return Mage_Core_Model_App 335 | */ 336 | public function run($params) 337 | { 338 | $options = isset($params['options']) ? $params['options'] : array(); 339 | $this->baseInit($options); 340 | Mage::register('application_params', $params); 341 | 342 | if ($this->_cache->processRequest()) { 343 | $this->getResponse()->sendResponse(); 344 | } else { 345 | $this->_initModules(); 346 | $this->loadAreaPart(Mage_Core_Model_App_Area::AREA_GLOBAL, Mage_Core_Model_App_Area::PART_EVENTS); 347 | 348 | if ($this->_config->isLocalConfigLoaded()) { 349 | $scopeCode = isset($params['scope_code']) ? $params['scope_code'] : ''; 350 | $scopeType = isset($params['scope_type']) ? $params['scope_type'] : 'store'; 351 | $this->_initCurrentStore($scopeCode, $scopeType); 352 | $this->_initRequest(); 353 | Mage_Core_Model_Resource_Setup::applyAllDataUpdates(); 354 | } 355 | 356 | $this->getFrontController()->dispatch(); 357 | } 358 | return $this; 359 | } 360 | 361 | /** 362 | * Initialize PHP environment 363 | * 364 | * @return Mage_Core_Model_App 365 | */ 366 | protected function _initEnvironment() 367 | { 368 | $this->setErrorHandler(self::DEFAULT_ERROR_HANDLER); 369 | date_default_timezone_set(Mage_Core_Model_Locale::DEFAULT_TIMEZONE); 370 | return $this; 371 | } 372 | 373 | /** 374 | * Initialize base system configuration (local.xml and config.xml files). 375 | * Base configuration provide ability initialize DB connection and cache backend 376 | * 377 | * @return Mage_Core_Model_App 378 | */ 379 | protected function _initBaseConfig() 380 | { 381 | Varien_Profiler::start('mage::app::init::system_config'); 382 | $this->_config->loadBase(); 383 | Varien_Profiler::stop('mage::app::init::system_config'); 384 | return $this; 385 | } 386 | 387 | /** 388 | * Initialize application cache instance 389 | * 390 | * @param array $cacheInitOptions 391 | * @return Mage_Core_Model_App 392 | */ 393 | protected function _initCache(array $cacheInitOptions = array()) 394 | { 395 | $this->_isCacheLocked = true; 396 | $options = $this->_config->getNode('global/cache'); 397 | if ($options) { 398 | $options = $options->asArray(); 399 | } else { 400 | $options = array(); 401 | } 402 | $options = array_merge($options, $cacheInitOptions); 403 | $this->_cache = Mage::getModel('core/cache', $options); 404 | $this->_isCacheLocked = false; 405 | return $this; 406 | } 407 | 408 | /** 409 | * If the cache requires a refresh, set a lock in the specified Redis database. Subsequent requests are then 410 | * retried after a period of time to let the cache regenerate. 411 | * 412 | * @return $this 413 | */ 414 | protected function _initModulesWithLocking () 415 | { 416 | if ($this->_config->loadModulesCache()) { 417 | return $this; 418 | } 419 | 420 | $ctiCache = new Cti_Cache_Cache(); 421 | 422 | // Check if a cache lock has been created 423 | $cacheLock = false; 424 | 425 | // If the cache is currently being regenerated 426 | if ($ctiCache->getIsCacheLocked()) { 427 | $cacheLock = true; 428 | } 429 | 430 | // If the cache needs to be created 431 | if ($cacheLock === false) { 432 | // Create a new cache lock 433 | $ctiCache->acquireCacheLock(); 434 | 435 | $this->_config->loadModules(); 436 | if ($this->_config->isLocalConfigLoaded() && !$this->_shouldSkipProcessModulesUpdates()) { 437 | Varien_Profiler::start('mage::app::init::apply_db_schema_updates'); 438 | Mage_Core_Model_Resource_Setup::applyAllUpdates(); 439 | Varien_Profiler::stop('mage::app::init::apply_db_schema_updates'); 440 | } 441 | $this->_config->loadDb(); 442 | $this->_config->saveCache(); 443 | 444 | // Release the cache lock 445 | $ctiCache->releaseCacheLock(); 446 | 447 | return $this; 448 | } 449 | 450 | // The maximum amount of times to recheck the cache is generated 451 | $maxAttempts = $ctiCache->getMaxAttempts(); 452 | 453 | // Current attempts 454 | $attempts = 0; 455 | 456 | // If the lock is found keep retrying to see if the cache has been generated 457 | while ($cacheLock === true && $attempts < $maxAttempts) { 458 | $attempts++; 459 | usleep($ctiCache->getRetryTime()); 460 | 461 | if ($this->_config->loadModulesCache()) { 462 | return $this; 463 | } 464 | } 465 | // If the maximum amount of attempts has been reached then stop the request 466 | if ($attempts >= $maxAttempts) { 467 | include_once BP . DS . 'errors' . DS . '503.php'; 468 | exit; 469 | } 470 | return $this; 471 | } 472 | 473 | /** 474 | * Initialize active modules configuration and data 475 | * 476 | * @return Mage_Core_Model_App 477 | */ 478 | protected function _initModules() 479 | { 480 | // If cache locking is enabled then use that 481 | if ((bool)(string) $this->_config->getNode(self::XML_PATH_CACHE_LOCK_ENABLE) === true) { 482 | return $this->_initModulesWithLocking(); 483 | } 484 | 485 | if (!$this->_config->loadModulesCache()) { 486 | $this->_config->loadModules(); 487 | if ($this->_config->isLocalConfigLoaded() && !$this->_shouldSkipProcessModulesUpdates()) { 488 | Varien_Profiler::start('mage::app::init::apply_db_schema_updates'); 489 | Mage_Core_Model_Resource_Setup::applyAllUpdates(); 490 | Varien_Profiler::stop('mage::app::init::apply_db_schema_updates'); 491 | } 492 | $this->_config->loadDb(); 493 | $this->_config->saveCache(); 494 | } 495 | return $this; 496 | } 497 | 498 | /** 499 | * Check whether modules updates processing should be skipped 500 | * 501 | * @return bool 502 | */ 503 | protected function _shouldSkipProcessModulesUpdates() 504 | { 505 | if (!Mage::isInstalled()) { 506 | return false; 507 | } 508 | 509 | $ignoreDevelopmentMode = (bool)(string)$this->_config->getNode(self::XML_PATH_IGNORE_DEV_MODE); 510 | if (Mage::getIsDeveloperMode() && !$ignoreDevelopmentMode) { 511 | return false; 512 | } 513 | 514 | return (bool)(string)$this->_config->getNode(self::XML_PATH_SKIP_PROCESS_MODULES_UPDATES); 515 | } 516 | 517 | /** 518 | * Init request object 519 | * 520 | * @return Mage_Core_Model_App 521 | */ 522 | protected function _initRequest() 523 | { 524 | $this->getRequest()->setPathInfo(); 525 | return $this; 526 | } 527 | 528 | /** 529 | * Initialize currently ran store 530 | * 531 | * @param string $scopeCode code of default scope (website/store_group/store code) 532 | * @param string $scopeType type of default scope (website/group/store) 533 | * @return unknown_type 534 | */ 535 | protected function _initCurrentStore($scopeCode, $scopeType) 536 | { 537 | Varien_Profiler::start('mage::app::init::stores'); 538 | $this->_initStores(); 539 | Varien_Profiler::stop('mage::app::init::stores'); 540 | 541 | if (empty($scopeCode) && !is_null($this->_website)) { 542 | $scopeCode = $this->_website->getCode(); 543 | $scopeType = 'website'; 544 | } 545 | switch ($scopeType) { 546 | case 'store': 547 | $this->_currentStore = $scopeCode; 548 | break; 549 | case 'group': 550 | $this->_currentStore = $this->_getStoreByGroup($scopeCode); 551 | break; 552 | case 'website': 553 | $this->_currentStore = $this->_getStoreByWebsite($scopeCode); 554 | break; 555 | default: 556 | $this->throwStoreException(); 557 | } 558 | 559 | if (!empty($this->_currentStore)) { 560 | $this->_checkCookieStore($scopeType); 561 | $this->_checkGetStore($scopeType); 562 | } 563 | $this->_useSessionInUrl = $this->getStore()->getConfig( 564 | Mage_Core_Model_Session_Abstract::XML_PATH_USE_FRONTEND_SID); 565 | return $this; 566 | } 567 | 568 | /** 569 | * Retrieve cookie object 570 | * 571 | * @return Mage_Core_Model_Cookie 572 | */ 573 | public function getCookie() 574 | { 575 | return Mage::getSingleton('core/cookie'); 576 | } 577 | 578 | /** 579 | * Check get store 580 | * 581 | * @return Mage_Core_Model_App 582 | */ 583 | protected function _checkGetStore($type) 584 | { 585 | if (empty($_GET)) { 586 | return $this; 587 | } 588 | 589 | /** 590 | * @todo check XML_PATH_STORE_IN_URL 591 | */ 592 | if (!isset($_GET['___store'])) { 593 | return $this; 594 | } 595 | 596 | $store = $_GET['___store']; 597 | if (!isset($this->_stores[$store])) { 598 | return $this; 599 | } 600 | 601 | $storeObj = $this->_stores[$store]; 602 | if (!$storeObj->getId() || !$storeObj->getIsActive()) { 603 | return $this; 604 | } 605 | 606 | /** 607 | * prevent running a store from another website or store group, 608 | * if website or store group was specified explicitly in Mage::run() 609 | */ 610 | $curStoreObj = $this->_stores[$this->_currentStore]; 611 | if ($type == 'website' && $storeObj->getWebsiteId() == $curStoreObj->getWebsiteId()) { 612 | $this->_currentStore = $store; 613 | } 614 | elseif ($type == 'group' && $storeObj->getGroupId() == $curStoreObj->getGroupId()) { 615 | $this->_currentStore = $store; 616 | } 617 | elseif ($type == 'store') { 618 | $this->_currentStore = $store; 619 | } 620 | 621 | if ($this->_currentStore == $store) { 622 | $store = $this->getStore($store); 623 | if ($store->getWebsite()->getDefaultStore()->getId() == $store->getId()) { 624 | $this->getCookie()->delete(Mage_Core_Model_Store::COOKIE_NAME); 625 | } else { 626 | $this->getCookie()->set(Mage_Core_Model_Store::COOKIE_NAME, $this->_currentStore, true); 627 | } 628 | } 629 | return $this; 630 | } 631 | 632 | /** 633 | * Check cookie store 634 | * 635 | * @param string $type 636 | * @return Mage_Core_Model_App 637 | */ 638 | protected function _checkCookieStore($type) 639 | { 640 | if (!$this->getCookie()->get()) { 641 | return $this; 642 | } 643 | 644 | $store = $this->getCookie()->get(Mage_Core_Model_Store::COOKIE_NAME); 645 | if ($store && isset($this->_stores[$store]) 646 | && $this->_stores[$store]->getId() 647 | && $this->_stores[$store]->getIsActive()) { 648 | if ($type == 'website' 649 | && $this->_stores[$store]->getWebsiteId() == $this->_stores[$this->_currentStore]->getWebsiteId()) { 650 | $this->_currentStore = $store; 651 | } 652 | if ($type == 'group' 653 | && $this->_stores[$store]->getGroupId() == $this->_stores[$this->_currentStore]->getGroupId()) { 654 | $this->_currentStore = $store; 655 | } 656 | if ($type == 'store') { 657 | $this->_currentStore = $store; 658 | } 659 | } 660 | return $this; 661 | } 662 | 663 | public function reinitStores() 664 | { 665 | return $this->_initStores(); 666 | } 667 | 668 | /** 669 | * Init store, group and website collections 670 | * 671 | */ 672 | protected function _initStores() 673 | { 674 | $this->_stores = array(); 675 | $this->_groups = array(); 676 | $this->_website = null; 677 | $this->_websites = array(); 678 | 679 | /** @var $websiteCollection Mage_Core_Model_Website */ 680 | $websiteCollection = Mage::getModel('core/website')->getCollection() 681 | ->initCache($this->getCache(), 'app', array(Mage_Core_Model_Website::CACHE_TAG)) 682 | ->setLoadDefault(true); 683 | 684 | /** @var $websiteCollection Mage_Core_Model_Store_Group */ 685 | $groupCollection = Mage::getModel('core/store_group')->getCollection() 686 | ->initCache($this->getCache(), 'app', array(Mage_Core_Model_Store_Group::CACHE_TAG)) 687 | ->setLoadDefault(true); 688 | 689 | /** @var $websiteCollection Mage_Core_Model_Store */ 690 | $storeCollection = Mage::getModel('core/store')->getCollection() 691 | ->initCache($this->getCache(), 'app', array(Mage_Core_Model_Store::CACHE_TAG)) 692 | ->setLoadDefault(true); 693 | 694 | $this->_isSingleStore = false; 695 | if ($this->_isSingleStoreAllowed) { 696 | $this->_isSingleStore = $storeCollection->count() < 3; 697 | } 698 | 699 | $websiteStores = array(); 700 | $websiteGroups = array(); 701 | $groupStores = array(); 702 | 703 | foreach ($storeCollection as $store) { 704 | /** @var $store Mage_Core_Model_Store */ 705 | $store->initConfigCache(); 706 | $store->setWebsite($websiteCollection->getItemById($store->getWebsiteId())); 707 | $store->setGroup($groupCollection->getItemById($store->getGroupId())); 708 | 709 | $this->_stores[$store->getId()] = $store; 710 | $this->_stores[$store->getCode()] = $store; 711 | 712 | $websiteStores[$store->getWebsiteId()][$store->getId()] = $store; 713 | $groupStores[$store->getGroupId()][$store->getId()] = $store; 714 | 715 | if (is_null($this->_store) && $store->getId()) { 716 | $this->_store = $store; 717 | } 718 | } 719 | 720 | foreach ($groupCollection as $group) { 721 | /* @var $group Mage_Core_Model_Store_Group */ 722 | if (!isset($groupStores[$group->getId()])) { 723 | $groupStores[$group->getId()] = array(); 724 | } 725 | $group->setStores($groupStores[$group->getId()]); 726 | $group->setWebsite($websiteCollection->getItemById($group->getWebsiteId())); 727 | 728 | $websiteGroups[$group->getWebsiteId()][$group->getId()] = $group; 729 | 730 | $this->_groups[$group->getId()] = $group; 731 | } 732 | 733 | foreach ($websiteCollection as $website) { 734 | /* @var $website Mage_Core_Model_Website */ 735 | if (!isset($websiteGroups[$website->getId()])) { 736 | $websiteGroups[$website->getId()] = array(); 737 | } 738 | if (!isset($websiteStores[$website->getId()])) { 739 | $websiteStores[$website->getId()] = array(); 740 | } 741 | if ($website->getIsDefault()) { 742 | $this->_website = $website; 743 | } 744 | $website->setGroups($websiteGroups[$website->getId()]); 745 | $website->setStores($websiteStores[$website->getId()]); 746 | 747 | $this->_websites[$website->getId()] = $website; 748 | $this->_websites[$website->getCode()] = $website; 749 | } 750 | } 751 | 752 | /** 753 | * Is single Store mode (only one store without default) 754 | * 755 | * @return bool 756 | */ 757 | public function isSingleStoreMode() 758 | { 759 | if (!Mage::isInstalled()) { 760 | return false; 761 | } 762 | return $this->_isSingleStore; 763 | } 764 | 765 | /** 766 | * Retrieve store code or null by store group 767 | * 768 | * @param int $group 769 | * @return string|null 770 | */ 771 | protected function _getStoreByGroup($group) 772 | { 773 | if (!isset($this->_groups[$group])) { 774 | return null; 775 | } 776 | if (!$this->_groups[$group]->getDefaultStoreId()) { 777 | return null; 778 | } 779 | return $this->_stores[$this->_groups[$group]->getDefaultStoreId()]->getCode(); 780 | } 781 | 782 | /** 783 | * Retrieve store code or null by website 784 | * 785 | * @param int|string $website 786 | * @return string|null 787 | */ 788 | protected function _getStoreByWebsite($website) 789 | { 790 | if (!isset($this->_websites[$website])) { 791 | return null; 792 | } 793 | if (!$this->_websites[$website]->getDefaultGroupId()) { 794 | return null; 795 | } 796 | return $this->_getStoreByGroup($this->_websites[$website]->getDefaultGroupId()); 797 | } 798 | 799 | /** 800 | * Set current default store 801 | * 802 | * @param string $store 803 | * @return Mage_Core_Model_App 804 | */ 805 | public function setCurrentStore($store) 806 | { 807 | $this->_currentStore = $store; 808 | return $this; 809 | } 810 | 811 | /** 812 | * Initialize application front controller 813 | * 814 | * @return Mage_Core_Model_App 815 | */ 816 | protected function _initFrontController() 817 | { 818 | $this->_frontController = new Mage_Core_Controller_Varien_Front(); 819 | Mage::register('controller', $this->_frontController); 820 | Varien_Profiler::start('mage::app::init_front_controller'); 821 | $this->_frontController->init(); 822 | Varien_Profiler::stop('mage::app::init_front_controller'); 823 | return $this; 824 | } 825 | 826 | /** 827 | * Redeclare custom error handler 828 | * 829 | * @param string $handler 830 | * @return Mage_Core_Model_App 831 | */ 832 | public function setErrorHandler($handler) 833 | { 834 | set_error_handler($handler); 835 | return $this; 836 | } 837 | 838 | /** 839 | * Loading application area 840 | * 841 | * @param string $code 842 | * @return Mage_Core_Model_App 843 | */ 844 | public function loadArea($code) 845 | { 846 | $this->getArea($code)->load(); 847 | return $this; 848 | } 849 | 850 | /** 851 | * Loding part of area data 852 | * 853 | * @param string $area 854 | * @param string $part 855 | * @return Mage_Core_Model_App 856 | */ 857 | public function loadAreaPart($area, $part) 858 | { 859 | $this->getArea($area)->load($part); 860 | return $this; 861 | } 862 | 863 | /** 864 | * Retrieve application area 865 | * 866 | * @param string $code 867 | * @return Mage_Core_Model_App_Area 868 | */ 869 | public function getArea($code) 870 | { 871 | if (!isset($this->_areas[$code])) { 872 | $this->_areas[$code] = new Mage_Core_Model_App_Area($code, $this); 873 | } 874 | return $this->_areas[$code]; 875 | } 876 | 877 | /** 878 | * Retrieve application store object 879 | * 880 | * @param null|string|bool|int|Mage_Core_Model_Store $id 881 | * @return Mage_Core_Model_Store 882 | * @throws Mage_Core_Model_Store_Exception 883 | */ 884 | public function getStore($id = null) 885 | { 886 | if (!Mage::isInstalled() || $this->getUpdateMode()) { 887 | return $this->_getDefaultStore(); 888 | } 889 | 890 | if ($id === true && $this->isSingleStoreMode()) { 891 | return $this->_store; 892 | } 893 | 894 | if (!isset($id) || ''===$id || $id === true) { 895 | $id = $this->_currentStore; 896 | } 897 | if ($id instanceof Mage_Core_Model_Store) { 898 | return $id; 899 | } 900 | if (!isset($id)) { 901 | $this->throwStoreException(); 902 | } 903 | 904 | if (empty($this->_stores[$id])) { 905 | $store = Mage::getModel('core/store'); 906 | /* @var $store Mage_Core_Model_Store */ 907 | if (is_numeric($id)) { 908 | $store->load($id); 909 | } elseif (is_string($id)) { 910 | $store->load($id, 'code'); 911 | } 912 | 913 | if (!$store->getCode()) { 914 | $this->throwStoreException(); 915 | } 916 | $this->_stores[$store->getStoreId()] = $store; 917 | $this->_stores[$store->getCode()] = $store; 918 | } 919 | return $this->_stores[$id]; 920 | } 921 | 922 | /** 923 | * Retrieve application store object without Store_Exception 924 | * 925 | * @param string|int|Mage_Core_Model_Store $id 926 | * @return Mage_Core_Model_Store 927 | */ 928 | public function getSafeStore($id = null) 929 | { 930 | try { 931 | return $this->getStore($id); 932 | } 933 | catch (Exception $e) { 934 | if ($this->_currentStore) { 935 | $this->getRequest()->setActionName('noRoute'); 936 | return new Varien_Object(); 937 | } 938 | else { 939 | Mage::throwException(Mage::helper('core')->__('Requested invalid store "%s"', $id)); 940 | } 941 | } 942 | } 943 | 944 | /** 945 | * Retrieve stores array 946 | * 947 | * @param bool $withDefault 948 | * @param bool $codeKey 949 | * @return array 950 | */ 951 | public function getStores($withDefault = false, $codeKey = false) 952 | { 953 | $stores = array(); 954 | foreach ($this->_stores as $store) { 955 | if (!$withDefault && $store->getId() == 0) { 956 | continue; 957 | } 958 | if ($codeKey) { 959 | $stores[$store->getCode()] = $store; 960 | } 961 | else { 962 | $stores[$store->getId()] = $store; 963 | } 964 | } 965 | 966 | return $stores; 967 | } 968 | 969 | protected function _getDefaultStore() 970 | { 971 | if (empty($this->_store)) { 972 | $this->_store = Mage::getModel('core/store') 973 | ->setId(self::DISTRO_STORE_ID) 974 | ->setCode(self::DISTRO_STORE_CODE); 975 | } 976 | return $this->_store; 977 | } 978 | 979 | /** 980 | * Retrieve default store for default group and website 981 | * 982 | * @return Mage_Core_Model_Store 983 | */ 984 | public function getDefaultStoreView() 985 | { 986 | foreach ($this->getWebsites() as $_website) { 987 | if ($_website->getIsDefault()) { 988 | $_defaultStore = $this->getGroup($_website->getDefaultGroupId())->getDefaultStore(); 989 | if ($_defaultStore) { 990 | return $_defaultStore; 991 | } 992 | } 993 | } 994 | return null; 995 | } 996 | 997 | public function getDistroLocaleCode() 998 | { 999 | return self::DISTRO_LOCALE_CODE; 1000 | } 1001 | 1002 | /** 1003 | * Retrieve application website object 1004 | * 1005 | * @return Mage_Core_Model_Website 1006 | */ 1007 | public function getWebsite($id=null) 1008 | { 1009 | if (is_null($id)) { 1010 | $id = $this->getStore()->getWebsiteId(); 1011 | } elseif ($id instanceof Mage_Core_Model_Website) { 1012 | return $id; 1013 | } elseif ($id === true) { 1014 | return $this->_website; 1015 | } 1016 | 1017 | if (empty($this->_websites[$id])) { 1018 | $website = Mage::getModel('core/website'); 1019 | if (is_numeric($id)) { 1020 | $website->load($id); 1021 | if (!$website->hasWebsiteId()) { 1022 | throw Mage::exception('Mage_Core', 'Invalid website id requested.'); 1023 | } 1024 | } elseif (is_string($id)) { 1025 | $websiteConfig = $this->_config->getNode('websites/'.$id); 1026 | if (!$websiteConfig) { 1027 | throw Mage::exception('Mage_Core', 'Invalid website code requested: '.$id); 1028 | } 1029 | $website->loadConfig($id); 1030 | } 1031 | $this->_websites[$website->getWebsiteId()] = $website; 1032 | $this->_websites[$website->getCode()] = $website; 1033 | } 1034 | return $this->_websites[$id]; 1035 | } 1036 | 1037 | public function getWebsites($withDefault = false, $codeKey = false) 1038 | { 1039 | $websites = array(); 1040 | if (is_array($this->_websites)) { 1041 | foreach ($this->_websites as $website) { 1042 | if (!$withDefault && $website->getId() == 0) { 1043 | continue; 1044 | } 1045 | if ($codeKey) { 1046 | $websites[$website->getCode()] = $website; 1047 | } 1048 | else { 1049 | $websites[$website->getId()] = $website; 1050 | } 1051 | } 1052 | } 1053 | 1054 | return $websites; 1055 | } 1056 | 1057 | /** 1058 | * Retrieve application store group object 1059 | * 1060 | * @return Mage_Core_Model_Store_Group 1061 | */ 1062 | public function getGroup($id=null) 1063 | { 1064 | if (is_null($id)) { 1065 | $id = $this->getStore()->getGroup()->getId(); 1066 | } elseif ($id instanceof Mage_Core_Model_Store_Group) { 1067 | return $id; 1068 | } 1069 | if (empty($this->_groups[$id])) { 1070 | $group = Mage::getModel('core/store_group'); 1071 | if (is_numeric($id)) { 1072 | $group->load($id); 1073 | if (!$group->hasGroupId()) { 1074 | throw Mage::exception('Mage_Core', 'Invalid store group id requested.'); 1075 | } 1076 | } 1077 | $this->_groups[$group->getGroupId()] = $group; 1078 | } 1079 | return $this->_groups[$id]; 1080 | } 1081 | 1082 | /** 1083 | * Retrieve application locale object 1084 | * 1085 | * @return Mage_Core_Model_Locale 1086 | */ 1087 | public function getLocale() 1088 | { 1089 | if (!$this->_locale) { 1090 | $this->_locale = Mage::getSingleton('core/locale'); 1091 | } 1092 | return $this->_locale; 1093 | } 1094 | 1095 | /** 1096 | * Retrive layout object 1097 | * 1098 | * @return Mage_Core_Model_Layout 1099 | */ 1100 | public function getLayout() 1101 | { 1102 | if (!$this->_layout) { 1103 | if ($this->getFrontController()->getAction()) { 1104 | $this->_layout = $this->getFrontController()->getAction()->getLayout(); 1105 | } else { 1106 | $this->_layout = Mage::getSingleton('core/layout'); 1107 | } 1108 | } 1109 | return $this->_layout; 1110 | } 1111 | 1112 | /** 1113 | * Retrieve translate object 1114 | * 1115 | * @return Mage_Core_Model_Translate 1116 | */ 1117 | public function getTranslator() 1118 | { 1119 | if (!$this->_translator) { 1120 | $this->_translator = Mage::getSingleton('core/translate'); 1121 | } 1122 | return $this->_translator; 1123 | } 1124 | 1125 | /** 1126 | * Retrieve helper object 1127 | * 1128 | * @param string $name 1129 | * @return Mage_Core_Helper_Abstract 1130 | */ 1131 | public function getHelper($name) 1132 | { 1133 | return Mage::helper($name); 1134 | } 1135 | 1136 | /** 1137 | * Retrieve application base currency code 1138 | * 1139 | * @return string 1140 | */ 1141 | public function getBaseCurrencyCode() 1142 | { 1143 | //return Mage::getStoreConfig(Mage_Directory_Model_Currency::XML_PATH_CURRENCY_BASE, 0); 1144 | return (string) Mage::app()->getConfig() 1145 | ->getNode('default/' . Mage_Directory_Model_Currency::XML_PATH_CURRENCY_BASE); 1146 | } 1147 | 1148 | /** 1149 | * Retrieve configuration object 1150 | * 1151 | * @return Mage_Core_Model_Config 1152 | */ 1153 | public function getConfig() 1154 | { 1155 | return $this->_config; 1156 | } 1157 | 1158 | /** 1159 | * Retrieve front controller object 1160 | * 1161 | * @return Mage_Core_Controller_Varien_Front 1162 | */ 1163 | public function getFrontController() 1164 | { 1165 | if (!$this->_frontController) { 1166 | $this->_initFrontController(); 1167 | } 1168 | 1169 | return $this->_frontController; 1170 | } 1171 | 1172 | /** 1173 | * Get core cache model 1174 | * 1175 | * @return Mage_Core_Model_Cache 1176 | */ 1177 | public function getCacheInstance() 1178 | { 1179 | if (!$this->_cache) { 1180 | $this->_initCache(); 1181 | } 1182 | return $this->_cache; 1183 | } 1184 | 1185 | /** 1186 | * Retrieve cache object 1187 | * 1188 | * @return Zend_Cache_Core 1189 | */ 1190 | public function getCache() 1191 | { 1192 | if (!$this->_cache) { 1193 | $this->_initCache(); 1194 | } 1195 | return $this->_cache->getFrontend(); 1196 | } 1197 | 1198 | /** 1199 | * Loading cache data 1200 | * 1201 | * @param string $id 1202 | * @return mixed 1203 | */ 1204 | public function loadCache($id) 1205 | { 1206 | return $this->_cache->load($id); 1207 | } 1208 | 1209 | /** 1210 | * Saving cache data 1211 | * 1212 | * @param mixed $data 1213 | * @param string $id 1214 | * @param array $tags 1215 | * @return Mage_Core_Model_App 1216 | */ 1217 | public function saveCache($data, $id, $tags=array(), $lifeTime=false) 1218 | { 1219 | $this->_cache->save($data, $id, $tags, $lifeTime); 1220 | return $this; 1221 | } 1222 | 1223 | /** 1224 | * Remove cache 1225 | * 1226 | * @param string $id 1227 | * @return Mage_Core_Model_App 1228 | */ 1229 | public function removeCache($id) 1230 | { 1231 | $this->_cache->remove($id); 1232 | return $this; 1233 | } 1234 | 1235 | /** 1236 | * Cleaning cache 1237 | * 1238 | * @param array $tags 1239 | * @return Mage_Core_Model_App 1240 | */ 1241 | public function cleanCache($tags=array()) 1242 | { 1243 | $this->_cache->clean($tags); 1244 | Mage::dispatchEvent('application_clean_cache', array('tags' => $tags)); 1245 | return $this; 1246 | } 1247 | 1248 | /** 1249 | * Check whether to use cache for specific component 1250 | * 1251 | * @return boolean 1252 | */ 1253 | public function useCache($type=null) 1254 | { 1255 | return $this->_cache->canUse($type); 1256 | } 1257 | 1258 | /** 1259 | * Save cache usage settings 1260 | * 1261 | * @param array $data 1262 | * @return Mage_Core_Model_App 1263 | */ 1264 | public function saveUseCache($data) 1265 | { 1266 | $this->_cache->saveOptions($data); 1267 | return $this; 1268 | } 1269 | 1270 | /** 1271 | * Deletes all session files 1272 | * 1273 | */ 1274 | public function cleanAllSessions() 1275 | { 1276 | if (session_module_name()=='files') { 1277 | $dir = session_save_path(); 1278 | mageDelTree($dir); 1279 | } 1280 | return $this; 1281 | } 1282 | 1283 | /** 1284 | * Retrieve request object 1285 | * 1286 | * @return Mage_Core_Controller_Request_Http 1287 | */ 1288 | public function getRequest() 1289 | { 1290 | if (empty($this->_request)) { 1291 | $this->_request = new Mage_Core_Controller_Request_Http(); 1292 | } 1293 | return $this->_request; 1294 | } 1295 | 1296 | /** 1297 | * Request setter 1298 | * 1299 | * @param Mage_Core_Controller_Request_Http $request 1300 | * @return Mage_Core_Model_App 1301 | */ 1302 | public function setRequest(Mage_Core_Controller_Request_Http $request) 1303 | { 1304 | $this->_request = $request; 1305 | return $this; 1306 | } 1307 | 1308 | /** 1309 | * Retrieve response object 1310 | * 1311 | * @return Zend_Controller_Response_Http 1312 | */ 1313 | public function getResponse() 1314 | { 1315 | if (empty($this->_response)) { 1316 | $this->_response = new Mage_Core_Controller_Response_Http(); 1317 | $this->_response->headersSentThrowsException = Mage::$headersSentThrowsException; 1318 | $this->_response->setHeader("Content-Type", "text/html; charset=UTF-8"); 1319 | } 1320 | return $this->_response; 1321 | } 1322 | 1323 | /** 1324 | * Response setter 1325 | * 1326 | * @param Mage_Core_Controller_Response_Http $response 1327 | * @return Mage_Core_Model_App 1328 | */ 1329 | public function setResponse(Mage_Core_Controller_Response_Http $response) 1330 | { 1331 | $this->_response = $response; 1332 | return $this; 1333 | } 1334 | 1335 | public function addEventArea($area) 1336 | { 1337 | if (!isset($this->_events[$area])) { 1338 | $this->_events[$area] = array(); 1339 | } 1340 | return $this; 1341 | } 1342 | 1343 | public function dispatchEvent($eventName, $args) 1344 | { 1345 | foreach ($this->_events as $area=>$events) { 1346 | if (!isset($events[$eventName])) { 1347 | $eventConfig = $this->getConfig()->getEventConfig($area, $eventName); 1348 | if (!$eventConfig) { 1349 | $this->_events[$area][$eventName] = false; 1350 | continue; 1351 | } 1352 | $observers = array(); 1353 | foreach ($eventConfig->observers->children() as $obsName=>$obsConfig) { 1354 | $observers[$obsName] = array( 1355 | 'type' => (string)$obsConfig->type, 1356 | 'model' => $obsConfig->class ? (string)$obsConfig->class : $obsConfig->getClassName(), 1357 | 'method'=> (string)$obsConfig->method, 1358 | 'args' => (array)$obsConfig->args, 1359 | ); 1360 | } 1361 | $events[$eventName]['observers'] = $observers; 1362 | $this->_events[$area][$eventName]['observers'] = $observers; 1363 | } 1364 | if (false===$events[$eventName]) { 1365 | continue; 1366 | } else { 1367 | $event = new Varien_Event($args); 1368 | $event->setName($eventName); 1369 | $observer = new Varien_Event_Observer(); 1370 | } 1371 | 1372 | foreach ($events[$eventName]['observers'] as $obsName=>$obs) { 1373 | $observer->setData(array('event'=>$event)); 1374 | Varien_Profiler::start('OBSERVER: '.$obsName); 1375 | switch ($obs['type']) { 1376 | case 'disabled': 1377 | break; 1378 | case 'object': 1379 | case 'model': 1380 | $method = $obs['method']; 1381 | $observer->addData($args); 1382 | $object = Mage::getModel($obs['model']); 1383 | $this->_callObserverMethod($object, $method, $observer); 1384 | break; 1385 | default: 1386 | $method = $obs['method']; 1387 | $observer->addData($args); 1388 | $object = Mage::getSingleton($obs['model']); 1389 | $this->_callObserverMethod($object, $method, $observer); 1390 | break; 1391 | } 1392 | Varien_Profiler::stop('OBSERVER: '.$obsName); 1393 | } 1394 | } 1395 | return $this; 1396 | } 1397 | 1398 | /** 1399 | * Performs non-existent observer method calls protection 1400 | * 1401 | * @param object $object 1402 | * @param string $method 1403 | * @param Varien_Event_Observer $observer 1404 | * @return Mage_Core_Model_App 1405 | * @throws Mage_Core_Exception 1406 | */ 1407 | protected function _callObserverMethod($object, $method, $observer) 1408 | { 1409 | if (method_exists($object, $method)) { 1410 | $object->$method($observer); 1411 | } elseif (Mage::getIsDeveloperMode()) { 1412 | Mage::throwException('Method "'.$method.'" is not defined in "'.get_class($object).'"'); 1413 | } 1414 | return $this; 1415 | } 1416 | 1417 | public function setUpdateMode($value) 1418 | { 1419 | $this->_updateMode = $value; 1420 | } 1421 | 1422 | public function getUpdateMode() 1423 | { 1424 | return $this->_updateMode; 1425 | } 1426 | 1427 | public function throwStoreException() 1428 | { 1429 | throw new Mage_Core_Model_Store_Exception(''); 1430 | } 1431 | 1432 | /** 1433 | * Set use session var instead of SID for URL 1434 | * 1435 | * @param bool $var 1436 | * @return Mage_Core_Model_App 1437 | */ 1438 | public function setUseSessionVar($var) 1439 | { 1440 | $this->_useSessionVar = (bool)$var; 1441 | return $this; 1442 | } 1443 | 1444 | /** 1445 | * Retrieve use flag session var instead of SID for URL 1446 | * 1447 | * @return bool 1448 | */ 1449 | public function getUseSessionVar() 1450 | { 1451 | return $this->_useSessionVar; 1452 | } 1453 | 1454 | /** 1455 | * Get either default or any store view 1456 | * 1457 | * @return Mage_Core_Model_Store 1458 | */ 1459 | public function getAnyStoreView() 1460 | { 1461 | $store = $this->getDefaultStoreView(); 1462 | if ($store) { 1463 | return $store; 1464 | } 1465 | foreach ($this->getStores() as $store) { 1466 | return $store; 1467 | } 1468 | } 1469 | 1470 | /** 1471 | * Set Use session in URL flag 1472 | * 1473 | * @param bool $flag 1474 | * @return Mage_Core_Model_App 1475 | */ 1476 | public function setUseSessionInUrl($flag = true) 1477 | { 1478 | $this->_useSessionInUrl = (bool)$flag; 1479 | return $this; 1480 | } 1481 | 1482 | /** 1483 | * Retrieve use session in URL flag 1484 | * 1485 | * @return bool 1486 | */ 1487 | public function getUseSessionInUrl() 1488 | { 1489 | return $this->_useSessionInUrl; 1490 | } 1491 | 1492 | /** 1493 | * Allow or disallow single store mode 1494 | * 1495 | * @param bool $value 1496 | * @return Mage_Core_Model_App 1497 | */ 1498 | public function setIsSingleStoreModeAllowed($value) 1499 | { 1500 | $this->_isSingleStoreAllowed = (bool)$value; 1501 | return $this; 1502 | } 1503 | 1504 | /** 1505 | * Prepare array of store groups 1506 | * can be filtered to contain default store group or not by $withDefault flag 1507 | * depending on flag $codeKey array keys can be group id or group code 1508 | * 1509 | * @param bool $withDefault 1510 | * @param bool $codeKey 1511 | * @return array 1512 | */ 1513 | public function getGroups($withDefault = false, $codeKey = false) 1514 | { 1515 | $groups = array(); 1516 | if (is_array($this->_groups)) { 1517 | foreach ($this->_groups as $group) { 1518 | if (!$withDefault && $group->getId() == 0) { 1519 | continue; 1520 | } 1521 | if ($codeKey) { 1522 | $groups[$group->getCode()] = $group; 1523 | } 1524 | else { 1525 | $groups[$group->getId()] = $group; 1526 | } 1527 | } 1528 | } 1529 | 1530 | return $groups; 1531 | } 1532 | 1533 | 1534 | 1535 | 1536 | /** 1537 | * Retrieve application installation flag 1538 | * 1539 | * @deprecated since 1.2 1540 | * @return bool 1541 | */ 1542 | public function isInstalled() 1543 | { 1544 | return Mage::isInstalled(); 1545 | } 1546 | 1547 | /** 1548 | * Generate cache tags from cache id 1549 | * 1550 | * @deprecated after 1.4.0.0-alpha3, functionality implemented in Mage_Core_Model_Cache 1551 | * @param string $id 1552 | * @param array $tags 1553 | * @return array 1554 | */ 1555 | protected function _getCacheTags($tags=array()) 1556 | { 1557 | foreach ($tags as $index=>$value) { 1558 | $tags[$index] = $this->_getCacheId($value); 1559 | } 1560 | return $tags; 1561 | } 1562 | 1563 | /** 1564 | * Get file name with cache configuration settings 1565 | * 1566 | * @deprecated after 1.4.0.0-alpha3, functionality implemented in Mage_Core_Model_Cache 1567 | * @return string 1568 | */ 1569 | public function getUseCacheFilename() 1570 | { 1571 | return $this->_config->getOptions()->getEtcDir().DS.'use_cache.ser'; 1572 | } 1573 | 1574 | /** 1575 | * Generate cache id with application specific data 1576 | * 1577 | * @deprecated after 1.4.0.0-alpha3, functionality implemented in Mage_Core_Model_Cache 1578 | * @param string $id 1579 | * @return string 1580 | */ 1581 | protected function _getCacheId($id=null) 1582 | { 1583 | if ($id) { 1584 | $id = $this->prepareCacheId($id); 1585 | } 1586 | return $id; 1587 | } 1588 | 1589 | /** 1590 | * Prepare identifier which can be used as cache id or cache tag 1591 | * 1592 | * @deprecated after 1.4.0.0-alpha3, functionality implemented in Mage_Core_Model_Cache 1593 | * @param string $id 1594 | * @return string 1595 | */ 1596 | public function prepareCacheId($id) 1597 | { 1598 | $id = strtoupper($id); 1599 | $id = preg_replace('/([^a-zA-Z0-9_]{1,1})/', '_', $id); 1600 | return $id; 1601 | } 1602 | 1603 | /** 1604 | * Get is cache locked 1605 | * 1606 | * @return bool 1607 | */ 1608 | public function getIsCacheLocked() 1609 | { 1610 | return (bool)$this->_isCacheLocked; 1611 | } 1612 | 1613 | /** 1614 | * Unset website by id from app cache 1615 | * 1616 | * @param null|bool|int|string|Mage_Core_Model_Website $id 1617 | * @return void 1618 | */ 1619 | public function clearWebsiteCache($id = null) 1620 | { 1621 | if (is_null($id)) { 1622 | $id = $this->getStore()->getWebsiteId(); 1623 | } elseif ($id instanceof Mage_Core_Model_Website) { 1624 | $id = $id->getId(); 1625 | } elseif ($id === true) { 1626 | $id = $this->_website->getId(); 1627 | } 1628 | 1629 | if (!empty($this->_websites[$id])) { 1630 | $website = $this->_websites[$id]; 1631 | 1632 | unset($this->_websites[$website->getWebsiteId()]); 1633 | unset($this->_websites[$website->getCode()]); 1634 | } 1635 | } 1636 | } 1637 | -------------------------------------------------------------------------------- /src/lib/Cti/Cache/Cache.php: -------------------------------------------------------------------------------- 1 | 8 | */ 9 | class Cti_Cache_Cache 10 | { 11 | // Whether Redis can be used 12 | private $_useRedis; 13 | // Redis instance to make requests 14 | private $_redis; 15 | // Redis database to store the flag 16 | private $_redisDatabase; 17 | // Maximum amount of attempts to reload the request 18 | private $_maxAttempts = 10; 19 | // The time between retries in microseconds (defaults to 10 seconds) 20 | private $_retryTime = 10000000; 21 | // The key to store in the redis database 22 | private $_cacheKey = 'cache_lock'; 23 | 24 | public function __construct () 25 | { 26 | // Get the local XML file 27 | $localXml = realpath(dirname(__FILE__)).DS.'..'.DS.'..'.DS.'..'.DS.'app'.DS.'etc'.DS.'local.xml'; 28 | 29 | try { 30 | if (!file_exists($localXml)) { 31 | throw new Exception('local.xml could not be found'); 32 | } 33 | 34 | $xml = simplexml_load_file($localXml); 35 | 36 | // Redis connection details 37 | $server = (string) $xml->global->cache_lock->server; 38 | $port = (string) $xml->global->cache_lock->port; 39 | $this->_redisDatabase = (int) $xml->global->cache_lock->database; 40 | $password = (string) $xml->global->cache_lock->password; 41 | $timeout = null; 42 | $persistent = ''; 43 | 44 | if (isset($xml->global->cache_lock->timeout)) { 45 | $timeout = (float) $xml->global->cache_lock->timeout; 46 | } 47 | 48 | if (isset($xml->global->cache_lock->persistent)) { 49 | $persistent = (string) $xml->global->cache_lock->persistent; 50 | } 51 | 52 | if (isset($xml->global->cache_lock->max_attempts)) { 53 | $this->_maxAttempts = (int) $xml->global->cache_lock->max_attempts; 54 | } 55 | 56 | if (isset($xml->global->cache_lock->retry_time)) { 57 | $this->_retryTime = (int) $xml->global->cache_lock->retry_time; 58 | } 59 | 60 | if (isset($xml->global->cache_lock->cache_key)) { 61 | $this->_cacheKey = (string) $xml->global->cache_lock->cache_key; 62 | } 63 | 64 | // Create a new Redis client 65 | $this->_redis = new Credis_Client($server, $port, $timeout, $persistent); 66 | 67 | if (!empty($password)) { 68 | $this->_redis->auth($password); 69 | } 70 | 71 | $this->_redis->setCloseOnDestruct(FALSE); 72 | 73 | $this->_useRedis = true; 74 | } catch (Exception $e) { 75 | Mage::logException($e); 76 | } 77 | } 78 | 79 | /** 80 | * Gets a redis key and value from the database 81 | * 82 | * @param null $key 83 | * @return bool 84 | */ 85 | private function _getRedis ($key = null) 86 | { 87 | try { 88 | if ($this->_useRedis === false) { 89 | throw new Exception('Cannot connect to Redis.'); 90 | } 91 | if (is_null($key)) { 92 | throw new Exception('No key was specified'); 93 | } 94 | $pipeline = $this->_redis->pipeline() 95 | ->select($this->_redisDatabase) 96 | ->get($key) 97 | ->exec(); 98 | 99 | if (is_array($pipeline)) { 100 | return $pipeline; 101 | } 102 | } catch (Exception $e) { 103 | Mage::logException($e); 104 | } 105 | 106 | return false; 107 | } 108 | 109 | /** 110 | * Sets the value of a key in Redis 111 | * 112 | * @param null $key 113 | * @param null $value 114 | * 115 | * @return bool 116 | */ 117 | private function _setRedis ($key = null, $value = null) 118 | { 119 | try { 120 | if ($this->_useRedis === false) { 121 | throw new Exception('Cannot connect to Redis.'); 122 | } 123 | if (is_null($key)) { 124 | throw new Exception('No key was specified.'); 125 | } 126 | if (is_null($value)) { 127 | throw new Exception('No value was specified.'); 128 | } 129 | 130 | $this->_redis->pipeline() 131 | ->select($this->_redisDatabase) 132 | ->set($key, $value) 133 | ->exec(); 134 | 135 | return true; 136 | } catch (Exception $e) { 137 | Mage::logException($e); 138 | } 139 | 140 | return false; 141 | } 142 | 143 | /** 144 | * Enables the cache lock in Redis 145 | * 146 | * @return bool 147 | */ 148 | public function acquireCacheLock () 149 | { 150 | $lock = $this->_setRedis($this->_cacheKey, '1'); 151 | if ($lock === true) { 152 | return true; 153 | } 154 | return false; 155 | } 156 | 157 | /** 158 | * Remvoes the cache lock in Redis 159 | * 160 | * @return bool 161 | */ 162 | public function releaseCacheLock () 163 | { 164 | $lock = $this->_setRedis($this->_cacheKey, '0'); 165 | if ($lock === true) { 166 | return true; 167 | } 168 | return false; 169 | } 170 | 171 | /** 172 | * Returns if the cache is locked in Redis 173 | * 174 | * @return bool 175 | */ 176 | public function getIsCacheLocked () 177 | { 178 | $locked = $this->_getRedis($this->_cacheKey); 179 | 180 | if (is_array($locked) && isset($locked[0]) && isset($locked[1])) { 181 | if ((bool) $locked[0] === true) { 182 | return (bool) $locked[1]; 183 | } 184 | } 185 | 186 | return false; 187 | } 188 | 189 | /** 190 | * Gets the maximum amount of attempts the request should be retried 191 | * 192 | * @return int 193 | */ 194 | public function getMaxAttempts () 195 | { 196 | return $this->_maxAttempts; 197 | } 198 | 199 | /** 200 | * Gets the time to wait between retring the request 201 | * 202 | * @return int 203 | */ 204 | public function getRetryTime () 205 | { 206 | return $this->_retryTime; 207 | } 208 | } --------------------------------------------------------------------------------