Version Notes
Initial release.
Download this release
Release Info
Developer | Severin Klingler |
Extension | store_dependency |
Version | 1.0.0 |
Comparing to | |
See all releases |
Version 1.0.0
- app/code/local/Customweb/Dependency/Helper/Config.php +332 -0
- app/code/local/Customweb/Dependency/Helper/Data.php +65 -0
- app/code/local/Customweb/Dependency/Helper/Element.php +223 -0
- app/code/local/Customweb/Dependency/Model/Category.php +16 -0
- app/code/local/Customweb/Dependency/Model/Config.php +17 -0
- app/code/local/Customweb/Dependency/Model/ConfigObserver.php +364 -0
- app/code/local/Customweb/Dependency/Model/Mysql4/Category.php +14 -0
- app/code/local/Customweb/Dependency/Model/Mysql4/Category/Collection.php +14 -0
- app/code/local/Customweb/Dependency/Model/Mysql4/Config.php +15 -0
- app/code/local/Customweb/Dependency/Model/Mysql4/Config/Collection.php +14 -0
- app/code/local/Customweb/Dependency/Model/Mysql4/Product.php +15 -0
- app/code/local/Customweb/Dependency/Model/Mysql4/Product/Collection.php +15 -0
- app/code/local/Customweb/Dependency/Model/Product.php +17 -0
- app/code/local/Customweb/Dependency/Model/Resource/Setup.php +12 -0
- app/code/local/Customweb/Dependency/controllers/TestController.php +12 -0
- app/code/local/Customweb/Dependency/etc/config.xml +108 -0
- app/code/local/Customweb/Dependency/sql/dependency_setup/mysql4-install-1.0.0.php +45 -0
- app/code/local/Mage/Core/Model/Config.php +1625 -0
- app/code/local/Varien/Data/Form/Element/Abstract.php +314 -0
- app/design/adminhtml/default/default/layout/dependency.xml +11 -0
- app/etc/modules/Customweb_Dependency.xml +11 -0
- js/customweb/dependency.js +116 -0
- package.xml +27 -0
- skin/adminhtml/base/default/css/dependency.css +76 -0
app/code/local/Customweb/Dependency/Helper/Config.php
ADDED
@@ -0,0 +1,332 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
::[Header]::
|
4 |
+
* @category Local
|
5 |
+
* @package Customweb_Dependency
|
6 |
+
* @link http://www.customweb.ch
|
7 |
+
*/
|
8 |
+
|
9 |
+
class Customweb_Dependency_Helper_Config extends Mage_Core_Helper_Abstract
|
10 |
+
{
|
11 |
+
/**
|
12 |
+
* Get all edges as a adjacency list where result[a] contains
|
13 |
+
* all the nodes that depend on a
|
14 |
+
*
|
15 |
+
* @param string $path
|
16 |
+
* @return array
|
17 |
+
*/
|
18 |
+
public function getDependentConfigEdges($path)
|
19 |
+
{
|
20 |
+
$edges = array();
|
21 |
+
$attributeCollection = Mage::getModel('dependency/config')->getCollection();
|
22 |
+
$attributeCollection->addFieldToFilter('path', $path);
|
23 |
+
|
24 |
+
foreach($attributeCollection as $att)
|
25 |
+
{
|
26 |
+
$edges[$att->getDependsOnScope() . '_' . $att->getDependsOnScopeId()][] = $att->getScope() . '_' . $att->getScopeId();
|
27 |
+
}
|
28 |
+
return $edges;
|
29 |
+
}
|
30 |
+
|
31 |
+
|
32 |
+
/**
|
33 |
+
* Get all edges as a adjacency list where result[a] contains
|
34 |
+
* all the nodes that a depends on
|
35 |
+
*
|
36 |
+
* @param string $path
|
37 |
+
* @return array
|
38 |
+
*/
|
39 |
+
public function getDependeeConfigEdges($path)
|
40 |
+
{
|
41 |
+
$edges = array();
|
42 |
+
$attributeCollection = Mage::getModel('dependency/config')->getCollection();
|
43 |
+
$attributeCollection->addFieldToFilter('path', $path);
|
44 |
+
|
45 |
+
foreach($attributeCollection as $att)
|
46 |
+
{
|
47 |
+
$edges[$att->getScope() . '_' . $att->getScopeId()] = $att->getDependsOnScope() . '_' . $att->getDependsOnScopeId();
|
48 |
+
}
|
49 |
+
return $edges;
|
50 |
+
}
|
51 |
+
|
52 |
+
/**
|
53 |
+
* Returns the dependency of an configuration entry.
|
54 |
+
*
|
55 |
+
* @param string $path
|
56 |
+
* @param string $scope
|
57 |
+
* @param string $scope_id
|
58 |
+
* @return Customweb_Dependency_Model_Config
|
59 |
+
*/
|
60 |
+
public function getConfigDependency($path,$scope,$scope_id)
|
61 |
+
{
|
62 |
+
$configCollection = Mage::getModel('dependency/config')->getCollection();
|
63 |
+
$configCollection->addFieldToFilter('path', $path)
|
64 |
+
->addFieldToFilter('scope', $scope)
|
65 |
+
->addFieldToFilter('scope_id', intval($scope_id));
|
66 |
+
$configDependency = $configCollection->getFirstItem();
|
67 |
+
if(!$configDependency->getId())
|
68 |
+
{
|
69 |
+
$configDependency = Mage::getModel('dependency/config');
|
70 |
+
$configDependency->setPath($path);
|
71 |
+
$configDependency->setScope($scope);
|
72 |
+
$configDependency->setScopeId($scope_id);
|
73 |
+
}
|
74 |
+
return $configDependency;
|
75 |
+
}
|
76 |
+
|
77 |
+
/**
|
78 |
+
* Translates between website and store names and corresponding
|
79 |
+
* IDs.
|
80 |
+
*
|
81 |
+
* @param string $websiteName
|
82 |
+
* @param string $storeName
|
83 |
+
*/
|
84 |
+
public function getConfigId($websiteName, $storeName)
|
85 |
+
{
|
86 |
+
$this->initTranslateArrays();
|
87 |
+
|
88 |
+
if($storeName == null)
|
89 |
+
{
|
90 |
+
return $this->websiteNameToCode[$websiteName];
|
91 |
+
}
|
92 |
+
else
|
93 |
+
{
|
94 |
+
return $this->storeNameToCode[$storeName];
|
95 |
+
}
|
96 |
+
|
97 |
+
}
|
98 |
+
|
99 |
+
/**
|
100 |
+
* Translates the select identifier value to a pair of
|
101 |
+
* scope and scopeId.
|
102 |
+
*
|
103 |
+
* This code is based on Mage_Adminhtml_Model_Config_Data::_getScope()
|
104 |
+
*
|
105 |
+
* @param string $string
|
106 |
+
* @return array
|
107 |
+
*/
|
108 |
+
public function getScope($string)
|
109 |
+
{
|
110 |
+
try {
|
111 |
+
$parts = explode('_',$string,2);
|
112 |
+
} catch (Exception $e) {
|
113 |
+
throw new Exception(print_r($string,true) . $e->getMessage());
|
114 |
+
}
|
115 |
+
|
116 |
+
if(count($parts) == 2)
|
117 |
+
{
|
118 |
+
$scope = $parts[0] . 's';
|
119 |
+
$scopeCode = $parts[1];
|
120 |
+
$scopeId = (int)Mage::getConfig()->getNode($scope . '/' . $scopeCode . '/system/' . $parts[0] . '/id');
|
121 |
+
}
|
122 |
+
else
|
123 |
+
{
|
124 |
+
$scope = 'default';
|
125 |
+
$scopeId = 0;
|
126 |
+
}
|
127 |
+
return array('scope' => $scope, 'scope_id' => $scopeId);
|
128 |
+
}
|
129 |
+
|
130 |
+
/**
|
131 |
+
* Splits a website/store identifier string of the form "stores_2" into an array.
|
132 |
+
*
|
133 |
+
* @param string $string website/store identifier
|
134 |
+
* @return array
|
135 |
+
*/
|
136 |
+
public function splitScopeString($string)
|
137 |
+
{
|
138 |
+
$parts = explode('_',$string,2);
|
139 |
+
return array('scope' => $parts[0], 'scope_id' => $parts[1]);
|
140 |
+
}
|
141 |
+
|
142 |
+
|
143 |
+
/**
|
144 |
+
* Create the mappings between website/store identifier strings and the website/store
|
145 |
+
* codes.
|
146 |
+
*/
|
147 |
+
private function initTranslateArrays()
|
148 |
+
{
|
149 |
+
$storeModel = Mage::getSingleton('adminhtml/system_store');
|
150 |
+
|
151 |
+
if($this->websiteNameToCode == null)
|
152 |
+
{
|
153 |
+
$this->websiteNameToCode = array();
|
154 |
+
foreach ($storeModel->getWebsiteCollection() as $website)
|
155 |
+
{
|
156 |
+
$this->websiteNameToCode[$website->getCode()] = $this->getScope('website_' . $website->getCode());
|
157 |
+
$scope = $this->getScope('website_' . $website->getCode());
|
158 |
+
$this->websiteCodeToName[$scope['scope_id']] = $website->getCode();
|
159 |
+
}
|
160 |
+
}
|
161 |
+
if($this->storeNameToCode == null)
|
162 |
+
{
|
163 |
+
$this->storeNameToCode = array();
|
164 |
+
foreach ($storeModel->getStoreCollection() as $store)
|
165 |
+
{
|
166 |
+
$this->storeNameToCode[$store->getCode()] = $this->getScope('store_' . $store->getCode());
|
167 |
+
$scope = $this->getScope('store_' . $store->getCode());
|
168 |
+
$this->storeCodeToName[$scope['scope_id']] = $store->getCode();
|
169 |
+
}
|
170 |
+
}
|
171 |
+
}
|
172 |
+
|
173 |
+
/**
|
174 |
+
* Checks for loops if we add the given new dependency.
|
175 |
+
*
|
176 |
+
* @param mixed $dependency
|
177 |
+
* @param string $type
|
178 |
+
* @return boolean True if the dependency graph does not contain a cylce starting at the specified node
|
179 |
+
*/
|
180 |
+
public function doesYieldNoLoop($dependency){
|
181 |
+
|
182 |
+
$edgesToDependent = $this->getDependentConfigEdges(
|
183 |
+
$dependency->getPath());
|
184 |
+
|
185 |
+
$node = $dependency->getScope() . '_' . $dependency->getScopeId();
|
186 |
+
$newDependency = $dependency->getDependsOnScope() . '_' . $dependency->getDependsOnScopeId();
|
187 |
+
|
188 |
+
|
189 |
+
|
190 |
+
// Only add the dependency if it does not already exist.
|
191 |
+
if(isset($edgesToDependent[$newDependency]))
|
192 |
+
{
|
193 |
+
if(!in_array($node,
|
194 |
+
$edgesToDependent[$newDependency]))
|
195 |
+
{
|
196 |
+
$edgesToDependent[$newDependency][] = $node;
|
197 |
+
}
|
198 |
+
}
|
199 |
+
else
|
200 |
+
{
|
201 |
+
$edgesToDependent[$newDependency] = array($node);
|
202 |
+
}
|
203 |
+
|
204 |
+
return Mage::helper('dependency')->dfs($node,$edgesToDependent);
|
205 |
+
}
|
206 |
+
|
207 |
+
/**
|
208 |
+
* Returns the path of the config value extracted from the html id and the element name
|
209 |
+
* of the respective form element.
|
210 |
+
*
|
211 |
+
* @param string $htmlId
|
212 |
+
* @param string $elementName
|
213 |
+
* @return string
|
214 |
+
*/
|
215 |
+
public function getPath($htmlId, $elementName)
|
216 |
+
{
|
217 |
+
preg_match('/groups\[(.*)\]\[fields\]\[(.*)\]\[value/i', $elementName, $m);
|
218 |
+
|
219 |
+
$group = $m[1];
|
220 |
+
$entry = $m[2];
|
221 |
+
preg_match('/(.*)\_' . $m[1] . '/', $htmlId, $m);
|
222 |
+
$base = $m[1];
|
223 |
+
|
224 |
+
return $this->createPath($base,$group,$entry);
|
225 |
+
}
|
226 |
+
|
227 |
+
/**
|
228 |
+
* Delete the dependency from the config value given, if any.
|
229 |
+
*
|
230 |
+
* @param string $path
|
231 |
+
* @param string $scope
|
232 |
+
* @param string $scopeId
|
233 |
+
*/
|
234 |
+
public function deleteDependenyOf($path, $scope, $scopeId)
|
235 |
+
{
|
236 |
+
$dependency = $this->getConfigDependency($path,$scope,$scopeId);
|
237 |
+
if($dependency->getId())
|
238 |
+
{
|
239 |
+
$dependency->delete();
|
240 |
+
}
|
241 |
+
}
|
242 |
+
|
243 |
+
/**
|
244 |
+
* Creates the correct path to the config value. Especially it handles custom
|
245 |
+
* defined field paths.
|
246 |
+
* Code taken from Mage_Adminhtml_Model_Config_Data::save()
|
247 |
+
*
|
248 |
+
* @param string $section
|
249 |
+
* @param string $group
|
250 |
+
* @param string $name
|
251 |
+
* @return string
|
252 |
+
*/
|
253 |
+
public function createPath($section,$group,$name)
|
254 |
+
{
|
255 |
+
$path = $section . '/' . $group . '/' . $name;
|
256 |
+
$fieldConfig = $this->getSections()->descend($section.'/groups/'.$group.'/fields/'.$name);
|
257 |
+
|
258 |
+
/**
|
259 |
+
* Look for custom defined field path
|
260 |
+
*/
|
261 |
+
if (is_object($fieldConfig)) {
|
262 |
+
$configPath = (string)$fieldConfig->config_path;
|
263 |
+
if (!empty($configPath) && strrpos($configPath, '/') > 0) {
|
264 |
+
$path = $configPath;
|
265 |
+
}
|
266 |
+
}
|
267 |
+
return $path;
|
268 |
+
}
|
269 |
+
|
270 |
+
/**
|
271 |
+
* Returns the store name based on the store code
|
272 |
+
* @param int $code
|
273 |
+
* @return string
|
274 |
+
*/
|
275 |
+
public function getStoreName($code)
|
276 |
+
{
|
277 |
+
$this->initTranslateArrays();
|
278 |
+
return $this->storeCodeToName[$code];
|
279 |
+
}
|
280 |
+
|
281 |
+
/**
|
282 |
+
* Returns the website name based on the website code.
|
283 |
+
* @param int $code
|
284 |
+
* @return string
|
285 |
+
*/
|
286 |
+
public function getWebsiteName($code)
|
287 |
+
{
|
288 |
+
$this->initTranslateArrays();
|
289 |
+
return $this->websiteCodeToName[$code];
|
290 |
+
}
|
291 |
+
|
292 |
+
/**
|
293 |
+
* Makes sure the dependency is valid. This does not check for loops in the
|
294 |
+
* dependency graphs it only makes sure no dependencies from website level to store level
|
295 |
+
* are possible.
|
296 |
+
*
|
297 |
+
* @param Customweb_Dependency_Model_Config $dependency
|
298 |
+
* @param string $throwException True(default) the method throws an exception, false the method returns false on invalid dependencies.
|
299 |
+
* @throws Exception
|
300 |
+
* @return boolean
|
301 |
+
*/
|
302 |
+
public function validateDependency(Customweb_Dependency_Model_Config $dependency, $throwException=true)
|
303 |
+
{
|
304 |
+
if($dependency->getScope() == 'websites' && $dependency->getDependsOnScope() == 'stores')
|
305 |
+
{
|
306 |
+
if($throwException)
|
307 |
+
{
|
308 |
+
throw new Exception(Mage::helper('dependency')->__("A website cannot depend on a store view."));
|
309 |
+
}
|
310 |
+
return false;
|
311 |
+
}
|
312 |
+
return true;
|
313 |
+
}
|
314 |
+
|
315 |
+
/**
|
316 |
+
* Returns all configuration sections.
|
317 |
+
*/
|
318 |
+
private function getSections()
|
319 |
+
{
|
320 |
+
if($this->sections == null){
|
321 |
+
$this->sections = Mage::getModel('adminhtml/config')->getSections();
|
322 |
+
}
|
323 |
+
return $this->sections;
|
324 |
+
}
|
325 |
+
|
326 |
+
protected $storeNameToCode = null;
|
327 |
+
protected $websiteNameToCode = null;
|
328 |
+
protected $storeCodeToName = null;
|
329 |
+
protected $websiteCodeToName = null;
|
330 |
+
protected $sections = null;
|
331 |
+
|
332 |
+
}
|
app/code/local/Customweb/Dependency/Helper/Data.php
ADDED
@@ -0,0 +1,65 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
::[Header]::
|
4 |
+
* @category Local
|
5 |
+
* @package Customweb_Dependency
|
6 |
+
* @link http://www.customweb.ch
|
7 |
+
*/
|
8 |
+
|
9 |
+
class Customweb_Dependency_Helper_Data extends Mage_Core_Helper_Abstract
|
10 |
+
{
|
11 |
+
|
12 |
+
|
13 |
+
/**
|
14 |
+
* Traverses the graph provided by $edges starting at node $node and looks for
|
15 |
+
* cycles.
|
16 |
+
*
|
17 |
+
* @param int $node
|
18 |
+
* @param array $edges
|
19 |
+
* @return boolean True if graph contains no cylces starting at $node
|
20 |
+
*/
|
21 |
+
public function dfs($node,$edges)
|
22 |
+
{
|
23 |
+
static $visited = array();
|
24 |
+
$noLoop = true;
|
25 |
+
if(array_key_exists($node,$visited) && $visited[$node] == 1)
|
26 |
+
{
|
27 |
+
return false;
|
28 |
+
}
|
29 |
+
else
|
30 |
+
{
|
31 |
+
$visited[$node] = 1;
|
32 |
+
|
33 |
+
if(isset($edges[$node]))
|
34 |
+
{
|
35 |
+
foreach($edges[$node] as $nextNode)
|
36 |
+
{
|
37 |
+
$noLoop = $noLoop && $this->dfs($nextNode,$edges);
|
38 |
+
}
|
39 |
+
}
|
40 |
+
}
|
41 |
+
|
42 |
+
$visited[$node] = 0;
|
43 |
+
return $noLoop;
|
44 |
+
}
|
45 |
+
|
46 |
+
|
47 |
+
|
48 |
+
/**
|
49 |
+
* Returns an array of all store ids.
|
50 |
+
*
|
51 |
+
* @return array List of store ids.
|
52 |
+
*/
|
53 |
+
public function getAllStoreIds()
|
54 |
+
{
|
55 |
+
return array_keys(Mage::app()->getStores());
|
56 |
+
}
|
57 |
+
|
58 |
+
|
59 |
+
|
60 |
+
/**
|
61 |
+
* Stores the mapping from type names to model names.
|
62 |
+
* @var array
|
63 |
+
*/
|
64 |
+
protected $typeToModel = null;
|
65 |
+
}
|
app/code/local/Customweb/Dependency/Helper/Element.php
ADDED
@@ -0,0 +1,223 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
::[Header]::
|
4 |
+
* @category Local
|
5 |
+
* @package Customweb_Dependency
|
6 |
+
* @link http://www.customweb.ch
|
7 |
+
*/
|
8 |
+
|
9 |
+
class Customweb_Dependency_Helper_Element extends Mage_Core_Helper_Abstract
|
10 |
+
{
|
11 |
+
|
12 |
+
private $name = null;
|
13 |
+
private $htmlId = null;
|
14 |
+
private $elementId = null;
|
15 |
+
private $params = null;
|
16 |
+
|
17 |
+
/**
|
18 |
+
* Returns a HTML suffix that is added to every element of applicable admin forms.
|
19 |
+
* The suffix contains a select field that allows the user to select on what store view/website
|
20 |
+
* the element is dependent.
|
21 |
+
*
|
22 |
+
* @param string $name Name of the element
|
23 |
+
* @param string $htmlId HTML ID of the element
|
24 |
+
* @param string $elementId ID of the element
|
25 |
+
* @param array $params HTTP Request parameters
|
26 |
+
* @return string
|
27 |
+
*/
|
28 |
+
public function getElementSuffix($name,$htmlId,$elementId,$params)
|
29 |
+
{
|
30 |
+
$this->name = $name;
|
31 |
+
$this->htmlId = $htmlId;
|
32 |
+
$this->elementId = $elementId;
|
33 |
+
$this->params = $params;
|
34 |
+
$suffix = "";
|
35 |
+
|
36 |
+
|
37 |
+
|
38 |
+
|
39 |
+
$suffix = $this->getSuffixForConfigElement();
|
40 |
+
|
41 |
+
return $suffix;
|
42 |
+
}
|
43 |
+
|
44 |
+
|
45 |
+
|
46 |
+
|
47 |
+
/**
|
48 |
+
* Returns the select field for configuration elements.
|
49 |
+
*
|
50 |
+
* @return string HTML suffix
|
51 |
+
*/
|
52 |
+
private function getSuffixForConfigElement()
|
53 |
+
{
|
54 |
+
$suffix = "";
|
55 |
+
|
56 |
+
if(isset($this->params['website']))
|
57 |
+
{
|
58 |
+
$websiteName = $this->params['website'];
|
59 |
+
$storeName = (isset($this->params['store']) ? $this->params['store'] : null);
|
60 |
+
$helper = Mage::helper('dependency/config');
|
61 |
+
|
62 |
+
if(preg_match('/groups\[(.*)\]\[fields\]\[(.*)\]\[value/i',$this->name))
|
63 |
+
{
|
64 |
+
$dependency = Mage::getModel('dependency/config');
|
65 |
+
$path = $helper->getPath($this->htmlId, $this->name);
|
66 |
+
$scope = $helper->getConfigId($websiteName,$storeName);
|
67 |
+
$dependsOn = $helper->getConfigDependency($path,$scope['scope'],$scope['scope_id']);
|
68 |
+
|
69 |
+
$type = 'config';
|
70 |
+
|
71 |
+
$selectName = preg_replace('/^(.*)\[value\]/i', '$1[source]' ,$this->name);
|
72 |
+
$dependencyName = preg_replace('/^(.*)\[value\]/i', '$1[dependency]' ,$this->name);
|
73 |
+
|
74 |
+
$selectHtml = $this->createScopeDependencySelect($selectName,$dependsOn);
|
75 |
+
|
76 |
+
$suffix = '<input type="hidden" name="' . $dependencyName . '" value="1" />';
|
77 |
+
$suffix .= '<div class="dependency-box"><div class="dependency-select">' . $selectHtml . '</div></div>';
|
78 |
+
}
|
79 |
+
}
|
80 |
+
return $suffix;
|
81 |
+
}
|
82 |
+
|
83 |
+
/**
|
84 |
+
* Creates a select element that looks like the standard magento store switcher select
|
85 |
+
* for configurations.
|
86 |
+
* This code is partly taken from template/system/config/switcher.phtml
|
87 |
+
*/
|
88 |
+
private function createScopeDependencySelect($name,$selected)
|
89 |
+
{
|
90 |
+
$dependsOnWebsite = false;
|
91 |
+
$dependsOnStore = false;
|
92 |
+
$scope = $selected->getDependsOnScope();
|
93 |
+
$helper = Mage::helper('dependency/config');
|
94 |
+
|
95 |
+
|
96 |
+
|
97 |
+
if($scope == 'websites')
|
98 |
+
{
|
99 |
+
$dependsOnWebsite = $helper->getWebsiteName($selected->getDependsOnScopeId());
|
100 |
+
}
|
101 |
+
elseif ($scope == 'stores')
|
102 |
+
{
|
103 |
+
$dependsOnStore = $helper->getStoreName($selected->getDependsOnScopeId());
|
104 |
+
}
|
105 |
+
|
106 |
+
$html = '<select id="store_switcher" class="config-dependency-selector" dependencyfor="' . $this->htmlId .'" name="' . $name . '" onchange="' . $this->getUpdateJsString() .'" >';
|
107 |
+
foreach ($this->getStoreSelectOptions($dependsOnStore,$dependsOnWebsite) as $_value => $_option)
|
108 |
+
{
|
109 |
+
if (isset($_option['is_group']))
|
110 |
+
{
|
111 |
+
if ($_option['is_close'])
|
112 |
+
{
|
113 |
+
$html .= '</optgroup>';
|
114 |
+
}
|
115 |
+
else
|
116 |
+
{
|
117 |
+
$html .= '<optgroup label="' . $this->escapeHtml($_option['label']) . '" style="' . $_option['style'] . '">';
|
118 |
+
}
|
119 |
+
continue;
|
120 |
+
}
|
121 |
+
// Check for dependency
|
122 |
+
$scope = $helper->getScope($_value);
|
123 |
+
$selected->setDependsOnScope($scope['scope']);
|
124 |
+
$selected->setDependsOnScopeId($scope['scope_id']);
|
125 |
+
$optionClass = 'dependency-check-failed';
|
126 |
+
if($helper->validateDependency($selected,false))
|
127 |
+
{
|
128 |
+
$optionClass = 'dependency-loop';
|
129 |
+
if(Mage::helper('dependency/config')->doesYieldNoLoop($selected))
|
130 |
+
{
|
131 |
+
$optionClass = 'dependency-ok';
|
132 |
+
}
|
133 |
+
}
|
134 |
+
$html .= '<option value="' . $this->escapeHtml($_value) . '" url="' . $_option['url'] . '" ' . ($_option['selected'] ? 'selected="selected"' : '') . ' class="' . $optionClass . '" ' . ' style="' . $_option['style'] . '">';
|
135 |
+
$html .= $this->escapeHtml($_option['label']) . '</option>';
|
136 |
+
}
|
137 |
+
$html .= '</select>';
|
138 |
+
return $html;
|
139 |
+
}
|
140 |
+
|
141 |
+
/**
|
142 |
+
* Taken from Mage_Adminhtml_Block_System_Config_Switcher
|
143 |
+
*/
|
144 |
+
private function getStoreSelectOptions($curStore,$curWebsite)
|
145 |
+
{
|
146 |
+
$section = $this->params['section'];
|
147 |
+
|
148 |
+
$storeModel = Mage::getSingleton('adminhtml/system_store');
|
149 |
+
/* @var $storeModel Mage_Adminhtml_Model_System_Store */
|
150 |
+
|
151 |
+
$url = Mage::getModel('adminhtml/url');
|
152 |
+
|
153 |
+
$options = array();
|
154 |
+
$options['default'] = array(
|
155 |
+
'label' => Mage::helper('dependency')->__('No dependency'),
|
156 |
+
'url' => $url->getUrl('*/*/*', array('section'=>$section)),
|
157 |
+
'selected' => !$curWebsite && !$curStore,
|
158 |
+
'style' => 'background:#ccc; font-weight:bold;',
|
159 |
+
);
|
160 |
+
|
161 |
+
foreach ($storeModel->getWebsiteCollection() as $website) {
|
162 |
+
$websiteShow = false;
|
163 |
+
foreach ($storeModel->getGroupCollection() as $group) {
|
164 |
+
if ($group->getWebsiteId() != $website->getId()) {
|
165 |
+
continue;
|
166 |
+
}
|
167 |
+
$groupShow = false;
|
168 |
+
foreach ($storeModel->getStoreCollection() as $store) {
|
169 |
+
if ($store->getGroupId() != $group->getId()) {
|
170 |
+
continue;
|
171 |
+
}
|
172 |
+
if (!$websiteShow) {
|
173 |
+
$websiteShow = true;
|
174 |
+
$options['website_' . $website->getCode()] = array(
|
175 |
+
'label' => $website->getName(),
|
176 |
+
'url' => $url->getUrl('*/*/*', array('section'=>$section, 'website'=>$website->getCode())),
|
177 |
+
'selected' => !$curStore && $curWebsite == $website->getCode(),
|
178 |
+
'style' => 'padding-left:16px; background:#DDD; font-weight:bold;',
|
179 |
+
);
|
180 |
+
}
|
181 |
+
if (!$groupShow) {
|
182 |
+
$groupShow = true;
|
183 |
+
$options['group_' . $group->getId() . '_open'] = array(
|
184 |
+
'is_group' => true,
|
185 |
+
'is_close' => false,
|
186 |
+
'label' => $group->getName(),
|
187 |
+
'style' => 'padding-left:32px;'
|
188 |
+
);
|
189 |
+
}
|
190 |
+
$options['store_' . $store->getCode()] = array(
|
191 |
+
'label' => $store->getName(),
|
192 |
+
'url' => $url->getUrl('*/*/*', array('section'=>$section, 'website'=>$website->getCode(), 'store'=>$store->getCode())),
|
193 |
+
'selected' => $curStore == $store->getCode(),
|
194 |
+
'style' => '',
|
195 |
+
);
|
196 |
+
}
|
197 |
+
if ($groupShow) {
|
198 |
+
$options['group_' . $group->getId() . '_close'] = array(
|
199 |
+
'is_group' => true,
|
200 |
+
'is_close' => true,
|
201 |
+
);
|
202 |
+
}
|
203 |
+
}
|
204 |
+
}
|
205 |
+
|
206 |
+
return $options;
|
207 |
+
}
|
208 |
+
|
209 |
+
private function getUpdateJsString()
|
210 |
+
{
|
211 |
+
$loopError = Mage::helper('dependency')->__("Can not depend on this store view. Loop detected.");
|
212 |
+
$dependencyCheckError = Mage::helper('dependency')->__("A website cannot depend on a store view.");
|
213 |
+
|
214 |
+
return 'updateDependencySelect(this,\'' . $this->htmlId .'\',false,\'' . $loopError . '\',\'' . $dependencyCheckError . '\')';
|
215 |
+
}
|
216 |
+
|
217 |
+
|
218 |
+
|
219 |
+
|
220 |
+
|
221 |
+
|
222 |
+
|
223 |
+
}
|
app/code/local/Customweb/Dependency/Model/Category.php
ADDED
@@ -0,0 +1,16 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
::[Header]::
|
4 |
+
* @category Local
|
5 |
+
* @package Customweb_Dependency
|
6 |
+
* @link http://www.customweb.ch
|
7 |
+
*/
|
8 |
+
|
9 |
+
class Customweb_Dependency_Model_Category extends Mage_Core_Model_Abstract
|
10 |
+
{
|
11 |
+
protected function _construct()
|
12 |
+
{
|
13 |
+
$this->_init('dependency/category');
|
14 |
+
}
|
15 |
+
|
16 |
+
}
|
app/code/local/Customweb/Dependency/Model/Config.php
ADDED
@@ -0,0 +1,17 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/**
|
4 |
+
::[Header]::
|
5 |
+
* @category Local
|
6 |
+
* @package Customweb_Dependency
|
7 |
+
* @link http://www.customweb.ch
|
8 |
+
*/
|
9 |
+
|
10 |
+
class Customweb_Dependency_Model_Config extends Mage_Core_Model_Abstract
|
11 |
+
{
|
12 |
+
protected function _construct()
|
13 |
+
{
|
14 |
+
$this->_init('dependency/config');
|
15 |
+
}
|
16 |
+
|
17 |
+
}
|
app/code/local/Customweb/Dependency/Model/ConfigObserver.php
ADDED
@@ -0,0 +1,364 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
::[Header]::
|
4 |
+
* @category Local
|
5 |
+
* @package Customweb_Dependency
|
6 |
+
* @link http://www.customweb.ch
|
7 |
+
*/
|
8 |
+
|
9 |
+
class Customweb_Dependency_Model_ConfigObserver
|
10 |
+
{
|
11 |
+
/**
|
12 |
+
* The method is registered to the event 'model_config_data_save_before'. It updates
|
13 |
+
* the dependency graph.
|
14 |
+
*
|
15 |
+
* @param Varien_Event_Observer $observer
|
16 |
+
*/
|
17 |
+
public function configSaveBefore(Varien_Event_Observer $observer)
|
18 |
+
{
|
19 |
+
$event = $observer->getEvent();
|
20 |
+
$config = $event->getObject();
|
21 |
+
|
22 |
+
$section = $config->getSection();
|
23 |
+
$website = $config->getWebsite();
|
24 |
+
$store = $config->getStore();
|
25 |
+
$groups = $config->getGroups();
|
26 |
+
$scope = $config->getScope();
|
27 |
+
$scopeId = $config->getScopeId();
|
28 |
+
$this->handleConfigs = array();
|
29 |
+
|
30 |
+
$write = Mage::getSingleton('core/resource')->getConnection('core_write');
|
31 |
+
$write->beginTransaction();
|
32 |
+
|
33 |
+
|
34 |
+
try
|
35 |
+
{
|
36 |
+
foreach ($groups as $group => $groupData)
|
37 |
+
{
|
38 |
+
foreach($groupData['fields'] as $name => $data)
|
39 |
+
{
|
40 |
+
if(isset($data['dependency']))
|
41 |
+
{
|
42 |
+
$path = $this->getHelper()->createPath($section, $group, $name);
|
43 |
+
$dependency = $this->getHelper()->getConfigDependency($path,$scope,$scopeId);
|
44 |
+
$source = 'default';
|
45 |
+
|
46 |
+
if(isset($data['source']))
|
47 |
+
{
|
48 |
+
$source = $this->getFirstElementIfArray($data['source']);
|
49 |
+
}
|
50 |
+
|
51 |
+
if(isset($data['inherit']) || $source == 'default')
|
52 |
+
{
|
53 |
+
$dependency->delete();
|
54 |
+
|
55 |
+
// Config values that are inherited have to be rememered, for later processing
|
56 |
+
$this->handleConfigs[] = array('path' => $path, 'scope' => $scope, 'scopeId' => $scopeId);
|
57 |
+
|
58 |
+
}
|
59 |
+
else
|
60 |
+
{
|
61 |
+
// Create dependency
|
62 |
+
$scopeInfo = $this->getHelper()->getScope($source);
|
63 |
+
$dependency->setDependsOnScope($scopeInfo['scope']);
|
64 |
+
$dependency->setDependsOnScopeId($scopeInfo['scope_id']);
|
65 |
+
$this->getHelper()->validateDependency($dependency);
|
66 |
+
$dependency->save();
|
67 |
+
|
68 |
+
|
69 |
+
// Save a config value
|
70 |
+
//$configModel = new Mage_Core_Model_Config();
|
71 |
+
//$configModel ->saveConfig('general/country/default', "US", $scope, $scopeId);
|
72 |
+
}
|
73 |
+
}
|
74 |
+
}
|
75 |
+
}
|
76 |
+
$write->commit();
|
77 |
+
}
|
78 |
+
catch(Exception $e)
|
79 |
+
{
|
80 |
+
while($write->getTransactionLevel() > 0)
|
81 |
+
{
|
82 |
+
$write->rollback();
|
83 |
+
}
|
84 |
+
throw $e;
|
85 |
+
}
|
86 |
+
}
|
87 |
+
|
88 |
+
/**
|
89 |
+
* This method is registered to the event 'core_config_data_delete_after'. All dependencies
|
90 |
+
* are resolved after deleting and inherited values are updated.
|
91 |
+
*
|
92 |
+
* @param Varien_Event_Observer $observer
|
93 |
+
*/
|
94 |
+
public function configDeleteAfter(Varien_Event_Observer $observer)
|
95 |
+
{
|
96 |
+
$this->configSaveAfter($observer);
|
97 |
+
}
|
98 |
+
|
99 |
+
/**
|
100 |
+
* This method is registered to the event 'core_config_data_save_after'. All dependencies
|
101 |
+
* are resolved after saving and inherited values are updated.
|
102 |
+
*
|
103 |
+
* @param Varien_Event_Observer $observer
|
104 |
+
*/
|
105 |
+
public function configSaveAfter(Varien_Event_Observer $observer)
|
106 |
+
{
|
107 |
+
// We keep track of wheter we are already in the dependency updating process
|
108 |
+
static $configUpdateInProgress = false;
|
109 |
+
|
110 |
+
if(!$configUpdateInProgress)
|
111 |
+
{
|
112 |
+
$configUpdateInProgress = true;
|
113 |
+
$configData = $observer->getEvent()->getConfigData();
|
114 |
+
|
115 |
+
$path = $configData->getPath();
|
116 |
+
$scope = $configData->getScope();
|
117 |
+
$scopeId = $configData->getScopeId();
|
118 |
+
|
119 |
+
$this->handleConfigs[] = array('path' => $path, 'scope' => $scope, 'scopeId' => $scopeId);
|
120 |
+
$this->saveUpdateConfig($this->handleConfigs);
|
121 |
+
|
122 |
+
$configUpdateInProgress = false;
|
123 |
+
}
|
124 |
+
}
|
125 |
+
|
126 |
+
/**
|
127 |
+
* This method listens to the event 'core_model_config_save_before'.
|
128 |
+
* This is a CUSTOM EVENT that is introduced in local/Mage/Core/Model/Config.php to
|
129 |
+
* handle changes in config values from code and not the UI.
|
130 |
+
* The dependency for the changed config value is removed if one exists and dependent values
|
131 |
+
* are updateted.
|
132 |
+
*
|
133 |
+
* @param Varien_Event_Observer $observer
|
134 |
+
*/
|
135 |
+
public function coreConfigSaveAfter(Varien_Event_Observer $observer)
|
136 |
+
{
|
137 |
+
$path = $observer->getPath();
|
138 |
+
$scope = $observer->getScope();
|
139 |
+
$scopeId = $observer->getScopeId();
|
140 |
+
|
141 |
+
$write = Mage::getSingleton('core/resource')->getConnection('core_write');
|
142 |
+
$write->beginTransaction();
|
143 |
+
|
144 |
+
try
|
145 |
+
{
|
146 |
+
$this->getHelper()->deleteDependenyOf($path,$scope,$scopeId);
|
147 |
+
$this->saveUpdateConfig(array('path' => $path, 'scope' => $scope, 'scopeId' => $scopeId));
|
148 |
+
}
|
149 |
+
catch(Exception $e)
|
150 |
+
{
|
151 |
+
while($write->getTransactionLevel() > 0)
|
152 |
+
{
|
153 |
+
$write->rollback();
|
154 |
+
}
|
155 |
+
throw $e;
|
156 |
+
}
|
157 |
+
|
158 |
+
if($write->getTransactionLevel() >= 1)
|
159 |
+
{
|
160 |
+
$write->commit();
|
161 |
+
}
|
162 |
+
}
|
163 |
+
|
164 |
+
/**
|
165 |
+
* Handles all the config values we need to update.
|
166 |
+
* @param array $configs
|
167 |
+
*/
|
168 |
+
protected function saveUpdateConfig($configs)
|
169 |
+
{
|
170 |
+
foreach($configs as $config)
|
171 |
+
{
|
172 |
+
$path = $config['path'];
|
173 |
+
$scope = $config['scope'];
|
174 |
+
$scopeId = $config['scopeId'];
|
175 |
+
$allConfigData = $this->getAllConfigs($path);
|
176 |
+
|
177 |
+
if($scope == 'default' || preg_match('/website/i',$scope) || !isset($allConfigData[$scope . '_' . $scopeId]))
|
178 |
+
{
|
179 |
+
foreach($allConfigData as $entity)
|
180 |
+
{
|
181 |
+
$this->updateAllChildren($path, $entity, $allConfigData);
|
182 |
+
}
|
183 |
+
}
|
184 |
+
else
|
185 |
+
{
|
186 |
+
$entity = $allConfigData[$scope . '_' . $scopeId];
|
187 |
+
$this->updateAllChildren($path, $entity, $allConfigData);
|
188 |
+
}
|
189 |
+
|
190 |
+
$this->saveAllConfigData($allConfigData);
|
191 |
+
}
|
192 |
+
}
|
193 |
+
|
194 |
+
/**
|
195 |
+
* Updates all children of $possibleChild in the dependency graph.
|
196 |
+
*
|
197 |
+
* @param string $path
|
198 |
+
* @param Mage_Core_Config_Data $possibleChild
|
199 |
+
* @param array $allConfigData
|
200 |
+
*/
|
201 |
+
protected function updateAllChildren($path, $possibleChild, $allConfigData)
|
202 |
+
{
|
203 |
+
$edgesToDependent = $this->getHelper()->getDependentConfigEdges($path);
|
204 |
+
$edgesFromDependent = $this->getHelper()->getDependeeConfigEdges($path);
|
205 |
+
$start = $possibleChild->getScope() . "_" . $possibleChild->getScopeId();
|
206 |
+
$updateRoot = false;
|
207 |
+
$value = $possibleChild->getValue();
|
208 |
+
|
209 |
+
// If current node has a parent in the dependency graph
|
210 |
+
if(isset($edgesFromDependent[$start]))
|
211 |
+
{
|
212 |
+
$parent = $edgesFromDependent[$start];
|
213 |
+
$value = $this->getParentValue($parent,$allConfigData,$path);
|
214 |
+
$updateRoot = true;
|
215 |
+
}
|
216 |
+
|
217 |
+
$this->dfs($start, $allConfigData, $edgesToDependent, $value ,$updateRoot);
|
218 |
+
}
|
219 |
+
|
220 |
+
private function dfs($node, $allNodes, $edges, $value, $update)
|
221 |
+
{
|
222 |
+
static $visited = array();
|
223 |
+
if(array_key_exists($node,$visited) && $visited[$node] == 1)
|
224 |
+
{
|
225 |
+
throw new Exception(Mage::helper('dependency')->__("Dependency loop detected."));
|
226 |
+
}
|
227 |
+
else
|
228 |
+
{
|
229 |
+
$visited[$node] = 1;
|
230 |
+
if($update)
|
231 |
+
{
|
232 |
+
$s = $allNodes[$node];
|
233 |
+
if($s->getValue() != $value)
|
234 |
+
{
|
235 |
+
$s->setValue($value);
|
236 |
+
}
|
237 |
+
}
|
238 |
+
|
239 |
+
if(isset($edges[$node]))
|
240 |
+
{
|
241 |
+
foreach($edges[$node] as $nextNode)
|
242 |
+
{
|
243 |
+
$this->dfs($nextNode, $allNodes, $edges, $value, true);
|
244 |
+
}
|
245 |
+
}
|
246 |
+
}
|
247 |
+
|
248 |
+
$visited[$node] = 0;
|
249 |
+
}
|
250 |
+
|
251 |
+
/**
|
252 |
+
* Returns the value of the $parent node. This is a bit tricky as config values
|
253 |
+
* that use default values do no longer exist in the database.
|
254 |
+
*
|
255 |
+
* @param string $parent
|
256 |
+
* @param array $allConfigData
|
257 |
+
* @param string $path
|
258 |
+
* @return mixed
|
259 |
+
*/
|
260 |
+
private function getParentValue($parent, $allConfigData, $path)
|
261 |
+
{
|
262 |
+
// If the parent uses default no config value exists.
|
263 |
+
if(!isset($allConfigData[$parent]))
|
264 |
+
{
|
265 |
+
$scope = $this->getHelper()->splitScopeString($parent);
|
266 |
+
|
267 |
+
if(preg_match("/store/i", $scope['scope']))
|
268 |
+
{
|
269 |
+
$websiteId = $this->storeToWebsite($scope['scope_id']);
|
270 |
+
|
271 |
+
// If the website config does not exist, back up to the default value.
|
272 |
+
if(!isset($allConfigData['websites_' . $websiteId]))
|
273 |
+
{
|
274 |
+
// If there is no default value in the db, backup to the confg xml
|
275 |
+
if(!isset($allConfigData['default_0']))
|
276 |
+
{
|
277 |
+
$value = Mage::getStoreConfig($path);
|
278 |
+
}
|
279 |
+
else
|
280 |
+
{
|
281 |
+
$value = $allConfigData['default_0']->getValue();
|
282 |
+
}
|
283 |
+
}
|
284 |
+
else
|
285 |
+
{
|
286 |
+
$value = $allConfigData['websites_' . $websiteId]->getValue();
|
287 |
+
}
|
288 |
+
}
|
289 |
+
else
|
290 |
+
{
|
291 |
+
$value = $allConfigData['default_0']->getValue();
|
292 |
+
}
|
293 |
+
}
|
294 |
+
else
|
295 |
+
{
|
296 |
+
$value = $allConfigData[$parent]->getValue();
|
297 |
+
}
|
298 |
+
return $value;
|
299 |
+
}
|
300 |
+
|
301 |
+
private function getFirstElementIfArray($possibleArray)
|
302 |
+
{
|
303 |
+
return is_array($possibleArray) ? $possibleArray[0] : $possibleArray;
|
304 |
+
}
|
305 |
+
|
306 |
+
/**
|
307 |
+
* Returns an array of all the stored config values for a given path
|
308 |
+
* @param string $path
|
309 |
+
* @return array
|
310 |
+
*/
|
311 |
+
private function getAllConfigs($path)
|
312 |
+
{
|
313 |
+
$allConfigs = array();
|
314 |
+
$configDataCollection = Mage::getModel('core/config_data')->getCollection()
|
315 |
+
->addFieldToFilter('path', array('like' => "%" . $path . '%'));
|
316 |
+
|
317 |
+
foreach ($configDataCollection as $data) {
|
318 |
+
$allConfigs[$data->getScope() . '_' . $data->getScopeId()] = $data;
|
319 |
+
}
|
320 |
+
|
321 |
+
return $allConfigs;
|
322 |
+
}
|
323 |
+
|
324 |
+
/**
|
325 |
+
* Returns the website id for a given store id;
|
326 |
+
* @param int $id
|
327 |
+
*/
|
328 |
+
private function storeToWebsite($id)
|
329 |
+
{
|
330 |
+
if($this->storeToWebsiteMap == null)
|
331 |
+
{
|
332 |
+
$this->storeToWebsiteMap = array();
|
333 |
+
$storeModel = Mage::getSingleton('adminhtml/system_store');
|
334 |
+
foreach ($storeModel->getStoreCollection() as $store) {
|
335 |
+
$this->storeToWebsiteMap[$store->getId()] = $store->getWebsiteId();
|
336 |
+
}
|
337 |
+
}
|
338 |
+
return $this->storeToWebsiteMap[$id];
|
339 |
+
}
|
340 |
+
|
341 |
+
/**
|
342 |
+
* Stores all the configuration data to the database.
|
343 |
+
* @param array $allConfigData
|
344 |
+
*/
|
345 |
+
private function saveAllConfigData($allConfigData)
|
346 |
+
{
|
347 |
+
foreach($allConfigData as $data){
|
348 |
+
$data->save();
|
349 |
+
}
|
350 |
+
}
|
351 |
+
|
352 |
+
private function getHelper()
|
353 |
+
{
|
354 |
+
if($this->helper == null)
|
355 |
+
{
|
356 |
+
$this->helper = Mage::helper('dependency/config');
|
357 |
+
}
|
358 |
+
return $this->helper;
|
359 |
+
}
|
360 |
+
|
361 |
+
private $helper = null;
|
362 |
+
private $handleConfigs = array();
|
363 |
+
private $storeToWebsiteMap = null;
|
364 |
+
}
|
app/code/local/Customweb/Dependency/Model/Mysql4/Category.php
ADDED
@@ -0,0 +1,14 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
::[Header]::
|
4 |
+
* @category Local
|
5 |
+
* @package Customweb_Dependency
|
6 |
+
* @link http://www.customweb.ch
|
7 |
+
*/
|
8 |
+
|
9 |
+
class Customweb_Dependency_Model_Mysql4_Category extends Mage_Core_Model_Mysql4_Abstract{
|
10 |
+
protected function _construct()
|
11 |
+
{
|
12 |
+
$this->_init('dependency/category', 'dependency_id');
|
13 |
+
}
|
14 |
+
}
|
app/code/local/Customweb/Dependency/Model/Mysql4/Category/Collection.php
ADDED
@@ -0,0 +1,14 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
::[Header]::
|
4 |
+
* @category Local
|
5 |
+
* @package Customweb_Dependency
|
6 |
+
* @link http://www.customweb.ch
|
7 |
+
*/
|
8 |
+
|
9 |
+
class Customweb_Dependency_Model_Mysql4_Category_Collection extends Mage_Core_Model_Mysql4_Collection_Abstract {
|
10 |
+
protected function _construct()
|
11 |
+
{
|
12 |
+
$this->_init('dependency/category');
|
13 |
+
}
|
14 |
+
}
|
app/code/local/Customweb/Dependency/Model/Mysql4/Config.php
ADDED
@@ -0,0 +1,15 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/**
|
4 |
+
::[Header]::
|
5 |
+
* @category Local
|
6 |
+
* @package Customweb_Dependency
|
7 |
+
* @link http://www.customweb.ch
|
8 |
+
*/
|
9 |
+
|
10 |
+
class Customweb_Dependency_Model_Mysql4_Config extends Mage_Core_Model_Mysql4_Abstract{
|
11 |
+
protected function _construct()
|
12 |
+
{
|
13 |
+
$this->_init('dependency/config', 'dependency_id');
|
14 |
+
}
|
15 |
+
}
|
app/code/local/Customweb/Dependency/Model/Mysql4/Config/Collection.php
ADDED
@@ -0,0 +1,14 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
::[Header]::
|
4 |
+
* @category Local
|
5 |
+
* @package Customweb_Dependency
|
6 |
+
* @link http://www.customweb.ch
|
7 |
+
*/
|
8 |
+
|
9 |
+
class Customweb_Dependency_Model_Mysql4_Config_Collection extends Mage_Core_Model_Mysql4_Collection_Abstract {
|
10 |
+
protected function _construct()
|
11 |
+
{
|
12 |
+
$this->_init('dependency/config');
|
13 |
+
}
|
14 |
+
}
|
app/code/local/Customweb/Dependency/Model/Mysql4/Product.php
ADDED
@@ -0,0 +1,15 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/**
|
4 |
+
::[Header]::
|
5 |
+
* @category Local
|
6 |
+
* @package Customweb_Dependency
|
7 |
+
* @link http://www.customweb.ch
|
8 |
+
*/
|
9 |
+
|
10 |
+
class Customweb_Dependency_Model_Mysql4_Product extends Mage_Core_Model_Mysql4_Abstract{
|
11 |
+
protected function _construct()
|
12 |
+
{
|
13 |
+
$this->_init('dependency/product', 'dependency_id');
|
14 |
+
}
|
15 |
+
}
|
app/code/local/Customweb/Dependency/Model/Mysql4/Product/Collection.php
ADDED
@@ -0,0 +1,15 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/**
|
4 |
+
::[Header]::
|
5 |
+
* @category Local
|
6 |
+
* @package Customweb_Dependency
|
7 |
+
* @link http://www.customweb.ch
|
8 |
+
*/
|
9 |
+
|
10 |
+
class Customweb_Dependency_Model_Mysql4_Product_Collection extends Mage_Core_Model_Mysql4_Collection_Abstract {
|
11 |
+
protected function _construct()
|
12 |
+
{
|
13 |
+
$this->_init('dependency/product');
|
14 |
+
}
|
15 |
+
}
|
app/code/local/Customweb/Dependency/Model/Product.php
ADDED
@@ -0,0 +1,17 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/**
|
4 |
+
::[Header]::
|
5 |
+
* @category Local
|
6 |
+
* @package Customweb_Dependency
|
7 |
+
* @link http://www.customweb.ch
|
8 |
+
*/
|
9 |
+
|
10 |
+
class Customweb_Dependency_Model_Product extends Mage_Core_Model_Abstract
|
11 |
+
{
|
12 |
+
protected function _construct()
|
13 |
+
{
|
14 |
+
$this->_init('dependency/product');
|
15 |
+
}
|
16 |
+
|
17 |
+
}
|
app/code/local/Customweb/Dependency/Model/Resource/Setup.php
ADDED
@@ -0,0 +1,12 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
::[Header]::
|
4 |
+
* @category Local
|
5 |
+
* @package Customweb_Dependencies
|
6 |
+
* @link http://www.customweb.ch
|
7 |
+
*/
|
8 |
+
|
9 |
+
class Customweb_Dependency_Model_Resource_Setup extends Mage_Core_Model_Resource_Setup
|
10 |
+
{
|
11 |
+
|
12 |
+
}
|
app/code/local/Customweb/Dependency/controllers/TestController.php
ADDED
@@ -0,0 +1,12 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
class Customweb_Dependency_TestController extends Mage_Core_Controller_Front_Action
|
4 |
+
{
|
5 |
+
public function indexAction(){
|
6 |
+
$model = new Mage_Core_Model_Config();
|
7 |
+
//$model->saveConfig('esr/account_information/deposit_for', "Geänadert auf website level", 'websites', 2);
|
8 |
+
//$model->saveConfig('esr/account_information/deposit_for', "geändert auf store level", 'stores', 2);
|
9 |
+
$model->saveConfig('esr/account_information/deposit_for', "default 88");
|
10 |
+
die("fertig");
|
11 |
+
}
|
12 |
+
}
|
app/code/local/Customweb/Dependency/etc/config.xml
ADDED
@@ -0,0 +1,108 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?xml version="1.0" encoding="UTF-8"?>
|
2 |
+
|
3 |
+
<config>
|
4 |
+
<modules>
|
5 |
+
<Customweb_Dependency>
|
6 |
+
<version>1.0.0</version>
|
7 |
+
</Customweb_Dependency>
|
8 |
+
</modules>
|
9 |
+
|
10 |
+
<global>
|
11 |
+
<models>
|
12 |
+
<dependency>
|
13 |
+
<class>Customweb_Dependency_Model</class>
|
14 |
+
<resourceModel>dependency_mysql4</resourceModel>
|
15 |
+
</dependency>
|
16 |
+
<dependency_mysql4>
|
17 |
+
<class>Customweb_Dependency_Model_Mysql4</class>
|
18 |
+
<entities>
|
19 |
+
<product>
|
20 |
+
<table>customweb_product_dependency</table>
|
21 |
+
</product>
|
22 |
+
<category>
|
23 |
+
<table>customweb_category_dependency</table>
|
24 |
+
</category>
|
25 |
+
<config>
|
26 |
+
<table>customweb_config_dependency</table>
|
27 |
+
</config>
|
28 |
+
</entities>
|
29 |
+
</dependency_mysql4>
|
30 |
+
</models>
|
31 |
+
<helpers>
|
32 |
+
<dependency>
|
33 |
+
<class>Customweb_Dependency_Helper</class>
|
34 |
+
</dependency>
|
35 |
+
</helpers>
|
36 |
+
<resources>
|
37 |
+
<dependency_write>
|
38 |
+
<connection>
|
39 |
+
<use>core_write</use>
|
40 |
+
</connection>
|
41 |
+
</dependency_write>
|
42 |
+
<dependency_read>
|
43 |
+
<connection>
|
44 |
+
<use>core_read</use>
|
45 |
+
</connection>
|
46 |
+
</dependency_read>
|
47 |
+
<dependency_setup>
|
48 |
+
<setup>
|
49 |
+
<module>Customweb_Dependency</module>
|
50 |
+
<class>Customweb_Dependency_Model_Resource_Setup</class>
|
51 |
+
</setup>
|
52 |
+
</dependency_setup>
|
53 |
+
</resources>
|
54 |
+
<events>
|
55 |
+
<core_model_config_save_after>
|
56 |
+
<observers>
|
57 |
+
<dependency_core_config_save_after>
|
58 |
+
<type>singleton</type>
|
59 |
+
<class>Customweb_Dependency_Model_ConfigObserver</class>
|
60 |
+
<method>coreConfigSaveAfter</method>
|
61 |
+
</dependency_core_config_save_after>
|
62 |
+
</observers>
|
63 |
+
</core_model_config_save_after>
|
64 |
+
<model_config_data_save_before>
|
65 |
+
<observers>
|
66 |
+
<dependency_config_save_before>
|
67 |
+
<type>singleton</type>
|
68 |
+
<class>Customweb_Dependency_Model_ConfigObserver</class>
|
69 |
+
<method>configSaveBefore</method>
|
70 |
+
</dependency_config_save_before>
|
71 |
+
</observers>
|
72 |
+
</model_config_data_save_before>
|
73 |
+
<core_config_data_save_after>
|
74 |
+
<observers>
|
75 |
+
<dependency_config_save_after>
|
76 |
+
<type>singleton</type>
|
77 |
+
<class>Customweb_Dependency_Model_ConfigObserver</class>
|
78 |
+
<method>configSaveAfter</method>
|
79 |
+
</dependency_config_save_after>
|
80 |
+
</observers>
|
81 |
+
</core_config_data_save_after>
|
82 |
+
<core_config_data_delete_after>
|
83 |
+
<observers>
|
84 |
+
<dependency_config_delete_after>
|
85 |
+
<type>singleton</type>
|
86 |
+
<class>Customweb_Dependency_Model_ConfigObserver</class>
|
87 |
+
<method>configDeleteAfter</method>
|
88 |
+
</dependency_config_delete_after>
|
89 |
+
</observers>
|
90 |
+
</core_config_data_delete_after>
|
91 |
+
|
92 |
+
|
93 |
+
|
94 |
+
</events>
|
95 |
+
</global>
|
96 |
+
|
97 |
+
<adminhtml>
|
98 |
+
<layout>
|
99 |
+
<updates>
|
100 |
+
<dependency>
|
101 |
+
<file>dependency.xml</file>
|
102 |
+
</dependency>
|
103 |
+
</updates>
|
104 |
+
</layout>
|
105 |
+
</adminhtml>
|
106 |
+
|
107 |
+
|
108 |
+
</config>
|
app/code/local/Customweb/Dependency/sql/dependency_setup/mysql4-install-1.0.0.php
ADDED
@@ -0,0 +1,45 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/**
|
4 |
+
::[Header]::
|
5 |
+
* @category Local
|
6 |
+
* @package Customweb_Dependency
|
7 |
+
* @link http://www.customweb.ch
|
8 |
+
*/
|
9 |
+
|
10 |
+
$installer = $this;
|
11 |
+
$installer->startSetup();
|
12 |
+
$installer->run("CREATE TABLE `customweb_product_dependency` (
|
13 |
+
`dependency_id` INT NOT NULL AUTO_INCREMENT,
|
14 |
+
`attribute_id` INT NOT NULL ,
|
15 |
+
`store_id` INT NOT NULL ,
|
16 |
+
`entity_id` INT NOT NULL ,
|
17 |
+
`depends_on_store_id` INT NOT NULL ,
|
18 |
+
PRIMARY KEY ( `dependency_id` )
|
19 |
+
) ENGINE = InnoDB DEFAULT CHARSET=utf8;
|
20 |
+
");
|
21 |
+
|
22 |
+
$installer->run("CREATE TABLE `customweb_category_dependency` (
|
23 |
+
`dependency_id` INT NOT NULL AUTO_INCREMENT,
|
24 |
+
`attribute_id` INT NOT NULL ,
|
25 |
+
`store_id` INT NOT NULL ,
|
26 |
+
`entity_id` INT NOT NULL ,
|
27 |
+
`depends_on_store_id` INT NOT NULL ,
|
28 |
+
PRIMARY KEY ( `dependency_id` )
|
29 |
+
) ENGINE = InnoDB DEFAULT CHARSET=utf8;
|
30 |
+
");
|
31 |
+
|
32 |
+
$installer->run("CREATE TABLE `customweb_config_dependency` (
|
33 |
+
`dependency_id` INT NOT NULL AUTO_INCREMENT,
|
34 |
+
`path` VARCHAR(255) NOT NULL ,
|
35 |
+
`scope` VARCHAR(8) NOT NULL ,
|
36 |
+
`scope_id` INT NOT NULL ,
|
37 |
+
`depends_on_scope` VARCHAR(8) NOT NULL ,
|
38 |
+
`depends_on_scope_id` INT NOT NULL ,
|
39 |
+
PRIMARY KEY ( `dependency_id` )
|
40 |
+
) ENGINE = InnoDB DEFAULT CHARSET=utf8;
|
41 |
+
");
|
42 |
+
|
43 |
+
$installer->endSetup();
|
44 |
+
|
45 |
+
|
app/code/local/Mage/Core/Model/Config.php
ADDED
@@ -0,0 +1,1625 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/**
|
4 |
+
* This is an exact copy of the same class in code/core/Mage/Core/Model/Config.php
|
5 |
+
*
|
6 |
+
* The only difference is that we dispatch an event 'core_model_config_save_after' in function
|
7 |
+
* saveConfig().
|
8 |
+
*
|
9 |
+
*/
|
10 |
+
|
11 |
+
|
12 |
+
/**
|
13 |
+
* Core configuration class
|
14 |
+
*
|
15 |
+
* @category Mage
|
16 |
+
* @package Mage_Core
|
17 |
+
* @author Magento Core Team <core@magentocommerce.com>
|
18 |
+
*/
|
19 |
+
class Mage_Core_Model_Config extends Mage_Core_Model_Config_Base
|
20 |
+
{
|
21 |
+
const CACHE_TAG = 'CONFIG';
|
22 |
+
|
23 |
+
/**
|
24 |
+
* Flag which allow use cache logic
|
25 |
+
*
|
26 |
+
* @var bool
|
27 |
+
*/
|
28 |
+
protected $_useCache = false;
|
29 |
+
|
30 |
+
/**
|
31 |
+
* Instructions for spitting config cache
|
32 |
+
* array(
|
33 |
+
* $sectionName => $recursionLevel
|
34 |
+
* )
|
35 |
+
* Recursion level provide availability cache subnodes separatly
|
36 |
+
*
|
37 |
+
* @var array
|
38 |
+
*/
|
39 |
+
protected $_cacheSections = array(
|
40 |
+
'admin' => 0,
|
41 |
+
'adminhtml' => 0,
|
42 |
+
'crontab' => 0,
|
43 |
+
'install' => 0,
|
44 |
+
'stores' => 1,
|
45 |
+
'websites' => 0
|
46 |
+
);
|
47 |
+
|
48 |
+
/**
|
49 |
+
* Loaded Configuration by cached sections
|
50 |
+
*
|
51 |
+
* @var array
|
52 |
+
*/
|
53 |
+
protected $_cacheLoadedSections = array();
|
54 |
+
|
55 |
+
/**
|
56 |
+
* Configuration options
|
57 |
+
*
|
58 |
+
* @var Mage_Core_Model_Config_Options
|
59 |
+
*/
|
60 |
+
protected $_options;
|
61 |
+
|
62 |
+
/**
|
63 |
+
* Storage for generated class names
|
64 |
+
*
|
65 |
+
* @var array
|
66 |
+
*/
|
67 |
+
protected $_classNameCache = array();
|
68 |
+
|
69 |
+
/**
|
70 |
+
* Storage for generated block class names
|
71 |
+
*
|
72 |
+
* @var unknown_type
|
73 |
+
*/
|
74 |
+
protected $_blockClassNameCache = array();
|
75 |
+
|
76 |
+
/**
|
77 |
+
* Storage of validated secure urls
|
78 |
+
*
|
79 |
+
* @var array
|
80 |
+
*/
|
81 |
+
protected $_secureUrlCache = array();
|
82 |
+
|
83 |
+
/**
|
84 |
+
* System environment server variables
|
85 |
+
*
|
86 |
+
* @var array
|
87 |
+
*/
|
88 |
+
protected $_distroServerVars;
|
89 |
+
|
90 |
+
/**
|
91 |
+
* Array which is using for replace placeholders of server variables
|
92 |
+
*
|
93 |
+
* @var array
|
94 |
+
*/
|
95 |
+
protected $_substServerVars;
|
96 |
+
|
97 |
+
/**
|
98 |
+
* Resource model
|
99 |
+
* Used for operations with DB
|
100 |
+
*
|
101 |
+
* @var Mage_Core_Model_Mysql4_Config
|
102 |
+
*/
|
103 |
+
protected $_resourceModel;
|
104 |
+
|
105 |
+
/**
|
106 |
+
* Configuration for events by area
|
107 |
+
*
|
108 |
+
* @var array
|
109 |
+
*/
|
110 |
+
protected $_eventAreas;
|
111 |
+
|
112 |
+
/**
|
113 |
+
* Flag cache for existing or already created directories
|
114 |
+
*
|
115 |
+
* @var array
|
116 |
+
*/
|
117 |
+
protected $_dirExists = array();
|
118 |
+
|
119 |
+
/**
|
120 |
+
* Flach which allow using cache for config initialization
|
121 |
+
*
|
122 |
+
* @var bool
|
123 |
+
*/
|
124 |
+
protected $_allowCacheForInit = true;
|
125 |
+
|
126 |
+
/**
|
127 |
+
* Property used during cache save process
|
128 |
+
*
|
129 |
+
* @var array
|
130 |
+
*/
|
131 |
+
protected $_cachePartsForSave = array();
|
132 |
+
|
133 |
+
/**
|
134 |
+
* Empty configuration object for loading and megring configuration parts
|
135 |
+
*
|
136 |
+
* @var Mage_Core_Model_Config_Base
|
137 |
+
*/
|
138 |
+
protected $_prototype;
|
139 |
+
|
140 |
+
/**
|
141 |
+
* Flag which identify what local configuration is loaded
|
142 |
+
*
|
143 |
+
* @var bool
|
144 |
+
*/
|
145 |
+
protected $_isLocalConfigLoaded = false;
|
146 |
+
|
147 |
+
/**
|
148 |
+
* Depricated properties
|
149 |
+
*
|
150 |
+
* @deprecated
|
151 |
+
*/
|
152 |
+
protected $_baseDirCache = array();
|
153 |
+
protected $_customEtcDir = null;
|
154 |
+
|
155 |
+
/**
|
156 |
+
* Flag which allow to use modules from local code pool
|
157 |
+
*
|
158 |
+
* @var bool
|
159 |
+
*/
|
160 |
+
protected $_canUseLocalModules = null;
|
161 |
+
|
162 |
+
/**
|
163 |
+
* Active modules array per namespace
|
164 |
+
* @var array
|
165 |
+
*/
|
166 |
+
private $_moduleNamespaces = null;
|
167 |
+
|
168 |
+
/**
|
169 |
+
* Modules allowed to load
|
170 |
+
* If empty - all modules are allowed
|
171 |
+
*
|
172 |
+
* @var array
|
173 |
+
*/
|
174 |
+
protected $_allowedModules = array();
|
175 |
+
|
176 |
+
/**
|
177 |
+
* Class construct
|
178 |
+
*
|
179 |
+
* @param mixed $sourceData
|
180 |
+
*/
|
181 |
+
public function __construct($sourceData=null)
|
182 |
+
{
|
183 |
+
$this->setCacheId('config_global');
|
184 |
+
$this->_options = new Mage_Core_Model_Config_Options($sourceData);
|
185 |
+
$this->_prototype = new Mage_Core_Model_Config_Base();
|
186 |
+
$this->_cacheChecksum = null;
|
187 |
+
parent::__construct($sourceData);
|
188 |
+
}
|
189 |
+
|
190 |
+
/**
|
191 |
+
* Get config resource model
|
192 |
+
*
|
193 |
+
* @return Mage_Core_Store_Mysql4_Config
|
194 |
+
*/
|
195 |
+
public function getResourceModel()
|
196 |
+
{
|
197 |
+
if (is_null($this->_resourceModel)) {
|
198 |
+
$this->_resourceModel = Mage::getResourceModel('core/config');
|
199 |
+
}
|
200 |
+
return $this->_resourceModel;
|
201 |
+
}
|
202 |
+
|
203 |
+
/**
|
204 |
+
* Get configuration options object
|
205 |
+
*
|
206 |
+
* @return Mage_Core_Model_Config_Options
|
207 |
+
*/
|
208 |
+
public function getOptions()
|
209 |
+
{
|
210 |
+
return $this->_options;
|
211 |
+
}
|
212 |
+
|
213 |
+
/**
|
214 |
+
* Set configuration options
|
215 |
+
*
|
216 |
+
* @param array $options
|
217 |
+
* @return Mage_Core_Model_Config
|
218 |
+
*/
|
219 |
+
public function setOptions($options)
|
220 |
+
{
|
221 |
+
if (is_array($options)) {
|
222 |
+
$this->getOptions()->addData($options);
|
223 |
+
}
|
224 |
+
return $this;
|
225 |
+
}
|
226 |
+
|
227 |
+
/**
|
228 |
+
* Initialization of core configuration
|
229 |
+
*
|
230 |
+
* @return Mage_Core_Model_Config
|
231 |
+
*/
|
232 |
+
public function init($options=array())
|
233 |
+
{
|
234 |
+
$this->setCacheChecksum(null);
|
235 |
+
$this->_cacheLoadedSections = array();
|
236 |
+
$this->setOptions($options);
|
237 |
+
$this->loadBase();
|
238 |
+
|
239 |
+
$cacheLoad = $this->loadModulesCache();
|
240 |
+
if ($cacheLoad) {
|
241 |
+
return $this;
|
242 |
+
}
|
243 |
+
$this->loadModules();
|
244 |
+
$this->loadDb();
|
245 |
+
$this->saveCache();
|
246 |
+
return $this;
|
247 |
+
}
|
248 |
+
|
249 |
+
/**
|
250 |
+
* Load base system configuration (config.xml and local.xml files)
|
251 |
+
*
|
252 |
+
* @return Mage_Core_Model_Config
|
253 |
+
*/
|
254 |
+
public function loadBase()
|
255 |
+
{
|
256 |
+
$etcDir = $this->getOptions()->getEtcDir();
|
257 |
+
$files = glob($etcDir.DS.'*.xml');
|
258 |
+
$this->loadFile(current($files));
|
259 |
+
while ($file = next($files)) {
|
260 |
+
$merge = clone $this->_prototype;
|
261 |
+
$merge->loadFile($file);
|
262 |
+
$this->extend($merge);
|
263 |
+
}
|
264 |
+
if (in_array($etcDir.DS.'local.xml', $files)) {
|
265 |
+
$this->_isLocalConfigLoaded = true;
|
266 |
+
}
|
267 |
+
return $this;
|
268 |
+
}
|
269 |
+
|
270 |
+
/**
|
271 |
+
* Load cached modules configuration
|
272 |
+
*
|
273 |
+
* @return bool
|
274 |
+
*/
|
275 |
+
public function loadModulesCache()
|
276 |
+
{
|
277 |
+
if (Mage::isInstalled(array('etc_dir' => $this->getOptions()->getEtcDir()))) {
|
278 |
+
if ($this->_canUseCacheForInit()) {
|
279 |
+
Varien_Profiler::start('mage::app::init::config::load_cache');
|
280 |
+
$loaded = $this->loadCache();
|
281 |
+
Varien_Profiler::stop('mage::app::init::config::load_cache');
|
282 |
+
if ($loaded) {
|
283 |
+
$this->_useCache = true;
|
284 |
+
return true;
|
285 |
+
}
|
286 |
+
}
|
287 |
+
}
|
288 |
+
return false;
|
289 |
+
}
|
290 |
+
|
291 |
+
/**
|
292 |
+
* Load modules configuration
|
293 |
+
*
|
294 |
+
* @return Mage_Core_Model_Config
|
295 |
+
*/
|
296 |
+
public function loadModules()
|
297 |
+
{
|
298 |
+
Varien_Profiler::start('config/load-modules');
|
299 |
+
$this->_loadDeclaredModules();
|
300 |
+
|
301 |
+
$resourceConfig = sprintf('config.%s.xml', $this->_getResourceConnectionModel('core'));
|
302 |
+
$this->loadModulesConfiguration(array('config.xml',$resourceConfig), $this);
|
303 |
+
|
304 |
+
/**
|
305 |
+
* Prevent local.xml directives overwriting
|
306 |
+
*/
|
307 |
+
$mergeConfig = clone $this->_prototype;
|
308 |
+
$this->_isLocalConfigLoaded = $mergeConfig->loadFile($this->getOptions()->getEtcDir().DS.'local.xml');
|
309 |
+
if ($this->_isLocalConfigLoaded) {
|
310 |
+
$this->extend($mergeConfig);
|
311 |
+
}
|
312 |
+
|
313 |
+
$this->applyExtends();
|
314 |
+
Varien_Profiler::stop('config/load-modules');
|
315 |
+
return $this;
|
316 |
+
}
|
317 |
+
|
318 |
+
/**
|
319 |
+
* Check if local configuration (DB connection, etc) is loaded
|
320 |
+
*
|
321 |
+
* @return bool
|
322 |
+
*/
|
323 |
+
public function isLocalConfigLoaded()
|
324 |
+
{
|
325 |
+
return $this->_isLocalConfigLoaded;
|
326 |
+
}
|
327 |
+
|
328 |
+
/**
|
329 |
+
* Load config data from DB
|
330 |
+
*
|
331 |
+
* @return Mage_Core_Model_Config
|
332 |
+
*/
|
333 |
+
public function loadDb()
|
334 |
+
{
|
335 |
+
if ($this->_isLocalConfigLoaded && Mage::isInstalled()) {
|
336 |
+
Varien_Profiler::start('config/load-db');
|
337 |
+
$dbConf = $this->getResourceModel();
|
338 |
+
$dbConf->loadToXml($this);
|
339 |
+
Varien_Profiler::stop('config/load-db');
|
340 |
+
}
|
341 |
+
return $this;
|
342 |
+
}
|
343 |
+
|
344 |
+
/**
|
345 |
+
* Reinitialize configuration
|
346 |
+
*
|
347 |
+
* @param array $options
|
348 |
+
* @return Mage_Core_Model_Config
|
349 |
+
*/
|
350 |
+
public function reinit($options = array())
|
351 |
+
{
|
352 |
+
$this->_allowCacheForInit = false;
|
353 |
+
$this->_useCache = false;
|
354 |
+
return $this->init($options);
|
355 |
+
}
|
356 |
+
|
357 |
+
/**
|
358 |
+
* Check local modules enable/disable flag
|
359 |
+
* If local modules are disbled remove local modules path from include dirs
|
360 |
+
*
|
361 |
+
* return true if local modules enabled and false if disabled
|
362 |
+
*
|
363 |
+
* @return bool
|
364 |
+
*/
|
365 |
+
protected function _canUseLocalModules()
|
366 |
+
{
|
367 |
+
if ($this->_canUseLocalModules !== null) {
|
368 |
+
return $this->_canUseLocalModules;
|
369 |
+
}
|
370 |
+
|
371 |
+
$disableLocalModules = (string)$this->getNode('global/disable_local_modules');
|
372 |
+
if (!empty($disableLocalModules)) {
|
373 |
+
$disableLocalModules = (('true' === $disableLocalModules) || ('1' === $disableLocalModules));
|
374 |
+
} else {
|
375 |
+
$disableLocalModules = false;
|
376 |
+
}
|
377 |
+
|
378 |
+
if ($disableLocalModules && !defined('COMPILER_INCLUDE_PATH')) {
|
379 |
+
set_include_path(
|
380 |
+
// excluded '/app/code/local'
|
381 |
+
BP . DS . 'app' . DS . 'code' . DS . 'community' . PS .
|
382 |
+
BP . DS . 'app' . DS . 'code' . DS . 'core' . PS .
|
383 |
+
BP . DS . 'lib' . PS .
|
384 |
+
Mage::registry('original_include_path')
|
385 |
+
);
|
386 |
+
}
|
387 |
+
$this->_canUseLocalModules = !$disableLocalModules;
|
388 |
+
return $this->_canUseLocalModules;
|
389 |
+
}
|
390 |
+
|
391 |
+
/**
|
392 |
+
* Check if cache can be used for config initialization
|
393 |
+
*
|
394 |
+
* @return bool
|
395 |
+
*/
|
396 |
+
protected function _canUseCacheForInit()
|
397 |
+
{
|
398 |
+
return Mage::app()->useCache('config') && $this->_allowCacheForInit
|
399 |
+
&& !$this->_loadCache($this->_getCacheLockId());
|
400 |
+
}
|
401 |
+
|
402 |
+
/**
|
403 |
+
* Retrieve cache object
|
404 |
+
*
|
405 |
+
* @return Zend_Cache_Frontend_File
|
406 |
+
*/
|
407 |
+
public function getCache()
|
408 |
+
{
|
409 |
+
return Mage::app()->getCache();
|
410 |
+
}
|
411 |
+
|
412 |
+
/**
|
413 |
+
* Get lock flag cache identifier
|
414 |
+
*
|
415 |
+
* @return string
|
416 |
+
*/
|
417 |
+
protected function _getCacheLockId()
|
418 |
+
{
|
419 |
+
return $this->getCacheId().'.lock';
|
420 |
+
}
|
421 |
+
|
422 |
+
/**
|
423 |
+
* Save configuration cache
|
424 |
+
*
|
425 |
+
* @param array $tags cache tags
|
426 |
+
* @return Mage_Core_Model_Config
|
427 |
+
*/
|
428 |
+
public function saveCache($tags=array())
|
429 |
+
{
|
430 |
+
if (!Mage::app()->useCache('config')) {
|
431 |
+
return $this;
|
432 |
+
}
|
433 |
+
if (!in_array(self::CACHE_TAG, $tags)) {
|
434 |
+
$tags[] = self::CACHE_TAG;
|
435 |
+
}
|
436 |
+
$cacheLockId = $this->_getCacheLockId();
|
437 |
+
if ($this->_loadCache($cacheLockId)) {
|
438 |
+
return $this;
|
439 |
+
}
|
440 |
+
|
441 |
+
if (!empty($this->_cacheSections)) {
|
442 |
+
$xml = clone $this->_xml;
|
443 |
+
foreach ($this->_cacheSections as $sectionName => $level) {
|
444 |
+
$this->_saveSectionCache($this->getCacheId(), $sectionName, $xml, $level, $tags);
|
445 |
+
unset($xml->$sectionName);
|
446 |
+
}
|
447 |
+
$this->_cachePartsForSave[$this->getCacheId()] = $xml->asNiceXml('', false);
|
448 |
+
} else {
|
449 |
+
return parent::saveCache($tags);
|
450 |
+
}
|
451 |
+
|
452 |
+
$this->_saveCache(time(), $cacheLockId, array(), 60);
|
453 |
+
$this->removeCache();
|
454 |
+
foreach ($this->_cachePartsForSave as $cacheId => $cacheData) {
|
455 |
+
$this->_saveCache($cacheData, $cacheId, $tags, $this->getCacheLifetime());
|
456 |
+
}
|
457 |
+
unset($this->_cachePartsForSave);
|
458 |
+
$this->_removeCache($cacheLockId);
|
459 |
+
return $this;
|
460 |
+
}
|
461 |
+
|
462 |
+
/**
|
463 |
+
* Save cache of specified
|
464 |
+
*
|
465 |
+
* @param string $idPrefix cache id prefix
|
466 |
+
* @param string $sectionName
|
467 |
+
* @param Varien_Simplexml_Element $source
|
468 |
+
* @param int $recursionLevel
|
469 |
+
* @return Mage_Core_Model_Config
|
470 |
+
*/
|
471 |
+
protected function _saveSectionCache($idPrefix, $sectionName, $source, $recursionLevel=0, $tags=array())
|
472 |
+
{
|
473 |
+
if ($source && $source->$sectionName) {
|
474 |
+
$cacheId = $idPrefix . '_' . $sectionName;
|
475 |
+
if ($recursionLevel > 0) {
|
476 |
+
foreach ($source->$sectionName->children() as $subSectionName => $node) {
|
477 |
+
$this->_saveSectionCache(
|
478 |
+
$cacheId, $subSectionName, $source->$sectionName, $recursionLevel-1, $tags
|
479 |
+
);
|
480 |
+
}
|
481 |
+
}
|
482 |
+
$this->_cachePartsForSave[$cacheId] = $source->$sectionName->asNiceXml('', false);
|
483 |
+
}
|
484 |
+
return $this;
|
485 |
+
}
|
486 |
+
|
487 |
+
/**
|
488 |
+
* Load config section cached data
|
489 |
+
*
|
490 |
+
* @param string $sectionName
|
491 |
+
* @return Varien_Simplexml_Element
|
492 |
+
*/
|
493 |
+
protected function _loadSectionCache($sectionName)
|
494 |
+
{
|
495 |
+
$cacheId = $this->getCacheId() . '_' . $sectionName;
|
496 |
+
$xmlString = $this->_loadCache($cacheId);
|
497 |
+
|
498 |
+
/**
|
499 |
+
* If we can't load section cache (problems with cache storage)
|
500 |
+
*/
|
501 |
+
if (!$xmlString) {
|
502 |
+
$this->_useCache = false;
|
503 |
+
$this->reinit($this->_options);
|
504 |
+
return false;
|
505 |
+
} else {
|
506 |
+
$xml = simplexml_load_string($xmlString, $this->_elementClass);
|
507 |
+
return $xml;
|
508 |
+
}
|
509 |
+
}
|
510 |
+
|
511 |
+
/**
|
512 |
+
* Load cached data by identifier
|
513 |
+
*
|
514 |
+
* @param string $id
|
515 |
+
* @return string
|
516 |
+
*/
|
517 |
+
protected function _loadCache($id)
|
518 |
+
{
|
519 |
+
return Mage::app()->loadCache($id);
|
520 |
+
}
|
521 |
+
|
522 |
+
/**
|
523 |
+
* Save cache data
|
524 |
+
*
|
525 |
+
* @param string $data
|
526 |
+
* @param string $id
|
527 |
+
* @param array $tags
|
528 |
+
* @param false|int $lifetime
|
529 |
+
* @return Mage_Core_Model_Config
|
530 |
+
*/
|
531 |
+
protected function _saveCache($data, $id, $tags=array(), $lifetime=false)
|
532 |
+
{
|
533 |
+
return Mage::app()->saveCache($data, $id, $tags, $lifetime);
|
534 |
+
}
|
535 |
+
|
536 |
+
/**
|
537 |
+
* Clear cache data by id
|
538 |
+
*
|
539 |
+
* @param string $id
|
540 |
+
* @return Mage_Core_Model_Config
|
541 |
+
*/
|
542 |
+
protected function _removeCache($id)
|
543 |
+
{
|
544 |
+
return Mage::app()->removeCache($id);
|
545 |
+
}
|
546 |
+
|
547 |
+
/**
|
548 |
+
* Remove configuration cache
|
549 |
+
*
|
550 |
+
* @return Mage_Core_Model_Config
|
551 |
+
*/
|
552 |
+
public function removeCache()
|
553 |
+
{
|
554 |
+
Mage::app()->cleanCache(array(self::CACHE_TAG));
|
555 |
+
return parent::removeCache();
|
556 |
+
}
|
557 |
+
|
558 |
+
/**
|
559 |
+
* Configuration cache clean process
|
560 |
+
*
|
561 |
+
* @return Mage_Core_Model_Config
|
562 |
+
*/
|
563 |
+
public function cleanCache()
|
564 |
+
{
|
565 |
+
return $this->reinit();
|
566 |
+
}
|
567 |
+
|
568 |
+
/**
|
569 |
+
* Getter for section configuration object
|
570 |
+
*
|
571 |
+
* @param array $path
|
572 |
+
* @return Mage_Core_Model_Config_Element
|
573 |
+
*/
|
574 |
+
protected function _getSectionConfig($path)
|
575 |
+
{
|
576 |
+
$section = $path[0];
|
577 |
+
if (!isset($this->_cacheSections[$section])) {
|
578 |
+
return false;
|
579 |
+
}
|
580 |
+
$sectionPath = array_slice($path, 0, $this->_cacheSections[$section]+1);
|
581 |
+
$sectionKey = implode('_', $sectionPath);
|
582 |
+
|
583 |
+
if (!isset($this->_cacheLoadedSections[$sectionKey])) {
|
584 |
+
Varien_Profiler::start('init_config_section:' . $sectionKey);
|
585 |
+
$this->_cacheLoadedSections[$sectionKey] = $this->_loadSectionCache($sectionKey);
|
586 |
+
Varien_Profiler::stop('init_config_section:' . $sectionKey);
|
587 |
+
}
|
588 |
+
|
589 |
+
if ($this->_cacheLoadedSections[$sectionKey] === false) {
|
590 |
+
return false;
|
591 |
+
}
|
592 |
+
return $this->_cacheLoadedSections[$sectionKey];
|
593 |
+
}
|
594 |
+
|
595 |
+
/**
|
596 |
+
* Get node value from cached section data
|
597 |
+
*
|
598 |
+
* @param array $path
|
599 |
+
* @return Mage_Core_Model_Config
|
600 |
+
*/
|
601 |
+
public function getSectionNode($path)
|
602 |
+
{
|
603 |
+
$section = $path[0];
|
604 |
+
$config = $this->_getSectionConfig($path);
|
605 |
+
$path = array_slice($path, $this->_cacheSections[$section] + 1);
|
606 |
+
if ($config) {
|
607 |
+
return $config->descend($path);
|
608 |
+
}
|
609 |
+
return false;
|
610 |
+
}
|
611 |
+
|
612 |
+
/**
|
613 |
+
* Returns node found by the $path and scope info
|
614 |
+
*
|
615 |
+
* @param string $path
|
616 |
+
* @param string $scope
|
617 |
+
* @param string|int $scopeCode
|
618 |
+
* @return Mage_Core_Model_Config_Element
|
619 |
+
*/
|
620 |
+
public function getNode($path=null, $scope='', $scopeCode=null)
|
621 |
+
{
|
622 |
+
if ($scope !== '') {
|
623 |
+
if (('store' === $scope) || ('website' === $scope)) {
|
624 |
+
$scope .= 's';
|
625 |
+
}
|
626 |
+
if (('default' !== $scope) && is_int($scopeCode)) {
|
627 |
+
if ('stores' == $scope) {
|
628 |
+
$scopeCode = Mage::app()->getStore($scopeCode)->getCode();
|
629 |
+
} elseif ('websites' == $scope) {
|
630 |
+
$scopeCode = Mage::app()->getWebsite($scopeCode)->getCode();
|
631 |
+
} else {
|
632 |
+
Mage::throwException(Mage::helper('core')->__('Unknown scope "%s".', $scope));
|
633 |
+
}
|
634 |
+
}
|
635 |
+
$path = $scope . ($scopeCode ? '/' . $scopeCode : '' ) . (empty($path) ? '' : '/' . $path);
|
636 |
+
}
|
637 |
+
|
638 |
+
/**
|
639 |
+
* Check path cache loading
|
640 |
+
*/
|
641 |
+
if ($this->_useCache && ($path !== null)) {
|
642 |
+
$path = explode('/', $path);
|
643 |
+
$section= $path[0];
|
644 |
+
if (isset($this->_cacheSections[$section])) {
|
645 |
+
$res = $this->getSectionNode($path);
|
646 |
+
if ($res !== false) {
|
647 |
+
return $res;
|
648 |
+
}
|
649 |
+
}
|
650 |
+
}
|
651 |
+
return parent::getNode($path);
|
652 |
+
}
|
653 |
+
|
654 |
+
/**
|
655 |
+
* Create node by $path and set its value.
|
656 |
+
*
|
657 |
+
* @param string $path separated by slashes
|
658 |
+
* @param string $value
|
659 |
+
* @param bool $overwrite
|
660 |
+
* @return Varien_Simplexml_Config
|
661 |
+
*/
|
662 |
+
public function setNode($path, $value, $overwrite = true)
|
663 |
+
{
|
664 |
+
if ($this->_useCache && ($path !== null)) {
|
665 |
+
$sectionPath = explode('/', $path);
|
666 |
+
$config = $this->_getSectionConfig($sectionPath);
|
667 |
+
if ($config) {
|
668 |
+
$sectionPath = array_slice($sectionPath, $this->_cacheSections[$sectionPath[0]]+1);
|
669 |
+
$sectionPath = implode('/', $sectionPath);
|
670 |
+
$config->setNode($sectionPath, $value, $overwrite);
|
671 |
+
}
|
672 |
+
}
|
673 |
+
return parent::setNode($path, $value, $overwrite);
|
674 |
+
}
|
675 |
+
|
676 |
+
|
677 |
+
/**
|
678 |
+
* Retrive Declared Module file list
|
679 |
+
*
|
680 |
+
* @return array
|
681 |
+
*/
|
682 |
+
protected function _getDeclaredModuleFiles()
|
683 |
+
{
|
684 |
+
$etcDir = $this->getOptions()->getEtcDir();
|
685 |
+
$moduleFiles = glob($etcDir . DS . 'modules' . DS . '*.xml');
|
686 |
+
|
687 |
+
if (!$moduleFiles) {
|
688 |
+
return false;
|
689 |
+
}
|
690 |
+
|
691 |
+
$collectModuleFiles = array(
|
692 |
+
'base' => array(),
|
693 |
+
'mage' => array(),
|
694 |
+
'custom' => array()
|
695 |
+
);
|
696 |
+
|
697 |
+
foreach ($moduleFiles as $v) {
|
698 |
+
$name = explode(DIRECTORY_SEPARATOR, $v);
|
699 |
+
$name = substr($name[count($name) - 1], 0, -4);
|
700 |
+
|
701 |
+
if ($name == 'Mage_All') {
|
702 |
+
$collectModuleFiles['base'][] = $v;
|
703 |
+
} else if (substr($name, 0, 5) == 'Mage_') {
|
704 |
+
$collectModuleFiles['mage'][] = $v;
|
705 |
+
} else {
|
706 |
+
$collectModuleFiles['custom'][] = $v;
|
707 |
+
}
|
708 |
+
}
|
709 |
+
|
710 |
+
return array_merge(
|
711 |
+
$collectModuleFiles['base'],
|
712 |
+
$collectModuleFiles['mage'],
|
713 |
+
$collectModuleFiles['custom']
|
714 |
+
);
|
715 |
+
}
|
716 |
+
|
717 |
+
/**
|
718 |
+
* Add module(s) to allowed list
|
719 |
+
*
|
720 |
+
* @param strung|array $module
|
721 |
+
* @return Mage_Core_Model_Config
|
722 |
+
*/
|
723 |
+
public function addAllowedModules($module)
|
724 |
+
{
|
725 |
+
if (is_array($module)) {
|
726 |
+
foreach ($module as $moduleName) {
|
727 |
+
$this->addAllowedModules($moduleName);
|
728 |
+
}
|
729 |
+
} elseif (!in_array($module, $this->_allowedModules)) {
|
730 |
+
$this->_allowedModules[] = $module;
|
731 |
+
}
|
732 |
+
|
733 |
+
return $this;
|
734 |
+
}
|
735 |
+
|
736 |
+
/**
|
737 |
+
* Define if module is allowed
|
738 |
+
*
|
739 |
+
* @param string $moduleName
|
740 |
+
* @return bool
|
741 |
+
*/
|
742 |
+
protected function _isAllowedModule($moduleName)
|
743 |
+
{
|
744 |
+
if (empty($this->_allowedModules)) {
|
745 |
+
return true;
|
746 |
+
} else {
|
747 |
+
return in_array($moduleName, $this->_allowedModules);
|
748 |
+
}
|
749 |
+
}
|
750 |
+
|
751 |
+
/**
|
752 |
+
* Load declared modules configuration
|
753 |
+
*
|
754 |
+
* @param null $mergeConfig depricated
|
755 |
+
* @return Mage_Core_Model_Config
|
756 |
+
*/
|
757 |
+
protected function _loadDeclaredModules($mergeConfig = null)
|
758 |
+
{
|
759 |
+
$moduleFiles = $this->_getDeclaredModuleFiles();
|
760 |
+
if (!$moduleFiles) {
|
761 |
+
return ;
|
762 |
+
}
|
763 |
+
|
764 |
+
Varien_Profiler::start('config/load-modules-declaration');
|
765 |
+
|
766 |
+
$unsortedConfig = new Mage_Core_Model_Config_Base();
|
767 |
+
$unsortedConfig->loadString('<config/>');
|
768 |
+
$fileConfig = new Mage_Core_Model_Config_Base();
|
769 |
+
|
770 |
+
// load modules declarations
|
771 |
+
foreach ($moduleFiles as $file) {
|
772 |
+
$fileConfig->loadFile($file);
|
773 |
+
$unsortedConfig->extend($fileConfig);
|
774 |
+
}
|
775 |
+
|
776 |
+
$moduleDepends = array();
|
777 |
+
foreach ($unsortedConfig->getNode('modules')->children() as $moduleName => $moduleNode) {
|
778 |
+
if (!$this->_isAllowedModule($moduleName)) {
|
779 |
+
continue;
|
780 |
+
}
|
781 |
+
|
782 |
+
$depends = array();
|
783 |
+
if ($moduleNode->depends) {
|
784 |
+
foreach ($moduleNode->depends->children() as $depend) {
|
785 |
+
$depends[$depend->getName()] = true;
|
786 |
+
}
|
787 |
+
}
|
788 |
+
$moduleDepends[$moduleName] = array(
|
789 |
+
'module' => $moduleName,
|
790 |
+
'depends' => $depends,
|
791 |
+
'active' => ('true' === (string)$moduleNode->active ? true : false),
|
792 |
+
);
|
793 |
+
}
|
794 |
+
|
795 |
+
// check and sort module dependence
|
796 |
+
$moduleDepends = $this->_sortModuleDepends($moduleDepends);
|
797 |
+
|
798 |
+
// create sorted config
|
799 |
+
$sortedConfig = new Mage_Core_Model_Config_Base();
|
800 |
+
$sortedConfig->loadString('<config><modules/></config>');
|
801 |
+
|
802 |
+
foreach ($unsortedConfig->getNode()->children() as $nodeName => $node) {
|
803 |
+
if ($nodeName != 'modules') {
|
804 |
+
$sortedConfig->getNode()->appendChild($node);
|
805 |
+
}
|
806 |
+
}
|
807 |
+
|
808 |
+
foreach ($moduleDepends as $moduleProp) {
|
809 |
+
$node = $unsortedConfig->getNode('modules/'.$moduleProp['module']);
|
810 |
+
$sortedConfig->getNode('modules')->appendChild($node);
|
811 |
+
}
|
812 |
+
|
813 |
+
$this->extend($sortedConfig);
|
814 |
+
|
815 |
+
Varien_Profiler::stop('config/load-modules-declaration');
|
816 |
+
return $this;
|
817 |
+
}
|
818 |
+
|
819 |
+
/**
|
820 |
+
* Sort modules and check depends
|
821 |
+
*
|
822 |
+
* @param array $modules
|
823 |
+
* @return array
|
824 |
+
*/
|
825 |
+
protected function _sortModuleDepends($modules)
|
826 |
+
{
|
827 |
+
foreach ($modules as $moduleName => $moduleProps) {
|
828 |
+
$depends = $moduleProps['depends'];
|
829 |
+
foreach ($moduleProps['depends'] as $depend => $true) {
|
830 |
+
if ($moduleProps['active'] && ((!isset($modules[$depend])) || empty($modules[$depend]['active']))) {
|
831 |
+
Mage::throwException(
|
832 |
+
Mage::helper('core')->__('Module "%1$s" requires module "%2$s".', $moduleName, $depend)
|
833 |
+
);
|
834 |
+
}
|
835 |
+
$depends = array_merge($depends, $modules[$depend]['depends']);
|
836 |
+
}
|
837 |
+
$modules[$moduleName]['depends'] = $depends;
|
838 |
+
}
|
839 |
+
$modules = array_values($modules);
|
840 |
+
|
841 |
+
$size = count($modules) - 1;
|
842 |
+
for ($i = $size; $i >= 0; $i--) {
|
843 |
+
for ($j = $size; $i < $j; $j--) {
|
844 |
+
if (isset($modules[$i]['depends'][$modules[$j]['module']])) {
|
845 |
+
$value = $modules[$i];
|
846 |
+
$modules[$i] = $modules[$j];
|
847 |
+
$modules[$j] = $value;
|
848 |
+
}
|
849 |
+
}
|
850 |
+
}
|
851 |
+
|
852 |
+
$definedModules = array();
|
853 |
+
foreach ($modules as $moduleProp) {
|
854 |
+
foreach ($moduleProp['depends'] as $dependModule => $true) {
|
855 |
+
if (!isset($definedModules[$dependModule])) {
|
856 |
+
Mage::throwException(
|
857 |
+
Mage::helper('core')->__('Module "%1$s" cannot depend on "%2$s".', $moduleProp['module'], $dependModule)
|
858 |
+
);
|
859 |
+
}
|
860 |
+
}
|
861 |
+
$definedModules[$moduleProp['module']] = true;
|
862 |
+
}
|
863 |
+
|
864 |
+
return $modules;
|
865 |
+
}
|
866 |
+
|
867 |
+
/**
|
868 |
+
* Determine whether provided name begins from any available modules, according to namespaces priority
|
869 |
+
* If matched, returns as the matched module "factory" name or a fully qualified module name
|
870 |
+
*
|
871 |
+
* @param string $name
|
872 |
+
* @param bool $asFullModuleName
|
873 |
+
* @return string
|
874 |
+
*/
|
875 |
+
public function determineOmittedNamespace($name, $asFullModuleName = false)
|
876 |
+
{
|
877 |
+
if (null === $this->_moduleNamespaces) {
|
878 |
+
$this->_moduleNamespaces = array();
|
879 |
+
foreach ($this->_xml->xpath('modules/*') as $m) {
|
880 |
+
if ((string)$m->active == 'true') {
|
881 |
+
$moduleName = $m->getName();
|
882 |
+
$module = strtolower($moduleName);
|
883 |
+
$this->_moduleNamespaces[substr($module, 0, strpos($module, '_'))][$module] = $moduleName;
|
884 |
+
}
|
885 |
+
}
|
886 |
+
}
|
887 |
+
|
888 |
+
$name = explode('_', strtolower($name));
|
889 |
+
$partsNum = count($name);
|
890 |
+
$defaultNamespaceFlag = false;
|
891 |
+
foreach ($this->_moduleNamespaces as $namespaceName => $namespace) {
|
892 |
+
// assume the namespace is omitted (default namespace only, which comes first)
|
893 |
+
if ($defaultNamespaceFlag === false) {
|
894 |
+
$defaultNamespaceFlag = true;
|
895 |
+
$defaultNS = $namespaceName . '_' . $name[0];
|
896 |
+
if (isset($namespace[$defaultNS])) {
|
897 |
+
return $asFullModuleName ? $namespace[$defaultNS] : $name[0]; // return omitted as well
|
898 |
+
}
|
899 |
+
}
|
900 |
+
// assume namespace is qualified
|
901 |
+
if(isset($name[1])) {
|
902 |
+
$fullNS = $name[0] . '_' . $name[1];
|
903 |
+
if (2 <= $partsNum && isset($namespace[$fullNS])) {
|
904 |
+
return $asFullModuleName ? $namespace[$fullNS] : $fullNS;
|
905 |
+
}
|
906 |
+
}
|
907 |
+
}
|
908 |
+
return '';
|
909 |
+
}
|
910 |
+
|
911 |
+
/**
|
912 |
+
* Iterate all active modules "etc" folders and combine data from
|
913 |
+
* specidied xml file name to one object
|
914 |
+
*
|
915 |
+
* @param string $fileName
|
916 |
+
* @param null|Mage_Core_Model_Config_Base $mergeToObject
|
917 |
+
* @return Mage_Core_Model_Config_Base
|
918 |
+
*/
|
919 |
+
public function loadModulesConfiguration($fileName, $mergeToObject = null, $mergeModel=null)
|
920 |
+
{
|
921 |
+
$disableLocalModules = !$this->_canUseLocalModules();
|
922 |
+
|
923 |
+
if ($mergeToObject === null) {
|
924 |
+
$mergeToObject = clone $this->_prototype;
|
925 |
+
$mergeToObject->loadString('<config/>');
|
926 |
+
}
|
927 |
+
if ($mergeModel === null) {
|
928 |
+
$mergeModel = clone $this->_prototype;
|
929 |
+
}
|
930 |
+
$modules = $this->getNode('modules')->children();
|
931 |
+
foreach ($modules as $modName=>$module) {
|
932 |
+
if ($module->is('active')) {
|
933 |
+
if ($disableLocalModules && ('local' === (string)$module->codePool)) {
|
934 |
+
continue;
|
935 |
+
}
|
936 |
+
if (!is_array($fileName)) {
|
937 |
+
$fileName = array($fileName);
|
938 |
+
}
|
939 |
+
|
940 |
+
foreach ($fileName as $configFile) {
|
941 |
+
$configFile = $this->getModuleDir('etc', $modName).DS.$configFile;
|
942 |
+
if ($mergeModel->loadFile($configFile)) {
|
943 |
+
$mergeToObject->extend($mergeModel, true);
|
944 |
+
}
|
945 |
+
}
|
946 |
+
}
|
947 |
+
}
|
948 |
+
return $mergeToObject;
|
949 |
+
}
|
950 |
+
|
951 |
+
/**
|
952 |
+
* Retrieve temporary directory path
|
953 |
+
*
|
954 |
+
* @return string
|
955 |
+
*/
|
956 |
+
public function getTempVarDir()
|
957 |
+
{
|
958 |
+
return $this->getOptions()->getVarDir();
|
959 |
+
}
|
960 |
+
|
961 |
+
/**
|
962 |
+
* Get default server variables values
|
963 |
+
*
|
964 |
+
* @return array
|
965 |
+
*/
|
966 |
+
public function getDistroServerVars()
|
967 |
+
{
|
968 |
+
if (!$this->_distroServerVars) {
|
969 |
+
|
970 |
+
if (isset($_SERVER['SCRIPT_NAME']) && isset($_SERVER['HTTP_HOST'])) {
|
971 |
+
$secure = (!empty($_SERVER['HTTPS']) && ($_SERVER['HTTPS']!='off')) || $_SERVER['SERVER_PORT']=='443';
|
972 |
+
$scheme = ($secure ? 'https' : 'http') . '://' ;
|
973 |
+
|
974 |
+
$hostArr = explode(':', $_SERVER['HTTP_HOST']);
|
975 |
+
$host = $hostArr[0];
|
976 |
+
$port = isset(
|
977 |
+
$hostArr[1]) && (!$secure && $hostArr[1]!=80 || $secure && $hostArr[1]!=443
|
978 |
+
) ? ':'.$hostArr[1] : '';
|
979 |
+
$path = Mage::app()->getRequest()->getBasePath();
|
980 |
+
|
981 |
+
$baseUrl = $scheme.$host.$port.rtrim($path, '/').'/';
|
982 |
+
} else {
|
983 |
+
$baseUrl = 'http://localhost/';
|
984 |
+
}
|
985 |
+
|
986 |
+
$options = $this->getOptions();
|
987 |
+
$this->_distroServerVars = array(
|
988 |
+
'root_dir' => $options->getBaseDir(),
|
989 |
+
'app_dir' => $options->getAppDir(),
|
990 |
+
'var_dir' => $options->getVarDir(),
|
991 |
+
'base_url' => $baseUrl,
|
992 |
+
);
|
993 |
+
|
994 |
+
foreach ($this->_distroServerVars as $k=>$v) {
|
995 |
+
$this->_substServerVars['{{'.$k.'}}'] = $v;
|
996 |
+
}
|
997 |
+
}
|
998 |
+
return $this->_distroServerVars;
|
999 |
+
}
|
1000 |
+
|
1001 |
+
public function substDistroServerVars($data)
|
1002 |
+
{
|
1003 |
+
$this->getDistroServerVars();
|
1004 |
+
return str_replace(
|
1005 |
+
array_keys($this->_substServerVars),
|
1006 |
+
array_values($this->_substServerVars),
|
1007 |
+
$data
|
1008 |
+
);
|
1009 |
+
}
|
1010 |
+
|
1011 |
+
/**
|
1012 |
+
* Get module config node
|
1013 |
+
*
|
1014 |
+
* @param string $moduleName
|
1015 |
+
* @return Varien_Simplexml_Object
|
1016 |
+
*/
|
1017 |
+
function getModuleConfig($moduleName='')
|
1018 |
+
{
|
1019 |
+
$modules = $this->getNode('modules');
|
1020 |
+
if (''===$moduleName) {
|
1021 |
+
return $modules;
|
1022 |
+
} else {
|
1023 |
+
return $modules->$moduleName;
|
1024 |
+
}
|
1025 |
+
}
|
1026 |
+
|
1027 |
+
/**
|
1028 |
+
* Get module setup class instance.
|
1029 |
+
*
|
1030 |
+
* Defaults to Mage_Core_Setup
|
1031 |
+
*
|
1032 |
+
* @param string|Varien_Simplexml_Object $module
|
1033 |
+
* @return object
|
1034 |
+
*/
|
1035 |
+
function getModuleSetup($module='')
|
1036 |
+
{
|
1037 |
+
$className = 'Mage_Core_Setup';
|
1038 |
+
if (''!==$module) {
|
1039 |
+
if (is_string($module)) {
|
1040 |
+
$module = $this->getModuleConfig($module);
|
1041 |
+
}
|
1042 |
+
if (isset($module->setup)) {
|
1043 |
+
$moduleClassName = $module->setup->getClassName();
|
1044 |
+
if (!empty($moduleClassName)) {
|
1045 |
+
$className = $moduleClassName;
|
1046 |
+
}
|
1047 |
+
}
|
1048 |
+
}
|
1049 |
+
return new $className($module);
|
1050 |
+
}
|
1051 |
+
|
1052 |
+
/**
|
1053 |
+
* Get base filesystem directory. depends on $type
|
1054 |
+
*
|
1055 |
+
* If $moduleName is specified retrieves specific value for the module.
|
1056 |
+
*
|
1057 |
+
* @deprecated in favor of Mage_Core_Model_Config_Options
|
1058 |
+
* @todo get global dir config
|
1059 |
+
* @param string $type
|
1060 |
+
* @return string
|
1061 |
+
*/
|
1062 |
+
public function getBaseDir($type='base')
|
1063 |
+
{
|
1064 |
+
return $this->getOptions()->getDir($type);
|
1065 |
+
}
|
1066 |
+
|
1067 |
+
/**
|
1068 |
+
* Get temporary data directory name
|
1069 |
+
*
|
1070 |
+
* @param string $path
|
1071 |
+
* @param string $type
|
1072 |
+
* @return string
|
1073 |
+
*/
|
1074 |
+
public function getVarDir($path=null, $type='var')
|
1075 |
+
{
|
1076 |
+
$dir = Mage::getBaseDir($type).($path!==null ? DS.$path : '');
|
1077 |
+
if (!$this->createDirIfNotExists($dir)) {
|
1078 |
+
return false;
|
1079 |
+
}
|
1080 |
+
return $dir;
|
1081 |
+
}
|
1082 |
+
|
1083 |
+
public function createDirIfNotExists($dir)
|
1084 |
+
{
|
1085 |
+
return $this->getOptions()->createDirIfNotExists($dir);
|
1086 |
+
}
|
1087 |
+
|
1088 |
+
/**
|
1089 |
+
* Get module directory by directory type
|
1090 |
+
*
|
1091 |
+
* @param string $type
|
1092 |
+
* @param string $moduleName
|
1093 |
+
* @return string
|
1094 |
+
*/
|
1095 |
+
public function getModuleDir($type, $moduleName)
|
1096 |
+
{
|
1097 |
+
$codePool = (string)$this->getModuleConfig($moduleName)->codePool;
|
1098 |
+
$dir = $this->getOptions()->getCodeDir().DS.$codePool.DS.uc_words($moduleName, DS);
|
1099 |
+
|
1100 |
+
switch ($type) {
|
1101 |
+
case 'etc':
|
1102 |
+
$dir .= DS.'etc';
|
1103 |
+
break;
|
1104 |
+
|
1105 |
+
case 'controllers':
|
1106 |
+
$dir .= DS.'controllers';
|
1107 |
+
break;
|
1108 |
+
|
1109 |
+
case 'sql':
|
1110 |
+
$dir .= DS.'sql';
|
1111 |
+
break;
|
1112 |
+
case 'data':
|
1113 |
+
$dir .= DS.'data';
|
1114 |
+
break;
|
1115 |
+
|
1116 |
+
case 'locale':
|
1117 |
+
$dir .= DS.'locale';
|
1118 |
+
break;
|
1119 |
+
}
|
1120 |
+
|
1121 |
+
$dir = str_replace('/', DS, $dir);
|
1122 |
+
return $dir;
|
1123 |
+
}
|
1124 |
+
|
1125 |
+
/**
|
1126 |
+
* Load event observers for an area (front, admin)
|
1127 |
+
*
|
1128 |
+
* @param string $area
|
1129 |
+
* @return boolean
|
1130 |
+
*/
|
1131 |
+
public function loadEventObservers($area)
|
1132 |
+
{
|
1133 |
+
$events = $this->getNode("$area/events");
|
1134 |
+
if ($events) {
|
1135 |
+
$events = $events->children();
|
1136 |
+
} else {
|
1137 |
+
return false;
|
1138 |
+
}
|
1139 |
+
|
1140 |
+
foreach ($events as $event) {
|
1141 |
+
$eventName = $event->getName();
|
1142 |
+
$observers = $event->observers->children();
|
1143 |
+
foreach ($observers as $observer) {
|
1144 |
+
switch ((string)$observer->type) {
|
1145 |
+
case 'singleton':
|
1146 |
+
$callback = array(
|
1147 |
+
Mage::getSingleton((string)$observer->class),
|
1148 |
+
(string)$observer->method
|
1149 |
+
);
|
1150 |
+
break;
|
1151 |
+
case 'object':
|
1152 |
+
case 'model':
|
1153 |
+
$callback = array(
|
1154 |
+
Mage::getModel((string)$observer->class),
|
1155 |
+
(string)$observer->method
|
1156 |
+
);
|
1157 |
+
break;
|
1158 |
+
default:
|
1159 |
+
$callback = array($observer->getClassName(), (string)$observer->method);
|
1160 |
+
break;
|
1161 |
+
}
|
1162 |
+
|
1163 |
+
$args = (array)$observer->args;
|
1164 |
+
$observerClass = $observer->observer_class ? (string)$observer->observer_class : '';
|
1165 |
+
Mage::addObserver($eventName, $callback, $args, $observer->getName(), $observerClass);
|
1166 |
+
}
|
1167 |
+
}
|
1168 |
+
return true;
|
1169 |
+
}
|
1170 |
+
|
1171 |
+
/**
|
1172 |
+
* Get standard path variables.
|
1173 |
+
*
|
1174 |
+
* To be used in blocks, templates, etc.
|
1175 |
+
*
|
1176 |
+
* @param array|string $args Module name if string
|
1177 |
+
* @return array
|
1178 |
+
*/
|
1179 |
+
public function getPathVars($args=null)
|
1180 |
+
{
|
1181 |
+
$path = array();
|
1182 |
+
|
1183 |
+
$path['baseUrl'] = Mage::getBaseUrl();
|
1184 |
+
$path['baseSecureUrl'] = Mage::getBaseUrl('link', true);
|
1185 |
+
|
1186 |
+
return $path;
|
1187 |
+
}
|
1188 |
+
|
1189 |
+
/**
|
1190 |
+
* Retrieve class name by class group
|
1191 |
+
*
|
1192 |
+
* @param string $groupType currently supported model, block, helper
|
1193 |
+
* @param string $classId slash separated class identifier, ex. group/class
|
1194 |
+
* @param string $groupRootNode optional config path for group config
|
1195 |
+
* @return string
|
1196 |
+
*/
|
1197 |
+
public function getGroupedClassName($groupType, $classId, $groupRootNode=null)
|
1198 |
+
{
|
1199 |
+
if (empty($groupRootNode)) {
|
1200 |
+
$groupRootNode = 'global/'.$groupType.'s';
|
1201 |
+
}
|
1202 |
+
|
1203 |
+
$classArr = explode('/', trim($classId));
|
1204 |
+
$group = $classArr[0];
|
1205 |
+
$class = !empty($classArr[1]) ? $classArr[1] : null;
|
1206 |
+
|
1207 |
+
if (isset($this->_classNameCache[$groupRootNode][$group][$class])) {
|
1208 |
+
return $this->_classNameCache[$groupRootNode][$group][$class];
|
1209 |
+
}
|
1210 |
+
|
1211 |
+
$config = $this->_xml->global->{$groupType.'s'}->{$group};
|
1212 |
+
|
1213 |
+
// First - check maybe the entity class was rewritten
|
1214 |
+
$className = null;
|
1215 |
+
if (isset($config->rewrite->$class)) {
|
1216 |
+
$className = (string)$config->rewrite->$class;
|
1217 |
+
} else {
|
1218 |
+
/**
|
1219 |
+
* Backwards compatibility for pre-MMDB extensions.
|
1220 |
+
* In MMDB release resource nodes <..._mysql4> were renamed to <..._resource>. So <deprecatedNode> is left
|
1221 |
+
* to keep name of previously used nodes, that still may be used by non-updated extensions.
|
1222 |
+
*/
|
1223 |
+
if ($config->deprecatedNode) {
|
1224 |
+
$deprecatedNode = $config->deprecatedNode;
|
1225 |
+
$configOld = $this->_xml->global->{$groupType.'s'}->$deprecatedNode;
|
1226 |
+
if (isset($configOld->rewrite->$class)) {
|
1227 |
+
$className = (string) $configOld->rewrite->$class;
|
1228 |
+
}
|
1229 |
+
}
|
1230 |
+
}
|
1231 |
+
|
1232 |
+
// Second - if entity is not rewritten then use class prefix to form class name
|
1233 |
+
if (empty($className)) {
|
1234 |
+
if (!empty($config)) {
|
1235 |
+
$className = $config->getClassName();
|
1236 |
+
}
|
1237 |
+
if (empty($className)) {
|
1238 |
+
$className = 'mage_'.$group.'_'.$groupType;
|
1239 |
+
}
|
1240 |
+
if (!empty($class)) {
|
1241 |
+
$className .= '_'.$class;
|
1242 |
+
}
|
1243 |
+
$className = uc_words($className);
|
1244 |
+
}
|
1245 |
+
|
1246 |
+
$this->_classNameCache[$groupRootNode][$group][$class] = $className;
|
1247 |
+
return $className;
|
1248 |
+
}
|
1249 |
+
|
1250 |
+
/**
|
1251 |
+
* Retrieve block class name
|
1252 |
+
*
|
1253 |
+
* @param string $blockType
|
1254 |
+
* @return string
|
1255 |
+
*/
|
1256 |
+
public function getBlockClassName($blockType)
|
1257 |
+
{
|
1258 |
+
if (strpos($blockType, '/')===false) {
|
1259 |
+
return $blockType;
|
1260 |
+
}
|
1261 |
+
return $this->getGroupedClassName('block', $blockType);
|
1262 |
+
}
|
1263 |
+
|
1264 |
+
/**
|
1265 |
+
* Retrieve helper class name
|
1266 |
+
*
|
1267 |
+
* @param string $name
|
1268 |
+
* @return string
|
1269 |
+
*/
|
1270 |
+
public function getHelperClassName($helperName)
|
1271 |
+
{
|
1272 |
+
if (strpos($helperName, '/') === false) {
|
1273 |
+
$helperName .= '/data';
|
1274 |
+
}
|
1275 |
+
return $this->getGroupedClassName('helper', $helperName);
|
1276 |
+
}
|
1277 |
+
|
1278 |
+
/**
|
1279 |
+
* Retreive resource helper instance
|
1280 |
+
*
|
1281 |
+
* Example:
|
1282 |
+
* $config->getResourceHelper('cms')
|
1283 |
+
* will instantiate Mage_Cms_Model_Resource_Helper_<db_adapter_name>
|
1284 |
+
*
|
1285 |
+
* @param string $moduleName
|
1286 |
+
* @return Mage_Core_Model_Resource_Helper_Abstract|false
|
1287 |
+
*/
|
1288 |
+
public function getResourceHelper($moduleName)
|
1289 |
+
{
|
1290 |
+
$connectionModel = $this->_getResourceConnectionModel($moduleName);
|
1291 |
+
$helperClass = sprintf('%s/helper_%s', $moduleName, $connectionModel);
|
1292 |
+
$helperClassName = $this->_getResourceModelFactoryClassName($helperClass);
|
1293 |
+
if ($helperClassName) {
|
1294 |
+
return $this->getModelInstance($helperClassName, $moduleName);
|
1295 |
+
}
|
1296 |
+
|
1297 |
+
return false;
|
1298 |
+
}
|
1299 |
+
|
1300 |
+
/**
|
1301 |
+
* Retrieve module class name
|
1302 |
+
*
|
1303 |
+
* @param sting $modelClass
|
1304 |
+
* @return string
|
1305 |
+
*/
|
1306 |
+
public function getModelClassName($modelClass)
|
1307 |
+
{
|
1308 |
+
$modelClass = trim($modelClass);
|
1309 |
+
if (strpos($modelClass, '/')===false) {
|
1310 |
+
return $modelClass;
|
1311 |
+
}
|
1312 |
+
return $this->getGroupedClassName('model', $modelClass);
|
1313 |
+
}
|
1314 |
+
|
1315 |
+
/**
|
1316 |
+
* Get model class instance.
|
1317 |
+
*
|
1318 |
+
* Example:
|
1319 |
+
* $config->getModelInstance('catalog/product')
|
1320 |
+
*
|
1321 |
+
* Will instantiate Mage_Catalog_Model_Mysql4_Product
|
1322 |
+
*
|
1323 |
+
* @param string $modelClass
|
1324 |
+
* @param array|object $constructArguments
|
1325 |
+
* @return Mage_Core_Model_Abstract|false
|
1326 |
+
*/
|
1327 |
+
public function getModelInstance($modelClass='', $constructArguments=array())
|
1328 |
+
{
|
1329 |
+
$className = $this->getModelClassName($modelClass);
|
1330 |
+
if (class_exists($className)) {
|
1331 |
+
Varien_Profiler::start('CORE::create_object_of::'.$className);
|
1332 |
+
$obj = new $className($constructArguments);
|
1333 |
+
Varien_Profiler::stop('CORE::create_object_of::'.$className);
|
1334 |
+
return $obj;
|
1335 |
+
} else {
|
1336 |
+
return false;
|
1337 |
+
}
|
1338 |
+
}
|
1339 |
+
|
1340 |
+
public function getNodeClassInstance($path)
|
1341 |
+
{
|
1342 |
+
$config = Mage::getConfig()->getNode($path);
|
1343 |
+
if (!$config) {
|
1344 |
+
return false;
|
1345 |
+
} else {
|
1346 |
+
$className = $config->getClassName();
|
1347 |
+
return new $className();
|
1348 |
+
}
|
1349 |
+
}
|
1350 |
+
|
1351 |
+
/**
|
1352 |
+
* Get resource model object by alias
|
1353 |
+
*
|
1354 |
+
* @param string $modelClass
|
1355 |
+
* @param array $constructArguments
|
1356 |
+
* @return object
|
1357 |
+
*/
|
1358 |
+
public function getResourceModelInstance($modelClass='', $constructArguments=array())
|
1359 |
+
{
|
1360 |
+
$factoryName = $this->_getResourceModelFactoryClassName($modelClass);
|
1361 |
+
if (!$factoryName) {
|
1362 |
+
return false;
|
1363 |
+
}
|
1364 |
+
return $this->getModelInstance($factoryName, $constructArguments);
|
1365 |
+
}
|
1366 |
+
|
1367 |
+
/**
|
1368 |
+
* Get resource configuration for resource name
|
1369 |
+
*
|
1370 |
+
* @param string $name
|
1371 |
+
* @return Varien_Simplexml_Object
|
1372 |
+
*/
|
1373 |
+
public function getResourceConfig($name)
|
1374 |
+
{
|
1375 |
+
return $this->_xml->global->resources->{$name};
|
1376 |
+
}
|
1377 |
+
|
1378 |
+
/**
|
1379 |
+
* Get connection configuration
|
1380 |
+
*
|
1381 |
+
* @param string $name
|
1382 |
+
* @return Varien_Simplexml_Element
|
1383 |
+
*/
|
1384 |
+
public function getResourceConnectionConfig($name)
|
1385 |
+
{
|
1386 |
+
$config = $this->getResourceConfig($name);
|
1387 |
+
if ($config) {
|
1388 |
+
$conn = $config->connection;
|
1389 |
+
if ($conn) {
|
1390 |
+
if (!empty($conn->use)) {
|
1391 |
+
return $this->getResourceConnectionConfig((string)$conn->use);
|
1392 |
+
} else {
|
1393 |
+
return $conn;
|
1394 |
+
}
|
1395 |
+
}
|
1396 |
+
}
|
1397 |
+
return false;
|
1398 |
+
}
|
1399 |
+
|
1400 |
+
/**
|
1401 |
+
* Retrieve resource type configuration for resource name
|
1402 |
+
*
|
1403 |
+
* @param string $type
|
1404 |
+
* @return Varien_Simplexml_Object
|
1405 |
+
*/
|
1406 |
+
public function getResourceTypeConfig($type)
|
1407 |
+
{
|
1408 |
+
return $this->_xml->global->resource->connection->types->{$type};
|
1409 |
+
}
|
1410 |
+
|
1411 |
+
/**
|
1412 |
+
* Retrieve store Ids for $path with checking
|
1413 |
+
*
|
1414 |
+
* if empty $allowValues then retrieve all stores values
|
1415 |
+
*
|
1416 |
+
* return array($storeId=>$pathValue)
|
1417 |
+
*
|
1418 |
+
* @param string $path
|
1419 |
+
* @param array $allowValues
|
1420 |
+
* @return array
|
1421 |
+
*/
|
1422 |
+
public function getStoresConfigByPath($path, $allowValues = array(), $useAsKey = 'id')
|
1423 |
+
{
|
1424 |
+
$storeValues = array();
|
1425 |
+
$stores = $this->getNode('stores');
|
1426 |
+
foreach ($stores->children() as $code => $store) {
|
1427 |
+
switch ($useAsKey) {
|
1428 |
+
case 'id':
|
1429 |
+
$key = (int) $store->descend('system/store/id');
|
1430 |
+
break;
|
1431 |
+
|
1432 |
+
case 'code':
|
1433 |
+
$key = $code;
|
1434 |
+
break;
|
1435 |
+
|
1436 |
+
case 'name':
|
1437 |
+
$key = (string) $store->descend('system/store/name');
|
1438 |
+
}
|
1439 |
+
if ($key === false) {
|
1440 |
+
continue;
|
1441 |
+
}
|
1442 |
+
|
1443 |
+
$pathValue = (string) $store->descend($path);
|
1444 |
+
|
1445 |
+
if (empty($allowValues)) {
|
1446 |
+
$storeValues[$key] = $pathValue;
|
1447 |
+
} else if (in_array($pathValue, $allowValues)) {
|
1448 |
+
$storeValues[$key] = $pathValue;
|
1449 |
+
}
|
1450 |
+
}
|
1451 |
+
return $storeValues;
|
1452 |
+
}
|
1453 |
+
|
1454 |
+
/**
|
1455 |
+
* Check whether given path should be secure according to configuration security requirements for URL
|
1456 |
+
* "Secure" should not be confused with https protocol, it is about web/secure/*_url settings usage only
|
1457 |
+
*
|
1458 |
+
* @param string $url
|
1459 |
+
* @return bool
|
1460 |
+
*/
|
1461 |
+
public function shouldUrlBeSecure($url)
|
1462 |
+
{
|
1463 |
+
if (!Mage::getStoreConfigFlag(Mage_Core_Model_Store::XML_PATH_SECURE_IN_FRONTEND)) {
|
1464 |
+
return false;
|
1465 |
+
}
|
1466 |
+
|
1467 |
+
if (!isset($this->_secureUrlCache[$url])) {
|
1468 |
+
$this->_secureUrlCache[$url] = false;
|
1469 |
+
$secureUrls = $this->getNode('frontend/secure_url');
|
1470 |
+
foreach ($secureUrls->children() as $match) {
|
1471 |
+
if (strpos($url, (string)$match) === 0) {
|
1472 |
+
$this->_secureUrlCache[$url] = true;
|
1473 |
+
break;
|
1474 |
+
}
|
1475 |
+
}
|
1476 |
+
}
|
1477 |
+
|
1478 |
+
return $this->_secureUrlCache[$url];
|
1479 |
+
}
|
1480 |
+
|
1481 |
+
/**
|
1482 |
+
* Get DB table names prefix
|
1483 |
+
*
|
1484 |
+
* @return string
|
1485 |
+
*/
|
1486 |
+
public function getTablePrefix()
|
1487 |
+
{
|
1488 |
+
return $this->_xml->global->resources->db->table_prefix;
|
1489 |
+
}
|
1490 |
+
|
1491 |
+
/**
|
1492 |
+
* Get events configuration
|
1493 |
+
*
|
1494 |
+
* @param string $area event area
|
1495 |
+
* @param string $eventName event name
|
1496 |
+
* @return Mage_Core_Model_Config_Element
|
1497 |
+
*/
|
1498 |
+
public function getEventConfig($area, $eventName)
|
1499 |
+
{
|
1500 |
+
//return $this->getNode($area)->events->{$eventName};
|
1501 |
+
if (!isset($this->_eventAreas[$area])) {
|
1502 |
+
$this->_eventAreas[$area] = $this->getNode($area)->events;
|
1503 |
+
}
|
1504 |
+
return $this->_eventAreas[$area]->{$eventName};
|
1505 |
+
}
|
1506 |
+
|
1507 |
+
/**
|
1508 |
+
* Save config value to DB
|
1509 |
+
*
|
1510 |
+
* @param string $path
|
1511 |
+
* @param string $value
|
1512 |
+
* @param string $scope
|
1513 |
+
* @param int $scopeId
|
1514 |
+
* @return Mage_Core_Store_Config
|
1515 |
+
*/
|
1516 |
+
public function saveConfig($path, $value, $scope = 'default', $scopeId = 0)
|
1517 |
+
{
|
1518 |
+
$resource = $this->getResourceModel();
|
1519 |
+
$resource->saveConfig(rtrim($path, '/'), $value, $scope, $scopeId);
|
1520 |
+
|
1521 |
+
/***********************************************************************
|
1522 |
+
* BEGIN Customweb Dependency Module specific changes
|
1523 |
+
***********************************************************************/
|
1524 |
+
Mage::dispatchEvent('core_model_config_save_after', array('object'=>$this, 'path'=>$path, 'scope'=>$scope, 'scope_id'=>$scopeId, 'value'=>$value));
|
1525 |
+
/***********************************************************************
|
1526 |
+
* END Customweb Dependency Module specific changes
|
1527 |
+
***********************************************************************/
|
1528 |
+
return $this;
|
1529 |
+
}
|
1530 |
+
|
1531 |
+
/**
|
1532 |
+
* Delete config value from DB
|
1533 |
+
*
|
1534 |
+
* @param string $path
|
1535 |
+
* @param string $scope
|
1536 |
+
* @param int $scopeId
|
1537 |
+
* @return Mage_Core_Model_Config
|
1538 |
+
*/
|
1539 |
+
public function deleteConfig($path, $scope = 'default', $scopeId = 0)
|
1540 |
+
{
|
1541 |
+
$resource = $this->getResourceModel();
|
1542 |
+
$resource->deleteConfig(rtrim($path, '/'), $scope, $scopeId);
|
1543 |
+
|
1544 |
+
return $this;
|
1545 |
+
}
|
1546 |
+
|
1547 |
+
/**
|
1548 |
+
* Get fieldset from configuration
|
1549 |
+
*
|
1550 |
+
* @param string $name fieldset name
|
1551 |
+
* @param string $root fieldset area, could be 'admin'
|
1552 |
+
* @return null|array
|
1553 |
+
*/
|
1554 |
+
public function getFieldset($name, $root = 'global')
|
1555 |
+
{
|
1556 |
+
$rootNode = $this->getNode($root.'/fieldsets');
|
1557 |
+
if (!$rootNode) {
|
1558 |
+
return null;
|
1559 |
+
}
|
1560 |
+
return $rootNode->$name ? $rootNode->$name->children() : null;
|
1561 |
+
}
|
1562 |
+
|
1563 |
+
/**
|
1564 |
+
* Retrieve resource connection model name
|
1565 |
+
*
|
1566 |
+
* @param string $moduleName
|
1567 |
+
* @return string
|
1568 |
+
*/
|
1569 |
+
protected function _getResourceConnectionModel($moduleName = null)
|
1570 |
+
{
|
1571 |
+
$config = null;
|
1572 |
+
if (!is_null($moduleName)) {
|
1573 |
+
$setupResource = $moduleName . '_setup';
|
1574 |
+
$config = $this->getResourceConnectionConfig($setupResource);
|
1575 |
+
}
|
1576 |
+
if (!$config) {
|
1577 |
+
$config = $this->getResourceConnectionConfig(Mage_Core_Model_Resource::DEFAULT_SETUP_RESOURCE);
|
1578 |
+
}
|
1579 |
+
|
1580 |
+
return (string)$config->model;
|
1581 |
+
}
|
1582 |
+
|
1583 |
+
/**
|
1584 |
+
* Get factory class name for a resource
|
1585 |
+
*
|
1586 |
+
* @param string $modelClass
|
1587 |
+
* @return string|false
|
1588 |
+
*/
|
1589 |
+
protected function _getResourceModelFactoryClassName($modelClass)
|
1590 |
+
{
|
1591 |
+
$classArray = explode('/', $modelClass);
|
1592 |
+
if (count($classArray) != 2) {
|
1593 |
+
return false;
|
1594 |
+
}
|
1595 |
+
|
1596 |
+
list($module, $model) = $classArray;
|
1597 |
+
if (!isset($this->_xml->global->models->{$module})) {
|
1598 |
+
return false;
|
1599 |
+
}
|
1600 |
+
|
1601 |
+
$moduleNode = $this->_xml->global->models->{$module};
|
1602 |
+
if (!empty($moduleNode->resourceModel)) {
|
1603 |
+
$resourceModel = (string)$moduleNode->resourceModel;
|
1604 |
+
} else {
|
1605 |
+
return false;
|
1606 |
+
}
|
1607 |
+
|
1608 |
+
return $resourceModel . '/' . $model;
|
1609 |
+
}
|
1610 |
+
|
1611 |
+
/**
|
1612 |
+
* Get a resource model class name
|
1613 |
+
*
|
1614 |
+
* @param string $modelClass
|
1615 |
+
* @return string|false
|
1616 |
+
*/
|
1617 |
+
public function getResourceModelClassName($modelClass)
|
1618 |
+
{
|
1619 |
+
$factoryName = $this->_getResourceModelFactoryClassName($modelClass);
|
1620 |
+
if ($factoryName) {
|
1621 |
+
return $this->getModelClassName($factoryName);
|
1622 |
+
}
|
1623 |
+
return false;
|
1624 |
+
}
|
1625 |
+
}
|
app/code/local/Varien/Data/Form/Element/Abstract.php
ADDED
@@ -0,0 +1,314 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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 Varien
|
22 |
+
* @package Varien_Data
|
23 |
+
* @copyright Copyright (c) 2008 Irubin Consulting Inc. DBA Varien (http://www.varien.com)
|
24 |
+
* @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
|
25 |
+
*/
|
26 |
+
|
27 |
+
|
28 |
+
/**
|
29 |
+
* Data form abstract class
|
30 |
+
*
|
31 |
+
* @category Varien
|
32 |
+
* @package Varien_Data
|
33 |
+
* @author Magento Core Team <core@magentocommerce.com>
|
34 |
+
*/
|
35 |
+
abstract class Varien_Data_Form_Element_Abstract extends Varien_Data_Form_Abstract
|
36 |
+
{
|
37 |
+
protected $_id;
|
38 |
+
protected $_type;
|
39 |
+
protected $_form;
|
40 |
+
protected $_elements;
|
41 |
+
protected $_renderer;
|
42 |
+
|
43 |
+
public function __construct($attributes = array())
|
44 |
+
{
|
45 |
+
parent::__construct($attributes);
|
46 |
+
$this->_renderer = Varien_Data_Form::getElementRenderer();
|
47 |
+
}
|
48 |
+
|
49 |
+
/**
|
50 |
+
* Add form element
|
51 |
+
*
|
52 |
+
* @param Varien_Data_Form_Element_Abstract $element
|
53 |
+
* @return Varien_Data_Form
|
54 |
+
*/
|
55 |
+
public function addElement(Varien_Data_Form_Element_Abstract $element, $after=false)
|
56 |
+
{
|
57 |
+
if ($this->getForm()) {
|
58 |
+
$this->getForm()->checkElementId($element->getId());
|
59 |
+
$this->getForm()->addElementToCollection($element);
|
60 |
+
}
|
61 |
+
|
62 |
+
parent::addElement($element, $after);
|
63 |
+
return $this;
|
64 |
+
}
|
65 |
+
|
66 |
+
public function getId()
|
67 |
+
{
|
68 |
+
return $this->_id;
|
69 |
+
}
|
70 |
+
|
71 |
+
public function getType()
|
72 |
+
{
|
73 |
+
return $this->_type;
|
74 |
+
}
|
75 |
+
|
76 |
+
public function getForm()
|
77 |
+
{
|
78 |
+
return $this->_form;
|
79 |
+
}
|
80 |
+
|
81 |
+
public function setId($id)
|
82 |
+
{
|
83 |
+
$this->_id = $id;
|
84 |
+
$this->setData('html_id', $id);
|
85 |
+
return $this;
|
86 |
+
}
|
87 |
+
|
88 |
+
public function getHtmlId()
|
89 |
+
{
|
90 |
+
return $this->getForm()->getHtmlIdPrefix() . $this->getData('html_id') . $this->getForm()->getHtmlIdSuffix();
|
91 |
+
}
|
92 |
+
|
93 |
+
public function getName()
|
94 |
+
{
|
95 |
+
$name = $this->getData('name');
|
96 |
+
if ($suffix = $this->getForm()->getFieldNameSuffix()) {
|
97 |
+
$name = $this->getForm()->addSuffixToName($name, $suffix);
|
98 |
+
}
|
99 |
+
return $name;
|
100 |
+
}
|
101 |
+
|
102 |
+
public function setType($type)
|
103 |
+
{
|
104 |
+
$this->_type = $type;
|
105 |
+
$this->setData('type', $type);
|
106 |
+
return $this;
|
107 |
+
}
|
108 |
+
|
109 |
+
public function setForm($form)
|
110 |
+
{
|
111 |
+
$this->_form = $form;
|
112 |
+
return $this;
|
113 |
+
}
|
114 |
+
|
115 |
+
public function removeField($elementId)
|
116 |
+
{
|
117 |
+
$this->getForm()->removeField($elementId);
|
118 |
+
return parent::removeField($elementId);
|
119 |
+
}
|
120 |
+
|
121 |
+
public function getHtmlAttributes()
|
122 |
+
{
|
123 |
+
return array('type', 'title', 'class', 'style', 'onclick', 'onchange', 'disabled', 'readonly', 'tabindex');
|
124 |
+
}
|
125 |
+
|
126 |
+
public function addClass($class)
|
127 |
+
{
|
128 |
+
$oldClass = $this->getClass();
|
129 |
+
$this->setClass($oldClass.' '.$class);
|
130 |
+
return $this;
|
131 |
+
}
|
132 |
+
|
133 |
+
/**
|
134 |
+
* Remove CSS class
|
135 |
+
*
|
136 |
+
* @param string $class
|
137 |
+
* @return Varien_Data_Form_Element_Abstract
|
138 |
+
*/
|
139 |
+
public function removeClass($class)
|
140 |
+
{
|
141 |
+
$classes = array_unique(explode(' ', $this->getClass()));
|
142 |
+
if (false !== ($key = array_search($class, $classes))) {
|
143 |
+
unset($classes[$key]);
|
144 |
+
}
|
145 |
+
$this->setClass(implode(' ', $classes));
|
146 |
+
return $this;
|
147 |
+
}
|
148 |
+
|
149 |
+
protected function _escape($string)
|
150 |
+
{
|
151 |
+
return htmlspecialchars($string, ENT_COMPAT);
|
152 |
+
}
|
153 |
+
|
154 |
+
public function getEscapedValue($index=null)
|
155 |
+
{
|
156 |
+
$value = $this->getValue($index);
|
157 |
+
|
158 |
+
if ($filter = $this->getValueFilter()) {
|
159 |
+
$value = $filter->filter($value);
|
160 |
+
}
|
161 |
+
return $this->_escape($value);
|
162 |
+
}
|
163 |
+
|
164 |
+
public function setRenderer(Varien_Data_Form_Element_Renderer_Interface $renderer)
|
165 |
+
{
|
166 |
+
$this->_renderer = $renderer;
|
167 |
+
return $this;
|
168 |
+
}
|
169 |
+
|
170 |
+
public function getRenderer()
|
171 |
+
{
|
172 |
+
return $this->_renderer;
|
173 |
+
}
|
174 |
+
|
175 |
+
public function getElementHtml()
|
176 |
+
{
|
177 |
+
$html = '<input id="'.$this->getHtmlId().'" name="'.$this->getName()
|
178 |
+
.'" value="'.$this->getEscapedValue().'" '.$this->serialize($this->getHtmlAttributes()).'/>'."\n";
|
179 |
+
$html.= $this->getAfterElementHtml();
|
180 |
+
return $html;
|
181 |
+
}
|
182 |
+
|
183 |
+
/***********************************************************************
|
184 |
+
* BEGIN Customweb Dependency Module specific changes
|
185 |
+
***********************************************************************/
|
186 |
+
public function getAfterElementHtml()
|
187 |
+
{
|
188 |
+
$name = $this->getName();
|
189 |
+
$id = $this->getId();
|
190 |
+
$htmlId = $this->getHtmlId();
|
191 |
+
$params = Mage::app()->getRequest()->getParams();
|
192 |
+
|
193 |
+
$suffix = Mage::helper('dependency/element')->getElementSuffix($name, $htmlId, $id,$params);
|
194 |
+
|
195 |
+
return $this->getData('after_element_html') . $suffix;
|
196 |
+
}
|
197 |
+
/***********************************************************************
|
198 |
+
* END Customweb Dependency Module specific changes
|
199 |
+
***********************************************************************/
|
200 |
+
|
201 |
+
/**
|
202 |
+
* Render HTML for element's label
|
203 |
+
*
|
204 |
+
* @param string $idSuffix
|
205 |
+
* @return string
|
206 |
+
*/
|
207 |
+
public function getLabelHtml($idSuffix = '')
|
208 |
+
{
|
209 |
+
if (!is_null($this->getLabel())) {
|
210 |
+
$html = '<label for="'.$this->getHtmlId() . $idSuffix . '">' . $this->_escape($this->getLabel())
|
211 |
+
. ( $this->getRequired() ? ' <span class="required">*</span>' : '' ) . '</label>' . "\n";
|
212 |
+
} else {
|
213 |
+
$html = '';
|
214 |
+
}
|
215 |
+
return $html;
|
216 |
+
}
|
217 |
+
|
218 |
+
public function getDefaultHtml()
|
219 |
+
{
|
220 |
+
$html = $this->getData('default_html');
|
221 |
+
if (is_null($html)) {
|
222 |
+
$html = ( $this->getNoSpan() === true ) ? '' : '<span class="field-row">'."\n";
|
223 |
+
$html.= $this->getLabelHtml();
|
224 |
+
$html.= $this->getElementHtml();
|
225 |
+
$html.= ( $this->getNoSpan() === true ) ? '' : '</span>'."\n";
|
226 |
+
}
|
227 |
+
return $html;
|
228 |
+
}
|
229 |
+
|
230 |
+
public function getHtml()
|
231 |
+
{
|
232 |
+
if ($this->getRequired()) {
|
233 |
+
$this->addClass('required-entry');
|
234 |
+
}
|
235 |
+
if ($this->_renderer) {
|
236 |
+
$html = $this->_renderer->render($this);
|
237 |
+
}
|
238 |
+
else {
|
239 |
+
$html = $this->getDefaultHtml();
|
240 |
+
}
|
241 |
+
return $html;
|
242 |
+
}
|
243 |
+
|
244 |
+
public function toHtml()
|
245 |
+
{
|
246 |
+
return $this->getHtml();
|
247 |
+
}
|
248 |
+
|
249 |
+
public function serialize($attributes = array(), $valueSeparator='=', $fieldSeparator=' ', $quote='"')
|
250 |
+
{
|
251 |
+
if (in_array('disabled', $attributes) && !empty($this->_data['disabled'])) {
|
252 |
+
$this->_data['disabled'] = 'disabled';
|
253 |
+
}
|
254 |
+
else {
|
255 |
+
unset($this->_data['disabled']);
|
256 |
+
}
|
257 |
+
if (in_array('checked', $attributes) && !empty($this->_data['checked'])) {
|
258 |
+
$this->_data['checked'] = 'checked';
|
259 |
+
}
|
260 |
+
else {
|
261 |
+
unset($this->_data['checked']);
|
262 |
+
}
|
263 |
+
return parent::serialize($attributes, $valueSeparator, $fieldSeparator, $quote);
|
264 |
+
}
|
265 |
+
|
266 |
+
public function getReadonly()
|
267 |
+
{
|
268 |
+
if ($this->hasData('readonly_disabled')) {
|
269 |
+
return $this->_getData('readonly_disabled');
|
270 |
+
}
|
271 |
+
|
272 |
+
return $this->_getData('readonly');
|
273 |
+
}
|
274 |
+
|
275 |
+
public function getHtmlContainerId()
|
276 |
+
{
|
277 |
+
if ($this->hasData('container_id')) {
|
278 |
+
return $this->getData('container_id');
|
279 |
+
} elseif ($idPrefix = $this->getForm()->getFieldContainerIdPrefix()) {
|
280 |
+
return $idPrefix . $this->getId();
|
281 |
+
}
|
282 |
+
return '';
|
283 |
+
}
|
284 |
+
|
285 |
+
/**
|
286 |
+
* Add specified values to element values
|
287 |
+
*
|
288 |
+
* @param string|int|array $values
|
289 |
+
* @param bool $overwrite
|
290 |
+
* @return Varien_Data_Form_Element_Abstract
|
291 |
+
*/
|
292 |
+
public function addElementValues($values, $overwrite = false)
|
293 |
+
{
|
294 |
+
if (empty($values) || (is_string($values) && trim($values) == '')) {
|
295 |
+
return $this;
|
296 |
+
}
|
297 |
+
if (!is_array($values)) {
|
298 |
+
$values = Mage::helper('core')->escapeHtml(trim($values));
|
299 |
+
$values = array($values => $values);
|
300 |
+
}
|
301 |
+
$elementValues = $this->getValues();
|
302 |
+
if (!empty($elementValues)) {
|
303 |
+
foreach ($values as $key => $value) {
|
304 |
+
if ((isset($elementValues[$key]) && $overwrite) || !isset($elementValues[$key])) {
|
305 |
+
$elementValues[$key] = Mage::helper('core')->escapeHtml($value);
|
306 |
+
}
|
307 |
+
}
|
308 |
+
$values = $elementValues;
|
309 |
+
}
|
310 |
+
$this->setValues($values);
|
311 |
+
|
312 |
+
return $this;
|
313 |
+
}
|
314 |
+
}
|
app/design/adminhtml/default/default/layout/dependency.xml
ADDED
@@ -0,0 +1,11 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?xml version="1.0"?>
|
2 |
+
<layout version="0.1.0">
|
3 |
+
<default>
|
4 |
+
|
5 |
+
<reference name="head">
|
6 |
+
<action method="addCss"><stylesheet>css/dependency.css</stylesheet></action>
|
7 |
+
<action method="addJs"><script>customweb/dependency.js</script></action>
|
8 |
+
</reference>
|
9 |
+
|
10 |
+
</default>
|
11 |
+
</layout>
|
app/etc/modules/Customweb_Dependency.xml
ADDED
@@ -0,0 +1,11 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<config>
|
2 |
+
<modules>
|
3 |
+
<Customweb_Dependency>
|
4 |
+
<active>true</active>
|
5 |
+
<codePool>local</codePool>
|
6 |
+
<depends>
|
7 |
+
<Mage_Adminhtml />
|
8 |
+
</depends>
|
9 |
+
</Customweb_Dependency>
|
10 |
+
</modules>
|
11 |
+
</config>
|
js/customweb/dependency.js
ADDED
@@ -0,0 +1,116 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
function updateDependencySelect(sel, elementId, greyOutOnly, loopError, checkError){
|
2 |
+
if(sel.options[sel.selectedIndex].className == "dependency-loop"){
|
3 |
+
alert(loopError);
|
4 |
+
sel.selectedIndex = 0;
|
5 |
+
}
|
6 |
+
else if(sel.options[sel.selectedIndex].className == "dependency-check-failed")
|
7 |
+
{
|
8 |
+
alert(checkError);
|
9 |
+
sel.selectedIndex = 0;
|
10 |
+
}
|
11 |
+
greyOut(sel, elementId, greyOutOnly);
|
12 |
+
}
|
13 |
+
|
14 |
+
function greyOut(sel, elementId, greyOutOnly){
|
15 |
+
var value = sel.options[sel.selectedIndex].value;
|
16 |
+
var hiddenFields = $$('input[type="hidden"]');
|
17 |
+
var toExclude = hiddenFields.concat(sel);
|
18 |
+
if(value != 0 && value != 'default')
|
19 |
+
{
|
20 |
+
originalToggleValueElements($(elementId + "_default"),sel.parentNode.parentNode.parentNode.parentNode,toExclude,true);
|
21 |
+
originalToggleValueElements($(elementId + "_inherit"),sel.parentNode.parentNode.parentNode.parentNode,toExclude,true);
|
22 |
+
|
23 |
+
}
|
24 |
+
else if(!greyOutOnly)
|
25 |
+
{
|
26 |
+
originalToggleValueElements($(elementId + "_default"),sel.parentNode.parentNode.parentNode.parentNode,toExclude,false);
|
27 |
+
originalToggleValueElements($(elementId + "_inherit"),sel.parentNode.parentNode.parentNode.parentNode,toExclude,false);
|
28 |
+
}
|
29 |
+
}
|
30 |
+
|
31 |
+
function greyOutAttributes(){
|
32 |
+
if(typeof originalToggleValueElements == 'undefined')
|
33 |
+
{
|
34 |
+
originalToggleValueElements = toggleValueElements;
|
35 |
+
toggleValueElements = toggleValueElements.wrap(function(callOriginal, checkbox, container, excludedElements, checked){
|
36 |
+
|
37 |
+
// Exclude all hidden fields
|
38 |
+
var hiddenFields = $$('input[type="hidden"]');
|
39 |
+
if(typeof excludedElements != 'undefined')
|
40 |
+
{
|
41 |
+
hiddenFields = hiddenFields.concat(excludedElements);
|
42 |
+
}
|
43 |
+
var name = checkbox.readAttribute("name");
|
44 |
+
var m = name.match(/use_default/i);
|
45 |
+
if(m == null){
|
46 |
+
hiddenFields = hiddenFields.concat($$('select[class="dependency-selector"]'));
|
47 |
+
}
|
48 |
+
|
49 |
+
// WORKAROUND
|
50 |
+
// Magento standard behavior: Some fields (up to now only checkboxes)
|
51 |
+
// do not get disabled when checking 'use_default'. This behavior is unfortunately
|
52 |
+
// necessary for certain required fields. The following list therefore excludes those
|
53 |
+
// elements from beeing disabled.
|
54 |
+
var doNotDisable = ["use_config_group_5available_sort_by",
|
55 |
+
"use_config_group_5default_sort_by"];
|
56 |
+
|
57 |
+
for(var i=0; i < doNotDisable.length; i++){
|
58 |
+
var elem = $(doNotDisable[i]);
|
59 |
+
if(elem != null){
|
60 |
+
hiddenFields = hiddenFields.concat([elem])
|
61 |
+
}
|
62 |
+
}
|
63 |
+
|
64 |
+
callOriginal(checkbox, container, hiddenFields, checked);
|
65 |
+
|
66 |
+
updatedBasedOnSelects('select[class="dependency-selector"]');
|
67 |
+
updatedBasedOnSelects('select[class="config-dependency-selector"]');
|
68 |
+
|
69 |
+
|
70 |
+
});
|
71 |
+
}
|
72 |
+
|
73 |
+
$$('input[type="checkbox"]').each(function(element) {
|
74 |
+
var name = element.readAttribute('name');
|
75 |
+
if(name != null && (name.match(/use_default\[\]/i) || name.match(/\[inherit\]/i)))
|
76 |
+
{
|
77 |
+
toggleValueElements(element, element.parentNode.parentNode,$$('input[type="checkbox"][name="use_default[]"]'));
|
78 |
+
}
|
79 |
+
});
|
80 |
+
|
81 |
+
// This is a hack for the Chromium browser
|
82 |
+
var tab = $('category_info_tabs_group_4');
|
83 |
+
if(tab != null){
|
84 |
+
setTimeout(function(){eventFire(tab,'click');},200);
|
85 |
+
|
86 |
+
}
|
87 |
+
}
|
88 |
+
|
89 |
+
Event.observe(window, 'load', greyOutAttributes);
|
90 |
+
|
91 |
+
|
92 |
+
function updatedBasedOnSelects(itemSelector){
|
93 |
+
$$(itemSelector).each(function(item){
|
94 |
+
var name = item.readAttribute("name");
|
95 |
+
var dependencyFor = item.readAttribute("dependencyfor");
|
96 |
+
if(name != null)
|
97 |
+
{
|
98 |
+
var m = name.match(/\[(.*)source\]/i);
|
99 |
+
if(m != null)
|
100 |
+
{
|
101 |
+
greyOut(item,dependencyFor,true);
|
102 |
+
}
|
103 |
+
}
|
104 |
+
});
|
105 |
+
}
|
106 |
+
|
107 |
+
// Taken from stackoverflow
|
108 |
+
function eventFire(el, etype){
|
109 |
+
if (el.fireEvent) {
|
110 |
+
(el.fireEvent('on' + etype));
|
111 |
+
} else {
|
112 |
+
var evObj = document.createEvent('Events');
|
113 |
+
evObj.initEvent(etype, true, false);
|
114 |
+
el.dispatchEvent(evObj);
|
115 |
+
}
|
116 |
+
}
|
package.xml
ADDED
@@ -0,0 +1,27 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?xml version="1.0"?>
|
2 |
+
<package>
|
3 |
+
<name>store_dependency</name>
|
4 |
+
<version>1.0.0</version>
|
5 |
+
<stability>stable</stability>
|
6 |
+
<license uri="http://www.customweb.com/en/software-license-agreement">Customweb Software Licence</license>
|
7 |
+
<channel>community</channel>
|
8 |
+
<extends/>
|
9 |
+
<summary>The Extension allows you to synchronize and share content as well as settings among your different magento stores. </summary>
|
10 |
+
<description>The extension allows you to sync content between different Magento stores. A typical use case for this would be, if you are having country specific shops with more or less the same content.
|
11 |
+
<b>Products:</b>
|
12 |
+

|
13 |
+
Choose for each attribute of your product where to synchronize it from. This allows you to manage your content only in your default or any other store. The extension will then, as soon as the article will be saved, automatically synchronize the content from the source you choose.
|
14 |
+

|
15 |
+
<b>Settings:</b>
|
16 |
+

|
17 |
+
The extension enables you not only to synchronize content but also all the settings. Once you set-up your specific store the extensions enables you to choose where to synchronize the settings from.
|
18 |
+

|
19 |
+
This is the free version which only contains the settings part. The full version costs 180 $ and is available in our store: http://www.customweb.com/shop/en/magento-store-configuration-sync.html</description>
|
20 |
+
<notes>Initial release.</notes>
|
21 |
+
<authors><author><name>Severin Klingler</name><user>customweb</user><email>info@customweb.com</email></author></authors>
|
22 |
+
<date>2013-04-16</date>
|
23 |
+
<time>14:57:48</time>
|
24 |
+
<contents><target name="magelocal"><dir name="Customweb"><dir name="Dependency"><dir name="Helper"><file name="Config.php" hash="03b8c899185401944e755949d9bd57f7"/><file name="Data.php" hash="887cd057dbbebb2969cfa66ee39be28c"/><file name="Element.php" hash="ce43a22f8edc7b6e215e7542c4c05b1b"/></dir><dir name="Model"><file name="Category.php" hash="7c5545d94dcb6034f2d669b8c550f8d6"/><file name="Config.php" hash="329eafba749e1e66b157261fbf97bc55"/><file name="ConfigObserver.php" hash="377ab826ad78ecb61070436de8d86269"/><dir name="Mysql4"><dir name="Category"><file name="Collection.php" hash="81a1f7780bd8ab3fa47ac1b94e3008c7"/></dir><file name="Category.php" hash="df7c1c607fd5c9eb37e23971c55c9126"/><dir name="Config"><file name="Collection.php" hash="b774dbf894a742b74dbc5d958b3957ff"/></dir><file name="Config.php" hash="8d07a47ac114f70193ff508fac945d92"/><dir name="Product"><file name="Collection.php" hash="df9a5335d65258b78134c44d8c6e5877"/></dir><file name="Product.php" hash="197bfa001b8186c251493a73f61e3895"/></dir><file name="Product.php" hash="4a6ccbae9eb7c9e04d820b43b717cb34"/><dir name="Resource"><file name="Setup.php" hash="f3b9ae7227f7385c6d4199c3ad65f0c3"/></dir></dir><dir name="controllers"><file name="TestController.php" hash="a09d91f042b0aee47171f2b7633cacbd"/></dir><dir name="etc"><file name="config.xml" hash="d6d8034342ea82557cc9c4a62acf7388"/></dir><dir name="sql"><dir name="dependency_setup"><file name="mysql4-install-1.0.0.php" hash="f1ce4898842296e719e5edb4dd81ce0e"/></dir></dir></dir></dir><dir name="Mage"><dir name="Core"><dir name="Model"><file name="Config.php" hash="d6c777bac108cf193b5896ad59862b52"/></dir></dir></dir><dir name="Varien"><dir name="Data"><dir name="Form"><dir name="Element"><file name="Abstract.php" hash="8d417720fb040f64e5d3ec3852a0df97"/></dir></dir></dir></dir></target><target name="magedesign"><dir name="adminhtml"><dir name="default"><dir name="default"><dir name="layout"><file name="dependency.xml" hash="26b3aed75dbc791982a128fe7a3b43e9"/></dir></dir></dir></dir></target><target name="mageetc"><dir name="modules"><file name="Customweb_Dependency.xml" hash="6cbf8016b0e3b1e8ae9895a702d0f8fc"/></dir></target><target name="mage"><dir name="js"><dir name="customweb"><file name="dependency.js" hash="37912efa07da4691e52ed1b75bba43a1"/></dir></dir></target><target name="mageskin"><dir name="adminhtml"><dir name="base"><dir name="default"><dir name="css"><file name="dependency.css" hash="d0b575ab0e3115a04872f1663e8e9a2e"/></dir></dir></dir></dir></target></contents>
|
25 |
+
<compatible/>
|
26 |
+
<dependencies><required><php><min>5.1.0</min><max>6.0.0</max></php></required></dependencies>
|
27 |
+
</package>
|
skin/adminhtml/base/default/css/dependency.css
ADDED
@@ -0,0 +1,76 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/**
|
2 |
+
* @category Customweb
|
3 |
+
* @package Customweb
|
4 |
+
* @copyright Copyright (c) http://www.customweb.com
|
5 |
+
*/
|
6 |
+
.dependency-select {
|
7 |
+
position: relative;
|
8 |
+
width: 100%;
|
9 |
+
}
|
10 |
+
|
11 |
+
.dependency-select select {
|
12 |
+
position: absolute;
|
13 |
+
right: 0px;
|
14 |
+
margin-right: -210px;
|
15 |
+
top: 20px;
|
16 |
+
}
|
17 |
+
|
18 |
+
/**
|
19 |
+
.dependency-select .config-dependency-selector {
|
20 |
+
position: absolute;
|
21 |
+
right: 0px;
|
22 |
+
margin-right: -290px;
|
23 |
+
top: 20px;
|
24 |
+
}
|
25 |
+
*/
|
26 |
+
|
27 |
+
.dependency-select .config-dependency-selector.disabled {
|
28 |
+
display: none;
|
29 |
+
width: 200px;
|
30 |
+
}
|
31 |
+
|
32 |
+
.dependency-box {
|
33 |
+
float:right;
|
34 |
+
min-height: 35px;
|
35 |
+
}
|
36 |
+
|
37 |
+
.fieldset-wide .form-list td.value .dependency-select select.disabled {
|
38 |
+
display: none;
|
39 |
+
width: 200px;
|
40 |
+
}
|
41 |
+
|
42 |
+
.fieldset-wide .form-list td.value .dependency-select select {
|
43 |
+
width: 200px;
|
44 |
+
float: right;
|
45 |
+
}
|
46 |
+
.fieldset-wide .form-list td.value select {
|
47 |
+
float: left;
|
48 |
+
}
|
49 |
+
|
50 |
+
.entry-edit .form-list td.value .dependency-select select.disabled {
|
51 |
+
display: none;
|
52 |
+
width: 200px;
|
53 |
+
}
|
54 |
+
|
55 |
+
.entry-edit .form-list td.value .dependency-select select {
|
56 |
+
width: 200px;
|
57 |
+
float: right;
|
58 |
+
}
|
59 |
+
|
60 |
+
/* Do not show the dependency selector when within a label */
|
61 |
+
.entry-edit td label .dependency-select select {
|
62 |
+
display: none;
|
63 |
+
width: 200px;
|
64 |
+
}
|
65 |
+
|
66 |
+
.entry-edit .form-list td.value select {
|
67 |
+
float: left;
|
68 |
+
}
|
69 |
+
|
70 |
+
.dependency-loop {
|
71 |
+
color : #999999;
|
72 |
+
}
|
73 |
+
|
74 |
+
.dependency-check-failed {
|
75 |
+
color : #999999;
|
76 |
+
}
|