PageRenderTime 50ms CodeModel.GetById 17ms RepoModel.GetById 0ms app.codeStats 0ms

/app/code/core/Mage/Core/Model/Config.php

https://bitbucket.org/claudiu_marginean/magento-hg-mirror
PHP | 1522 lines | 839 code | 148 blank | 535 comment | 132 complexity | cbce1e8fc72dab6a081141d4b8bd06d8 MD5 | raw file
Possible License(s): CC-BY-SA-3.0, LGPL-2.1, GPL-2.0, WTFPL
  1. <?php
  2. /**
  3. * Magento
  4. *
  5. * NOTICE OF LICENSE
  6. *
  7. * This source file is subject to the Open Software License (OSL 3.0)
  8. * that is bundled with this package in the file LICENSE.txt.
  9. * It is also available through the world-wide-web at this URL:
  10. * http://opensource.org/licenses/osl-3.0.php
  11. * If you did not receive a copy of the license and are unable to
  12. * obtain it through the world-wide-web, please send an email
  13. * to license@magentocommerce.com so we can send you a copy immediately.
  14. *
  15. * DISCLAIMER
  16. *
  17. * Do not edit or add to this file if you wish to upgrade Magento to newer
  18. * versions in the future. If you wish to customize Magento for your
  19. * needs please refer to http://www.magentocommerce.com for more information.
  20. *
  21. * @category Mage
  22. * @package Mage_Core
  23. * @copyright Copyright (c) 2010 Magento Inc. (http://www.magentocommerce.com)
  24. * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
  25. */
  26. /**
  27. * Core configuration class
  28. *
  29. * @category Mage
  30. * @package Mage_Core
  31. * @author Magento Core Team <core@magentocommerce.com>
  32. */
  33. class Mage_Core_Model_Config extends Mage_Core_Model_Config_Base
  34. {
  35. const CACHE_TAG = 'CONFIG';
  36. /**
  37. * Flag which allow use cache logic
  38. *
  39. * @var bool
  40. */
  41. protected $_useCache = false;
  42. /**
  43. * Instructions for spitting config cache
  44. * array(
  45. * $sectionName => $recursionLevel
  46. * )
  47. * Recursion level provide availability cache subnodes separatly
  48. *
  49. * @var array
  50. */
  51. protected $_cacheSections = array(
  52. 'admin' => 0,
  53. 'adminhtml' => 0,
  54. 'crontab' => 0,
  55. 'install' => 0,
  56. 'stores' => 1,
  57. 'websites' => 0
  58. );
  59. /**
  60. * Loaded Configuration by cached sections
  61. *
  62. * @var array
  63. */
  64. protected $_cacheLoadedSections = array();
  65. /**
  66. * Configuration options
  67. *
  68. * @var Mage_Core_Model_Config_Options
  69. */
  70. protected $_options;
  71. /**
  72. * Storage for generated class names
  73. *
  74. * @var array
  75. */
  76. protected $_classNameCache = array();
  77. /**
  78. * Storage for generated block class names
  79. *
  80. * @var unknown_type
  81. */
  82. protected $_blockClassNameCache = array();
  83. /**
  84. * Storage of validated secure urls
  85. *
  86. * @var array
  87. */
  88. protected $_secureUrlCache = array();
  89. /**
  90. * System environment server variables
  91. *
  92. * @var array
  93. */
  94. protected $_distroServerVars;
  95. /**
  96. * Array which is using for replace placeholders of server variables
  97. *
  98. * @var array
  99. */
  100. protected $_substServerVars;
  101. /**
  102. * Resource model
  103. * Used for operations with DB
  104. *
  105. * @var Mage_Core_Model_Mysql4_Config
  106. */
  107. protected $_resourceModel;
  108. /**
  109. * Configuration for events by area
  110. *
  111. * @var array
  112. */
  113. protected $_eventAreas;
  114. /**
  115. * Flag cache for existing or already created directories
  116. *
  117. * @var array
  118. */
  119. protected $_dirExists = array();
  120. /**
  121. * Flach which allow using cache for config initialization
  122. *
  123. * @var bool
  124. */
  125. protected $_allowCacheForInit = true;
  126. /**
  127. * Property used during cache save process
  128. *
  129. * @var array
  130. */
  131. protected $_cachePartsForSave = array();
  132. /**
  133. * Empty configuration object for loading and megring configuration parts
  134. *
  135. * @var Mage_Core_Model_Config_Base
  136. */
  137. protected $_prototype;
  138. /**
  139. * Flag which identify what local configuration is loaded
  140. *
  141. * @var bool
  142. */
  143. protected $_isLocalConfigLoaded = false;
  144. /**
  145. * Depricated properties
  146. *
  147. * @deprecated
  148. */
  149. protected $_baseDirCache = array();
  150. protected $_customEtcDir = null;
  151. /**
  152. * Flag which allow to use modules from local code pool
  153. *
  154. * @var bool
  155. */
  156. protected $_canUseLocalModules = null;
  157. /**
  158. * Active modules array per namespace
  159. * @var array
  160. */
  161. private $_moduleNamespaces = null;
  162. /**
  163. * Modules allowed to load
  164. * If empty - all modules are allowed
  165. *
  166. * @var array
  167. */
  168. protected $_allowedModules = array();
  169. /**
  170. * Class construct
  171. *
  172. * @param mixed $sourceData
  173. */
  174. public function __construct($sourceData=null)
  175. {
  176. $this->setCacheId('config_global');
  177. $this->_options = new Mage_Core_Model_Config_Options();
  178. $this->_prototype = new Mage_Core_Model_Config_Base();
  179. $this->_cacheChecksum = null;
  180. parent::__construct($sourceData);
  181. }
  182. /**
  183. * Get config resource model
  184. *
  185. * @return Mage_Core_Store_Mysql4_Config
  186. */
  187. public function getResourceModel()
  188. {
  189. if (is_null($this->_resourceModel)) {
  190. $this->_resourceModel = Mage::getResourceModel('core/config');
  191. }
  192. return $this->_resourceModel;
  193. }
  194. /**
  195. * Get configuration options object
  196. *
  197. * @return Mage_Core_Model_Config_Options
  198. */
  199. public function getOptions()
  200. {
  201. return $this->_options;
  202. }
  203. /**
  204. * Set configuration options
  205. *
  206. * @param array $options
  207. * @return Mage_Core_Model_Config
  208. */
  209. public function setOptions($options)
  210. {
  211. if (is_array($options)) {
  212. $this->getOptions()->addData($options);
  213. }
  214. return $this;
  215. }
  216. /**
  217. * Initialization of core configuration
  218. *
  219. * @return Mage_Core_Model_Config
  220. */
  221. public function init($options=array())
  222. {
  223. $this->setCacheChecksum(null);
  224. $this->_cacheLoadedSections = array();
  225. $this->setOptions($options);
  226. $this->loadBase();
  227. $cacheLoad = $this->loadModulesCache();
  228. if ($cacheLoad) {
  229. return $this;
  230. }
  231. $this->loadModules();
  232. $this->loadDb();
  233. $this->saveCache();
  234. return $this;
  235. }
  236. /**
  237. * Load base system configuration (config.xml and local.xml files)
  238. *
  239. * @return Mage_Core_Model_Config
  240. */
  241. public function loadBase()
  242. {
  243. $etcDir = $this->getOptions()->getEtcDir();
  244. $files = glob($etcDir.DS.'*.xml');
  245. $this->loadFile(current($files));
  246. while ($file = next($files)) {
  247. $merge = clone $this->_prototype;
  248. $merge->loadFile($file);
  249. $this->extend($merge);
  250. }
  251. if (in_array($etcDir.DS.'local.xml', $files)) {
  252. $this->_isLocalConfigLoaded = true;
  253. }
  254. return $this;
  255. }
  256. /**
  257. * Load cached modules configuration
  258. *
  259. * @return bool
  260. */
  261. public function loadModulesCache()
  262. {
  263. if (Mage::isInstalled()) {
  264. if ($this->_canUseCacheForInit()) {
  265. Varien_Profiler::start('mage::app::init::config::load_cache');
  266. $loaded = $this->loadCache();
  267. Varien_Profiler::stop('mage::app::init::config::load_cache');
  268. if ($loaded) {
  269. $this->_useCache = true;
  270. return true;
  271. }
  272. }
  273. }
  274. return false;
  275. }
  276. /**
  277. * Load modules configuration
  278. *
  279. * @return Mage_Core_Model_Config
  280. */
  281. public function loadModules()
  282. {
  283. Varien_Profiler::start('config/load-modules');
  284. $this->_loadDeclaredModules();
  285. $this->loadModulesConfiguration('config.xml', $this);
  286. /**
  287. * Prevent local.xml directives overwriting
  288. */
  289. $mergeConfig = clone $this->_prototype;
  290. $this->_isLocalConfigLoaded = $mergeConfig->loadFile($this->getOptions()->getEtcDir().DS.'local.xml');
  291. if ($this->_isLocalConfigLoaded) {
  292. $this->extend($mergeConfig);
  293. }
  294. $this->applyExtends();
  295. Varien_Profiler::stop('config/load-modules');
  296. return $this;
  297. }
  298. /**
  299. * Check if local configuration (DB connection, etc) is loaded
  300. *
  301. * @return bool
  302. */
  303. public function isLocalConfigLoaded()
  304. {
  305. return $this->_isLocalConfigLoaded;
  306. }
  307. /**
  308. * Load config data from DB
  309. *
  310. * @return Mage_Core_Model_Config
  311. */
  312. public function loadDb()
  313. {
  314. if ($this->_isLocalConfigLoaded && Mage::isInstalled()) {
  315. Varien_Profiler::start('config/load-db');
  316. $dbConf = $this->getResourceModel();
  317. $dbConf->loadToXml($this);
  318. Varien_Profiler::stop('config/load-db');
  319. }
  320. return $this;
  321. }
  322. /**
  323. * Reinitialize configuration
  324. *
  325. * @param array $options
  326. * @return Mage_Core_Model_Config
  327. */
  328. public function reinit($options = array())
  329. {
  330. $this->_allowCacheForInit = false;
  331. $this->_useCache = false;
  332. return $this->init($options);
  333. }
  334. /**
  335. * Check local modules enable/disable flag
  336. * If local modules are disbled remove local modules path from include dirs
  337. *
  338. * return true if local modules enabled and false if disabled
  339. *
  340. * @return bool
  341. */
  342. protected function _canUseLocalModules()
  343. {
  344. if ($this->_canUseLocalModules !== null) {
  345. return $this->_canUseLocalModules;
  346. }
  347. $disableLocalModules = (string)$this->getNode('global/disable_local_modules');
  348. if (!empty($disableLocalModules)) {
  349. $disableLocalModules = (('true' === $disableLocalModules) || ('1' === $disableLocalModules));
  350. } else {
  351. $disableLocalModules = false;
  352. }
  353. if ($disableLocalModules && !defined('COMPILER_INCLUDE_PATH')) {
  354. set_include_path(
  355. // excluded '/app/code/local'
  356. BP . DS . 'app' . DS . 'code' . DS . 'community' . PS .
  357. BP . DS . 'app' . DS . 'code' . DS . 'core' . PS .
  358. BP . DS . 'lib' . PS .
  359. Mage::registry('original_include_path')
  360. );
  361. }
  362. $this->_canUseLocalModules = !$disableLocalModules;
  363. return $this->_canUseLocalModules;
  364. }
  365. /**
  366. * Check if cache can be used for config initialization
  367. *
  368. * @return bool
  369. */
  370. protected function _canUseCacheForInit()
  371. {
  372. return Mage::app()->useCache('config') && $this->_allowCacheForInit
  373. && !$this->_loadCache($this->_getCacheLockId());
  374. }
  375. /**
  376. * Retrieve cache object
  377. *
  378. * @return Zend_Cache_Frontend_File
  379. */
  380. public function getCache()
  381. {
  382. return Mage::app()->getCache();
  383. }
  384. /**
  385. * Get lock flag cache identifier
  386. *
  387. * @return string
  388. */
  389. protected function _getCacheLockId()
  390. {
  391. return $this->getCacheId().'.lock';
  392. }
  393. /**
  394. * Save configuration cache
  395. *
  396. * @param array $tags cache tags
  397. * @return Mage_Core_Model_Config
  398. */
  399. public function saveCache($tags=array())
  400. {
  401. if (!Mage::app()->useCache('config')) {
  402. return $this;
  403. }
  404. if (!in_array(self::CACHE_TAG, $tags)) {
  405. $tags[] = self::CACHE_TAG;
  406. }
  407. $cacheLockId = $this->_getCacheLockId();
  408. if ($this->_loadCache($cacheLockId)) {
  409. return $this;
  410. }
  411. if (!empty($this->_cacheSections)) {
  412. $xml = clone $this->_xml;
  413. foreach ($this->_cacheSections as $sectionName => $level) {
  414. $this->_saveSectionCache($this->getCacheId(), $sectionName, $xml, $level, $tags);
  415. unset($xml->$sectionName);
  416. }
  417. $this->_cachePartsForSave[$this->getCacheId()] = $xml->asNiceXml('', false);
  418. } else {
  419. return parent::saveCache($tags);
  420. }
  421. $this->_saveCache(time(), $cacheLockId, array(), 60);
  422. $this->removeCache();
  423. foreach ($this->_cachePartsForSave as $cacheId => $cacheData) {
  424. $this->_saveCache($cacheData, $cacheId, $tags, $this->getCacheLifetime());
  425. }
  426. unset($this->_cachePartsForSave);
  427. $this->_removeCache($cacheLockId);
  428. return $this;
  429. }
  430. /**
  431. * Save cache of specified
  432. *
  433. * @param string $idPrefix cache id prefix
  434. * @param string $sectionName
  435. * @param Varien_Simplexml_Element $source
  436. * @param int $recursionLevel
  437. * @return Mage_Core_Model_Config
  438. */
  439. protected function _saveSectionCache($idPrefix, $sectionName, $source, $recursionLevel=0, $tags=array())
  440. {
  441. if ($source && $source->$sectionName) {
  442. $cacheId = $idPrefix . '_' . $sectionName;
  443. if ($recursionLevel > 0) {
  444. foreach ($source->$sectionName->children() as $subSectionName => $node) {
  445. $this->_saveSectionCache($cacheId, $subSectionName, $source->$sectionName, $recursionLevel-1, $tags);
  446. }
  447. }
  448. $this->_cachePartsForSave[$cacheId] = $source->$sectionName->asNiceXml('', false);
  449. }
  450. return $this;
  451. }
  452. /**
  453. * Load config section cached data
  454. *
  455. * @param string $sectionName
  456. * @return Varien_Simplexml_Element
  457. */
  458. protected function _loadSectionCache($sectionName)
  459. {
  460. $cacheId = $this->getCacheId() . '_' . $sectionName;
  461. $xmlString = $this->_loadCache($cacheId);
  462. /**
  463. * If we can't load section cache (problems with cache storage)
  464. */
  465. if (!$xmlString) {
  466. $this->_useCache = false;
  467. $this->reinit($this->_options);
  468. return false;
  469. } else {
  470. $xml = simplexml_load_string($xmlString, $this->_elementClass);
  471. return $xml;
  472. }
  473. }
  474. /**
  475. * Load cached data by identifier
  476. *
  477. * @param string $id
  478. * @return string
  479. */
  480. protected function _loadCache($id)
  481. {
  482. return Mage::app()->loadCache($id);
  483. }
  484. /**
  485. * Save cache data
  486. *
  487. * @param string $data
  488. * @param string $id
  489. * @param array $tags
  490. * @param false|int $lifetime
  491. * @return Mage_Core_Model_Config
  492. */
  493. protected function _saveCache($data, $id, $tags=array(), $lifetime=false)
  494. {
  495. return Mage::app()->saveCache($data, $id, $tags, $lifetime);
  496. }
  497. /**
  498. * Clear cache data by id
  499. *
  500. * @param string $id
  501. * @return Mage_Core_Model_Config
  502. */
  503. protected function _removeCache($id)
  504. {
  505. return Mage::app()->removeCache($id);
  506. }
  507. /**
  508. * Remove configuration cache
  509. *
  510. * @return Mage_Core_Model_Config
  511. */
  512. public function removeCache()
  513. {
  514. Mage::app()->cleanCache(array(self::CACHE_TAG));
  515. return parent::removeCache();
  516. }
  517. /**
  518. * Configuration cache clean process
  519. *
  520. * @return Mage_Core_Model_Config
  521. */
  522. public function cleanCache()
  523. {
  524. return $this->reinit();
  525. }
  526. /**
  527. * Get node value from cached section data
  528. *
  529. * @param array $path
  530. * @return Mage_Core_Model_Config
  531. */
  532. public function getSectionNode($path)
  533. {
  534. $section = $path[0];
  535. $recursion = $this->_cacheSections[$section];
  536. $sectioPath = array_slice($path, 0, $recursion+1);
  537. $path = array_slice($path, $recursion+1);
  538. $sectionKey = implode('_', $sectioPath);
  539. if (!isset($this->_cacheLoadedSections[$sectionKey])) {
  540. Varien_Profiler::start('mage::app::init::config::section::'.$sectionKey);
  541. $this->_cacheLoadedSections[$sectionKey] = $this->_loadSectionCache($sectionKey);
  542. Varien_Profiler::stop('mage::app::init::config::section::'.$sectionKey);
  543. }
  544. if ($this->_cacheLoadedSections[$sectionKey] === false) {
  545. return false;
  546. }
  547. return $this->_cacheLoadedSections[$sectionKey]->descend($path);
  548. }
  549. /**
  550. * Returns node found by the $path and scope info
  551. *
  552. * @param string $path
  553. * @param string $scope
  554. * @param string $scopeCode
  555. * @return Mage_Core_Model_Config_Element
  556. */
  557. public function getNode($path=null, $scope='', $scopeCode=null)
  558. {
  559. if ($scope !== '') {
  560. if (('store' === $scope) || ('website' === $scope)) {
  561. $scope .= 's';
  562. }
  563. if (('default' !== $scope) && is_int($scopeCode)) {
  564. if ('stores' == $scope) {
  565. $scopeCode = Mage::app()->getStore($scopeCode)->getCode();
  566. } elseif ('websites' == $scope) {
  567. $scopeCode = Mage::app()->getWebsite($scopeCode)->getCode();
  568. } else {
  569. Mage::throwException(Mage::helper('core')->__('Unknown scope "%s".', $scope));
  570. }
  571. }
  572. $path = $scope . ($scopeCode ? '/' . $scopeCode : '' ) . (empty($path) ? '' : '/' . $path);
  573. }
  574. /**
  575. * Check path cache loading
  576. */
  577. if ($this->_useCache && ($path !== null)) {
  578. $path = explode('/', $path);
  579. $section= $path[0];
  580. if (isset($this->_cacheSections[$section])) {
  581. $res = $this->getSectionNode($path);
  582. if ($res !== false) {
  583. return $res;
  584. }
  585. }
  586. }
  587. return parent::getNode($path);
  588. }
  589. /**
  590. * Retrive Declared Module file list
  591. *
  592. * @return array
  593. */
  594. protected function _getDeclaredModuleFiles()
  595. {
  596. $etcDir = $this->getOptions()->getEtcDir();
  597. $moduleFiles = glob($etcDir . DS . 'modules' . DS . '*.xml');
  598. if (!$moduleFiles) {
  599. return false;
  600. }
  601. $collectModuleFiles = array(
  602. 'base' => array(),
  603. 'mage' => array(),
  604. 'custom' => array()
  605. );
  606. foreach ($moduleFiles as $v) {
  607. $name = explode(DIRECTORY_SEPARATOR, $v);
  608. $name = substr($name[count($name) - 1], 0, -4);
  609. if ($name == 'Mage_All') {
  610. $collectModuleFiles['base'][] = $v;
  611. }
  612. elseif (substr($name, 0, 5) == 'Mage_') {
  613. $collectModuleFiles['mage'][] = $v;
  614. }
  615. else {
  616. $collectModuleFiles['custom'][] = $v;
  617. }
  618. }
  619. return array_merge(
  620. $collectModuleFiles['base'],
  621. $collectModuleFiles['mage'],
  622. $collectModuleFiles['custom']
  623. );
  624. }
  625. /**
  626. * Add module(s) to allowed list
  627. *
  628. * @param strung|array $module
  629. * @return Mage_Core_Model_Config
  630. */
  631. public function addAllowedModules($module)
  632. {
  633. if (is_array($module)) {
  634. foreach ($module as $moduleName) {
  635. $this->addAllowedModules($moduleName);
  636. }
  637. } elseif (!in_array($module, $this->_allowedModules)) {
  638. $this->_allowedModules[] = $module;
  639. }
  640. return $this;
  641. }
  642. /**
  643. * Define if module is allowed
  644. *
  645. * @param string $moduleName
  646. * @return bool
  647. */
  648. protected function _isAllowedModule($moduleName)
  649. {
  650. if (empty($this->_allowedModules)) {
  651. return true;
  652. } else {
  653. return in_array($moduleName, $this->_allowedModules);
  654. }
  655. }
  656. /**
  657. * Load declared modules configuration
  658. *
  659. * @param null $mergeConfig depricated
  660. * @return Mage_Core_Model_Config
  661. */
  662. protected function _loadDeclaredModules($mergeConfig = null)
  663. {
  664. $moduleFiles = $this->_getDeclaredModuleFiles();
  665. if (!$moduleFiles) {
  666. return ;
  667. }
  668. Varien_Profiler::start('config/load-modules-declaration');
  669. $unsortedConfig = new Mage_Core_Model_Config_Base();
  670. $unsortedConfig->loadString('<config/>');
  671. $fileConfig = new Mage_Core_Model_Config_Base();
  672. // load modules declarations
  673. foreach ($moduleFiles as $file) {
  674. $fileConfig->loadFile($file);
  675. $unsortedConfig->extend($fileConfig);
  676. }
  677. $moduleDepends = array();
  678. foreach ($unsortedConfig->getNode('modules')->children() as $moduleName => $moduleNode) {
  679. if (!$this->_isAllowedModule($moduleName)) {
  680. continue;
  681. }
  682. $depends = array();
  683. if ($moduleNode->depends) {
  684. foreach ($moduleNode->depends->children() as $depend) {
  685. $depends[$depend->getName()] = true;
  686. }
  687. }
  688. $moduleDepends[$moduleName] = array(
  689. 'module' => $moduleName,
  690. 'depends' => $depends,
  691. 'active' => ('true' === (string)$moduleNode->active ? true : false),
  692. );
  693. }
  694. // check and sort module dependence
  695. $moduleDepends = $this->_sortModuleDepends($moduleDepends);
  696. // create sorted config
  697. $sortedConfig = new Mage_Core_Model_Config_Base();
  698. $sortedConfig->loadString('<config><modules/></config>');
  699. foreach ($unsortedConfig->getNode()->children() as $nodeName => $node) {
  700. if ($nodeName != 'modules') {
  701. $sortedConfig->getNode()->appendChild($node);
  702. }
  703. }
  704. foreach ($moduleDepends as $moduleProp) {
  705. $node = $unsortedConfig->getNode('modules/'.$moduleProp['module']);
  706. $sortedConfig->getNode('modules')->appendChild($node);
  707. }
  708. $this->extend($sortedConfig);
  709. Varien_Profiler::stop('config/load-modules-declaration');
  710. return $this;
  711. }
  712. /**
  713. * Sort modules and check depends
  714. *
  715. * @param array $modules
  716. * @return array
  717. */
  718. protected function _sortModuleDepends($modules)
  719. {
  720. foreach ($modules as $moduleName => $moduleProps) {
  721. $depends = $moduleProps['depends'];
  722. foreach ($moduleProps['depends'] as $depend => $true) {
  723. if ($moduleProps['active'] && ((!isset($modules[$depend])) || empty($modules[$depend]['active']))) {
  724. Mage::throwException(Mage::helper('core')->__('Module "%1$s" requires module "%2$s".', $moduleName, $depend));
  725. }
  726. $depends = array_merge($depends, $modules[$depend]['depends']);
  727. }
  728. $modules[$moduleName]['depends'] = $depends;
  729. }
  730. $modules = array_values($modules);
  731. $size = count($modules) - 1;
  732. for ($i = $size; $i >= 0; $i--) {
  733. for ($j = $size; $i < $j; $j--) {
  734. if (isset($modules[$i]['depends'][$modules[$j]['module']])) {
  735. $value = $modules[$i];
  736. $modules[$i] = $modules[$j];
  737. $modules[$j] = $value;
  738. }
  739. }
  740. }
  741. $definedModules = array();
  742. foreach ($modules as $moduleProp) {
  743. foreach ($moduleProp['depends'] as $dependModule => $true) {
  744. if (!isset($definedModules[$dependModule])) {
  745. Mage::throwException(
  746. Mage::helper('core')->__('Module "%1$s" cannot depend on "%2$s".', $moduleProp['module'], $dependModule)
  747. );
  748. }
  749. }
  750. $definedModules[$moduleProp['module']] = true;
  751. }
  752. return $modules;
  753. }
  754. /**
  755. * Determine whether provided name begins from any available modules, according to namespaces priority
  756. * If matched, returns as the matched module "factory" name or a fully qualified module name
  757. *
  758. * @param string $name
  759. * @param bool $asFullModuleName
  760. * @return string
  761. */
  762. public function determineOmittedNamespace($name, $asFullModuleName = false)
  763. {
  764. if (null === $this->_moduleNamespaces) {
  765. $this->_moduleNamespaces = array();
  766. foreach ($this->_xml->xpath('modules/*') as $m) {
  767. if ((string)$m->active == 'true') {
  768. $moduleName = $m->getName();
  769. $module = strtolower($moduleName);
  770. $this->_moduleNamespaces[substr($module, 0, strpos($module, '_'))][$module] = $moduleName;
  771. }
  772. }
  773. }
  774. $name = explode('_', strtolower($name));
  775. $partsNum = count($name);
  776. $defaultNamespaceFlag = false;
  777. foreach ($this->_moduleNamespaces as $namespaceName => $namespace) {
  778. // assume the namespace is omitted (default namespace only, which comes first)
  779. if ($defaultNamespaceFlag === false) {
  780. $defaultNamespaceFlag = true;
  781. $defaultNS = $namespaceName . '_' . $name[0];
  782. if (isset($namespace[$defaultNS])) {
  783. return $asFullModuleName ? $namespace[$defaultNS] : $name[0]; // return omitted as well
  784. }
  785. }
  786. // assume namespace is qualified
  787. if(isset($name[1])) {
  788. $fullNS = $name[0] . '_' . $name[1];
  789. if (2 <= $partsNum && isset($namespace[$fullNS])) {
  790. return $asFullModuleName ? $namespace[$fullNS] : $fullNS;
  791. }
  792. }
  793. }
  794. return '';
  795. }
  796. /**
  797. * Iterate all active modules "etc" folders and combine data from
  798. * specidied xml file name to one object
  799. *
  800. * @param string $fileName
  801. * @param null|Mage_Core_Model_Config_Base $mergeToObject
  802. * @return Mage_Core_Model_Config_Base
  803. */
  804. public function loadModulesConfiguration($fileName, $mergeToObject = null, $mergeModel=null)
  805. {
  806. $disableLocalModules = !$this->_canUseLocalModules();
  807. if ($mergeToObject === null) {
  808. $mergeToObject = clone $this->_prototype;
  809. $mergeToObject->loadString('<config/>');
  810. }
  811. if ($mergeModel === null) {
  812. $mergeModel = clone $this->_prototype;
  813. }
  814. $modules = $this->getNode('modules')->children();
  815. foreach ($modules as $modName=>$module) {
  816. if ($module->is('active')) {
  817. if ($disableLocalModules && ('local' === (string)$module->codePool)) {
  818. continue;
  819. }
  820. $configFile = $this->getModuleDir('etc', $modName).DS.$fileName;
  821. if ($mergeModel->loadFile($configFile)) {
  822. $mergeToObject->extend($mergeModel, true);
  823. }
  824. }
  825. }
  826. return $mergeToObject;
  827. }
  828. /**
  829. * Retrieve temporary directory path
  830. *
  831. * @return string
  832. */
  833. public function getTempVarDir()
  834. {
  835. return $this->getOptions()->getVarDir();
  836. }
  837. /**
  838. * Get default server variables values
  839. *
  840. * @return array
  841. */
  842. public function getDistroServerVars()
  843. {
  844. if (!$this->_distroServerVars) {
  845. if (isset($_SERVER['SCRIPT_NAME']) && isset($_SERVER['HTTP_HOST'])) {
  846. $secure = (!empty($_SERVER['HTTPS']) && ($_SERVER['HTTPS']!='off')) || $_SERVER['SERVER_PORT']=='443';
  847. $scheme = ($secure ? 'https' : 'http') . '://' ;
  848. $hostArr = explode(':', $_SERVER['HTTP_HOST']);
  849. $host = $hostArr[0];
  850. $port = isset($hostArr[1]) && (!$secure && $hostArr[1]!=80 || $secure && $hostArr[1]!=443) ? ':'.$hostArr[1] : '';
  851. $path = Mage::app()->getRequest()->getBasePath();
  852. $baseUrl = $scheme.$host.$port.rtrim($path, '/').'/';
  853. } else {
  854. $baseUrl = 'http://localhost/';
  855. }
  856. $options = $this->getOptions();
  857. $this->_distroServerVars = array(
  858. 'root_dir' => $options->getBaseDir(),
  859. 'app_dir' => $options->getAppDir(),
  860. 'var_dir' => $options->getVarDir(),
  861. 'base_url' => $baseUrl,
  862. );
  863. foreach ($this->_distroServerVars as $k=>$v) {
  864. $this->_substServerVars['{{'.$k.'}}'] = $v;
  865. }
  866. }
  867. return $this->_distroServerVars;
  868. }
  869. public function substDistroServerVars($data)
  870. {
  871. $this->getDistroServerVars();
  872. return str_replace(
  873. array_keys($this->_substServerVars),
  874. array_values($this->_substServerVars),
  875. $data
  876. );
  877. }
  878. /**
  879. * Get module config node
  880. *
  881. * @param string $moduleName
  882. * @return Varien_Simplexml_Object
  883. */
  884. function getModuleConfig($moduleName='')
  885. {
  886. $modules = $this->getNode('modules');
  887. if (''===$moduleName) {
  888. return $modules;
  889. } else {
  890. return $modules->$moduleName;
  891. }
  892. }
  893. /**
  894. * Get module setup class instance.
  895. *
  896. * Defaults to Mage_Core_Setup
  897. *
  898. * @param string|Varien_Simplexml_Object $module
  899. * @return object
  900. */
  901. function getModuleSetup($module='')
  902. {
  903. $className = 'Mage_Core_Setup';
  904. if (''!==$module) {
  905. if (is_string($module)) {
  906. $module = $this->getModuleConfig($module);
  907. }
  908. if (isset($module->setup)) {
  909. $moduleClassName = $module->setup->getClassName();
  910. if (!empty($moduleClassName)) {
  911. $className = $moduleClassName;
  912. }
  913. }
  914. }
  915. return new $className($module);
  916. }
  917. /**
  918. * Get base filesystem directory. depends on $type
  919. *
  920. * If $moduleName is specified retrieves specific value for the module.
  921. *
  922. * @deprecated in favor of Mage_Core_Model_Config_Options
  923. * @todo get global dir config
  924. * @param string $type
  925. * @return string
  926. */
  927. public function getBaseDir($type='base')
  928. {
  929. return $this->getOptions()->getDir($type);
  930. }
  931. /**
  932. * Get temporary data directory name
  933. *
  934. * @param string $path
  935. * @param string $type
  936. * @return string
  937. */
  938. public function getVarDir($path=null, $type='var')
  939. {
  940. $dir = Mage::getBaseDir($type).($path!==null ? DS.$path : '');
  941. if (!$this->createDirIfNotExists($dir)) {
  942. return false;
  943. }
  944. return $dir;
  945. }
  946. public function createDirIfNotExists($dir)
  947. {
  948. return $this->getOptions()->createDirIfNotExists($dir);
  949. }
  950. /**
  951. * Get module directory by directory type
  952. *
  953. * @param string $type
  954. * @param string $moduleName
  955. * @return string
  956. */
  957. public function getModuleDir($type, $moduleName)
  958. {
  959. $codePool = (string)$this->getModuleConfig($moduleName)->codePool;
  960. $dir = $this->getOptions()->getCodeDir().DS.$codePool.DS.uc_words($moduleName, DS);
  961. switch ($type) {
  962. case 'etc':
  963. $dir .= DS.'etc';
  964. break;
  965. case 'controllers':
  966. $dir .= DS.'controllers';
  967. break;
  968. case 'sql':
  969. $dir .= DS.'sql';
  970. break;
  971. case 'locale':
  972. $dir .= DS.'locale';
  973. break;
  974. }
  975. $dir = str_replace('/', DS, $dir);
  976. return $dir;
  977. }
  978. /**
  979. * Load event observers for an area (front, admin)
  980. *
  981. * @param string $area
  982. * @return boolean
  983. */
  984. public function loadEventObservers($area)
  985. {
  986. $events = $this->getNode("$area/events");
  987. if ($events) {
  988. $events = $events->children();
  989. }
  990. else {
  991. return false;
  992. }
  993. foreach ($events as $event) {
  994. $eventName = $event->getName();
  995. $observers = $event->observers->children();
  996. foreach ($observers as $observer) {
  997. switch ((string)$observer->type) {
  998. case 'singleton':
  999. $callback = array(
  1000. Mage::getSingleton((string)$observer->class),
  1001. (string)$observer->method
  1002. );
  1003. break;
  1004. case 'object':
  1005. case 'model':
  1006. $callback = array(
  1007. Mage::getModel((string)$observer->class),
  1008. (string)$observer->method
  1009. );
  1010. break;
  1011. default:
  1012. $callback = array($observer->getClassName(), (string)$observer->method);
  1013. break;
  1014. }
  1015. $args = (array)$observer->args;
  1016. $observerClass = $observer->observer_class ? (string)$observer->observer_class : '';
  1017. Mage::addObserver($eventName, $callback, $args, $observer->getName(), $observerClass);
  1018. }
  1019. }
  1020. return true;
  1021. }
  1022. /**
  1023. * Get standard path variables.
  1024. *
  1025. * To be used in blocks, templates, etc.
  1026. *
  1027. * @param array|string $args Module name if string
  1028. * @return array
  1029. */
  1030. public function getPathVars($args=null)
  1031. {
  1032. $path = array();
  1033. $path['baseUrl'] = Mage::getBaseUrl();
  1034. $path['baseSecureUrl'] = Mage::getBaseUrl('link', true);
  1035. return $path;
  1036. }
  1037. /**
  1038. * Retrieve class name by class group
  1039. *
  1040. * @param string $groupType currently supported model, block, helper
  1041. * @param string $classId slash separated class identifier, ex. group/class
  1042. * @param string $groupRootNode optional config path for group config
  1043. * @return string
  1044. */
  1045. public function getGroupedClassName($groupType, $classId, $groupRootNode=null)
  1046. {
  1047. if (empty($groupRootNode)) {
  1048. $groupRootNode = 'global/'.$groupType.'s';
  1049. }
  1050. $classArr = explode('/', trim($classId));
  1051. $group = $classArr[0];
  1052. $class = !empty($classArr[1]) ? $classArr[1] : null;
  1053. if (isset($this->_classNameCache[$groupRootNode][$group][$class])) {
  1054. return $this->_classNameCache[$groupRootNode][$group][$class];
  1055. }
  1056. //$config = $this->getNode($groupRootNode.'/'.$group);
  1057. $config = $this->_xml->global->{$groupType.'s'}->{$group};
  1058. if (isset($config->rewrite->$class)) {
  1059. $className = (string)$config->rewrite->$class;
  1060. } else {
  1061. if (!empty($config)) {
  1062. $className = $config->getClassName();
  1063. }
  1064. if (empty($className)) {
  1065. $className = 'mage_'.$group.'_'.$groupType;
  1066. }
  1067. if (!empty($class)) {
  1068. $className .= '_'.$class;
  1069. }
  1070. $className = uc_words($className);
  1071. }
  1072. $this->_classNameCache[$groupRootNode][$group][$class] = $className;
  1073. return $className;
  1074. }
  1075. /**
  1076. * Retrieve block class name
  1077. *
  1078. * @param string $blockType
  1079. * @return string
  1080. */
  1081. public function getBlockClassName($blockType)
  1082. {
  1083. if (strpos($blockType, '/')===false) {
  1084. return $blockType;
  1085. }
  1086. return $this->getGroupedClassName('block', $blockType);
  1087. }
  1088. /**
  1089. * Retrieve helper class name
  1090. *
  1091. * @param string $name
  1092. * @return string
  1093. */
  1094. public function getHelperClassName($helperName)
  1095. {
  1096. if (strpos($helperName, '/')===false) {
  1097. $helperName .= '/data';
  1098. }
  1099. return $this->getGroupedClassName('helper', $helperName);
  1100. }
  1101. /**
  1102. * Retrieve modele class name
  1103. *
  1104. * @param sting $modelClass
  1105. * @return string
  1106. */
  1107. public function getModelClassName($modelClass)
  1108. {
  1109. $modelClass = trim($modelClass);
  1110. if (strpos($modelClass, '/')===false) {
  1111. return $modelClass;
  1112. }
  1113. return $this->getGroupedClassName('model', $modelClass);
  1114. }
  1115. /**
  1116. * Get model class instance.
  1117. *
  1118. * Example:
  1119. * $config->getModelInstance('catalog/product')
  1120. *
  1121. * Will instantiate Mage_Catalog_Model_Mysql4_Product
  1122. *
  1123. * @param string $modelClass
  1124. * @param array|object $constructArguments
  1125. * @return Mage_Core_Model_Abstract
  1126. */
  1127. public function getModelInstance($modelClass='', $constructArguments=array())
  1128. {
  1129. $className = $this->getModelClassName($modelClass);
  1130. if (class_exists($className)) {
  1131. Varien_Profiler::start('CORE::create_object_of::'.$className);
  1132. $obj = new $className($constructArguments);
  1133. Varien_Profiler::stop('CORE::create_object_of::'.$className);
  1134. return $obj;
  1135. } else {
  1136. #throw Mage::exception('Mage_Core', Mage::helper('core')->__('Model class does not exist: %s.', $modelClass));
  1137. return false;
  1138. }
  1139. }
  1140. public function getNodeClassInstance($path)
  1141. {
  1142. $config = Mage::getConfig()->getNode($path);
  1143. if (!$config) {
  1144. return false;
  1145. } else {
  1146. $className = $config->getClassName();
  1147. return new $className();
  1148. }
  1149. }
  1150. /**
  1151. * Get resource model object by alias
  1152. *
  1153. * @param string $modelClass
  1154. * @param array $constructArguments
  1155. * @return object
  1156. */
  1157. public function getResourceModelInstance($modelClass='', $constructArguments=array())
  1158. {
  1159. $factoryName = $this->_getResourceModelFactoryClassName($modelClass);
  1160. if (!$factoryName) {
  1161. return false;
  1162. }
  1163. return $this->getModelInstance($factoryName, $constructArguments);
  1164. }
  1165. /**
  1166. * Get resource configuration for resource name
  1167. *
  1168. * @param string $name
  1169. * @return Varien_Simplexml_Object
  1170. */
  1171. public function getResourceConfig($name)
  1172. {
  1173. return $this->_xml->global->resources->{$name};
  1174. }
  1175. /**
  1176. * Get connection configuration
  1177. *
  1178. * @param string $name
  1179. * @return Varien_Simplexml_Element
  1180. */
  1181. public function getResourceConnectionConfig($name)
  1182. {
  1183. $config = $this->getResourceConfig($name);
  1184. if ($config) {
  1185. $conn = $config->connection;
  1186. if ($conn) {
  1187. if (!empty($conn->use)) {
  1188. return $this->getResourceConnectionConfig((string)$conn->use);
  1189. } else {
  1190. return $conn;
  1191. }
  1192. }
  1193. }
  1194. return false;
  1195. }
  1196. /**
  1197. * Retrieve resource type configuration for resource name
  1198. *
  1199. * @param string $type
  1200. * @return Varien_Simplexml_Object
  1201. */
  1202. public function getResourceTypeConfig($type)
  1203. {
  1204. return $this->_xml->global->resource->connection->types->{$type};
  1205. }
  1206. /**
  1207. * Retrieve store Ids for $path with checking
  1208. *
  1209. * if empty $allowValues then retrieve all stores values
  1210. *
  1211. * return array($storeId=>$pathValue)
  1212. *
  1213. * @param string $path
  1214. * @param array $allowValues
  1215. * @return array
  1216. */
  1217. public function getStoresConfigByPath($path, $allowValues = array(), $useAsKey = 'id')
  1218. {
  1219. $storeValues = array();
  1220. $stores = $this->getNode('stores');
  1221. foreach ($stores->children() as $code => $store) {
  1222. switch ($useAsKey) {
  1223. case 'id':
  1224. $key = (int) $store->descend('system/store/id');
  1225. break;
  1226. case 'code':
  1227. $key = $code;
  1228. break;
  1229. case 'name':
  1230. $key = (string) $store->descend('system/store/name');
  1231. }
  1232. if ($key === false) {
  1233. continue;
  1234. }
  1235. $pathValue = (string) $store->descend($path);
  1236. if (empty($allowValues)) {
  1237. $storeValues[$key] = $pathValue;
  1238. }
  1239. elseif(in_array($pathValue, $allowValues)) {
  1240. $storeValues[$key] = $pathValue;
  1241. }
  1242. }
  1243. return $storeValues;
  1244. }
  1245. /**
  1246. * Check security requirements for url
  1247. *
  1248. * @param string $url
  1249. * @return bool
  1250. */
  1251. public function shouldUrlBeSecure($url)
  1252. {
  1253. if (!isset($this->_secureUrlCache[$url])) {
  1254. $this->_secureUrlCache[$url] = false;
  1255. $secureUrls = $this->getNode('frontend/secure_url');
  1256. foreach ($secureUrls->children() as $match) {
  1257. if (strpos($url, (string)$match)===0) {
  1258. $this->_secureUrlCache[$url] = true;
  1259. break;
  1260. }
  1261. }
  1262. }
  1263. return $this->_secureUrlCache[$url];
  1264. }
  1265. /**
  1266. * Get DB table names prefix
  1267. *
  1268. * @return string
  1269. */
  1270. public function getTablePrefix()
  1271. {
  1272. return $this->_xml->global->resources->db->table_prefix;
  1273. }
  1274. /**
  1275. * Get events configuration
  1276. *
  1277. * @param string $area event area
  1278. * @param string $eventName event name
  1279. * @return Mage_Core_Model_Config_Element
  1280. */
  1281. public function getEventConfig($area, $eventName)
  1282. {
  1283. //return $this->getNode($area)->events->{$eventName};
  1284. if (!isset($this->_eventAreas[$area])) {
  1285. $this->_eventAreas[$area] = $this->getNode($area)->events;
  1286. }
  1287. return $this->_eventAreas[$area]->{$eventName};
  1288. }
  1289. /**
  1290. * Save config value to DB
  1291. *
  1292. * @param string $path
  1293. * @param string $value
  1294. * @param string $scope
  1295. * @param int $scopeId
  1296. * @return Mage_Core_Store_Config
  1297. */
  1298. public function saveConfig($path, $value, $scope = 'default', $scopeId = 0)
  1299. {
  1300. $resource = $this->getResourceModel();
  1301. $resource->saveConfig(rtrim($path, '/'), $value, $scope, $scopeId);
  1302. return $this;
  1303. }
  1304. /**
  1305. * Delete config value from DB
  1306. *
  1307. * @param string $path
  1308. * @param string $scope
  1309. * @param int $scopeId
  1310. * @return Mage_Core_Model_Config
  1311. */
  1312. public function deleteConfig($path, $scope = 'default', $scopeId = 0)
  1313. {
  1314. $resource = $this->getResourceModel();
  1315. $resource->deleteConfig(rtrim($path, '/'), $scope, $scopeId);
  1316. return $this;
  1317. }
  1318. /**
  1319. * Get fieldset from configuration
  1320. *
  1321. * @param string $name fieldset name
  1322. * @param string $root fieldset area, could be 'admin'
  1323. * @return null|array
  1324. */
  1325. public function getFieldset($name, $root = 'global')
  1326. {
  1327. $rootNode = $this->getNode($root.'/fieldsets');
  1328. if (!$rootNode) {
  1329. return null;
  1330. }
  1331. return $rootNode->$name ? $rootNode->$name->children() : null;
  1332. }
  1333. /**
  1334. * Get factory class name for for a resource
  1335. *
  1336. * @param string $modelClass
  1337. * @return string|false
  1338. */
  1339. protected function _getResourceModelFactoryClassName($modelClass)
  1340. {
  1341. $classArr = explode('/', $modelClass);
  1342. $resourceModel = false;
  1343. if (!isset($this->_xml->global->models->{$classArr[0]})) {
  1344. return false;
  1345. }
  1346. $module = $this->_xml->global->models->{$classArr[0]};
  1347. if ((count($classArr)==2)
  1348. && isset($module->{$classArr[1]}->resourceModel)
  1349. && $resourceInfo = $module->{$classArr[1]}->resourceModel) {
  1350. $resourceModel = (string) $resourceInfo;
  1351. }
  1352. elseif (isset($module->resourceModel) && $resourceInfo = $module->resourceModel) {
  1353. $resourceModel = (string) $resourceInfo;
  1354. }
  1355. if (!$resourceModel) {
  1356. return false;
  1357. }
  1358. return $resourceModel . '/' . $classArr[1];
  1359. }
  1360. /**
  1361. * Get a resource model class name
  1362. *
  1363. * @param string $modelClass
  1364. * @return string|false
  1365. */
  1366. public function getResourceModelClassName($modelClass)
  1367. {
  1368. $factoryName = $this->_getResourceModelFactoryClassName($modelClass);
  1369. if ($factoryName) {
  1370. return $this->getModelClassName($factoryName);
  1371. }
  1372. return false;
  1373. }
  1374. }