Development

/branches/1.0/lib/config/sfConfigCache.class.php

You must first sign up to be able to contribute.

root/branches/1.0/lib/config/sfConfigCache.class.php

Revision 10059, 9.9 kB (checked in by fabien, 6 years ago)

fixed opendir closed by fclose instead of closedir (closes #3880)

  • Property svn:mime-type set to text/x-php
  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Rev Date
Line 
1 <?php
2
3 /*
4  * This file is part of the symfony package.
5  * (c) 2004-2006 Fabien Potencier <fabien.potencier@symfony-project.com>
6  * (c) 2004-2006 Sean Kerr <sean@code-box.org>
7  *
8  * For the full copyright and license information, please view the LICENSE
9  * file that was distributed with this source code.
10  */
11
12 /**
13  * sfConfigCache allows you to customize the format of a configuration file to
14  * make it easy-to-use, yet still provide a PHP formatted result for direct
15  * inclusion into your modules.
16  *
17  * @package    symfony
18  * @subpackage config
19  * @author     Fabien Potencier <fabien.potencier@symfony-project.com>
20  * @author     Sean Kerr <sean@code-box.org>
21  * @version    SVN: $Id$
22  */
23 class sfConfigCache
24 {
25   protected
26     $handlers = array();
27
28   protected static
29     $instance = null;
30
31   /**
32    * Retrieves the singleton instance of this class.
33    *
34    * @return sfConfigCache A sfConfigCache instance
35    */
36   public static function getInstance()
37   {
38     if (!self::$instance)
39     {
40       self::$instance = new sfConfigCache();
41     }
42
43     return self::$instance;
44   }
45
46   /**
47    * Loads a configuration handler.
48    *
49    * @param string The handler to use when parsing a configuration file
50    * @param array  An array of absolute filesystem paths to configuration files
51    * @param string An absolute filesystem path to the cache file that will be written
52    *
53    * @throws <b>sfConfigurationException</b> If a requested configuration file does not have an associated configuration handler
54    */
55   protected function callHandler($handler, $configs, $cache)
56   {
57     if (count($this->handlers) == 0)
58     {
59       // we need to load the handlers first
60       $this->loadConfigHandlers();
61     }
62
63     // handler to call for this configuration file
64     $handlerToCall = null;
65
66     $handler = str_replace(DIRECTORY_SEPARATOR, '/', $handler);
67
68     // grab the base name of the handler
69     $basename = basename($handler);
70     if (isset($this->handlers[$handler]))
71     {
72       // we have a handler associated with the full configuration path
73       $handlerToCall = $this->handlers[$handler];
74     }
75     else if (isset($this->handlers[$basename]))
76     {
77       // we have a handler associated with the configuration base name
78       $handlerToCall = $this->handlers[$basename];
79     }
80     else
81     {
82       // let's see if we have any wildcard handlers registered that match
83       // this basename
84       foreach ($this->handlers as $key => $handlerInstance)
85       {
86         // replace wildcard chars in the configuration
87         $pattern = strtr($key, array('.' => '\.', '*' => '.*?'));
88
89         // create pattern from config
90         if (preg_match('#'.$pattern.'#', $handler))
91         {
92           // we found a match!
93           $handlerToCall = $this->handlers[$key];
94
95           break;
96         }
97       }
98     }
99
100     if ($handlerToCall)
101     {
102       // call the handler and retrieve the cache data
103       $data = $handlerToCall->execute($configs);
104
105       $this->writeCacheFile($handler, $cache, $data);
106     }
107     else
108     {
109       // we do not have a registered handler for this file
110       $error = sprintf('Configuration file "%s" does not have a registered handler', implode(', ', $configs));
111
112       throw new sfConfigurationException($error);
113     }
114   }
115
116   /**
117    * Checks to see if a configuration file has been modified and if so
118    * recompile the cache file associated with it.
119    *
120    * The recompilation only occurs in a non debug environment.
121    *
122    * If the configuration file path is relative, symfony will look in directories
123    * defined in the sfLoader::getConfigPaths() method.
124    *
125    * @param string A filesystem path to a configuration file
126    *
127    * @return string An absolute filesystem path to the cache filename associated with this specified configuration file
128    *
129    * @throws <b>sfConfigurationException</b> If a requested configuration file does not exist
130    *
131    * @see sfLoader::getConfigPaths()
132    */
133   public function checkConfig($configPath, $optional = false)
134   {
135     static $process_cache_cleared = false;
136
137     if (sfConfig::get('sf_debug') && sfConfig::get('sf_logging_enabled'))
138     {
139       $timer = sfTimerManager::getTimer('Configuration');
140     }
141
142     // the cache filename we'll be using
143     $cache = $this->getCacheName($configPath);
144
145     if (sfConfig::get('sf_in_bootstrap') && is_readable($cache))
146     {
147       if (sfConfig::get('sf_debug') && sfConfig::get('sf_logging_enabled'))
148       {
149         $timer->addTime();
150       }
151
152       return $cache;
153     }
154
155     if (!sfToolkit::isPathAbsolute($configPath))
156     {
157       $files = sfLoader::getConfigPaths($configPath);
158     }
159     else
160     {
161       $files = is_readable($configPath) ? array($configPath) : array();
162     }
163
164     if (!isset($files[0]))
165     {
166       if ($optional)
167       {
168         return null;
169       }
170
171       // configuration does not exist
172       $error = sprintf('Configuration "%s" does not exist or is unreadable', $configPath);
173
174       throw new sfConfigurationException($error);
175     }
176
177     // find the more recent configuration file last modification time
178     $mtime = 0;
179     foreach ($files as $file)
180     {
181       if (filemtime($file) > $mtime)
182       {
183         $mtime = filemtime($file);
184       }
185     }
186
187     if (!is_readable($cache) || $mtime > filemtime($cache))
188     {
189       // configuration has changed so we need to reparse it
190       $this->callHandler($configPath, $files, $cache);
191
192       // clear process cache
193       if ('config/config_handlers.yml' != $configPath && sfConfig::get('sf_use_process_cache') && !$process_cache_cleared)
194       {
195         sfProcessCache::clear();
196         $process_cache_cleared = true;
197       }
198     }
199
200     if (sfConfig::get('sf_debug') && sfConfig::get('sf_logging_enabled'))
201     {
202       $timer->addTime();
203     }
204
205     return $cache;
206   }
207
208   /**
209    * Clears all configuration cache files.
210    */
211   public function clear()
212   {
213     sfToolkit::clearDirectory(sfConfig::get('sf_config_cache_dir'));
214   }
215
216   /**
217    * Converts a normal filename into a cache filename.
218    *
219    * @param string A normal filename
220    *
221    * @return string An absolute filesystem path to a cache filename
222    */
223   public function getCacheName($config)
224   {
225     if (strlen($config) > 3 && ctype_alpha($config[0]) && $config[1] == ':' && ($config[2] == '\\' || $config[2] == '/'))
226     {
227       // file is a windows absolute path, strip off the drive letter
228       $config = substr($config, 3);
229     }
230
231     // replace unfriendly filename characters with an underscore
232     $config  = str_replace(array('\\', '/', ' '), '_', $config);
233     $config .= '.php';
234
235     return sfConfig::get('sf_config_cache_dir').'/'.$config;
236   }
237
238   /**
239    * Imports a configuration file.
240    *
241    * @param string A filesystem path to a configuration file
242    * @param bool   Only allow this configuration file to be included once per request?
243    *
244    * @see checkConfig()
245    */
246   public function import($config, $once = true, $optional = false)
247   {
248     $cache = $this->checkConfig($config, $optional);
249
250     if ($optional && !$cache)
251     {
252       return;
253     }
254
255     // include cache file
256     if ($once)
257     {
258       include_once($cache);
259     }
260     else
261     {
262       include($cache);
263     }
264   }
265
266   /**
267    * Loads all configuration application and module level handlers.
268    *
269    * @throws <b>sfConfigurationException</b> If a configuration related error occurs.
270    */
271   protected function loadConfigHandlers()
272   {
273     // manually create our config_handlers.yml handler
274     $this->handlers['config_handlers.yml'] = new sfRootConfigHandler();
275     $this->handlers['config_handlers.yml']->initialize();
276
277     // application configuration handlers
278
279     require_once($this->checkConfig(sfConfig::get('sf_app_config_dir_name').'/config_handlers.yml'));
280
281     // module level configuration handlers
282
283     // make sure our modules directory exists
284     if (is_readable($sf_app_module_dir = sfConfig::get('sf_app_module_dir')))
285     {
286       // ignore names
287       $ignore = array('.', '..', 'CVS', '.svn');
288
289       // create a file pointer to the module dir
290       $fp = opendir($sf_app_module_dir);
291
292       // loop through the directory and grab the modules
293       while (($directory = readdir($fp)) !== false)
294       {
295         if (!in_array($directory, $ignore))
296         {
297           $configPath = $sf_app_module_dir.'/'.$directory.'/'.sfConfig::get('sf_app_module_config_dir_name').'/config_handlers.yml';
298
299           if (is_readable($configPath))
300           {
301             // initialize the root configuration handler with this module name
302             $params = array('module_level' => true, 'module_name' => $directory);
303
304             $this->handlers['config_handlers.yml']->initialize($params);
305
306             // replace module dir path with a special keyword that
307             // checkConfig knows how to use
308             $configPath = sfConfig::get('sf_app_module_dir_name').'/'.$directory.'/'.sfConfig::get('sf_app_module_config_dir_name').'/config_handlers.yml';
309
310             require_once($this->checkConfig($configPath));
311           }
312         }
313       }
314
315       // close file pointer
316       closedir($fp);
317     }
318     else
319     {
320       // module directory doesn't exist or isn't readable
321       $error = sprintf('Module directory "%s" does not exist or is not readable',
322                        sfConfig::get('sf_app_module_dir'));
323       throw new sfConfigurationException($error);
324     }
325   }
326
327   /**
328    * Writes a cache file.
329    *
330    * @param string An absolute filesystem path to a configuration file
331    * @param string An absolute filesystem path to the cache file that will be written
332    * @param string Data to be written to the cache file
333    *
334    * @throws sfCacheException If the cache file cannot be written
335    */
336   protected function writeCacheFile($config, $cache, &$data)
337   {
338     $fileCache = new sfFileCache(dirname($cache));
339     $fileCache->initialize(array('lifeTime' => 86400 * 365 * 10, 'automaticCleaningFactor' => 0));
340     $fileCache->setWriteControl(true);
341     $fileCache->setSuffix('');
342
343     if (!$fileCache->set(basename($cache), '', $data))
344     {
345       $fileCache->remove(basename($cache), '');
346
347       throw new sfConfigurationException(sprintf('Unable to write config cache for "%s".', $config));
348     }
349   }
350 }
351
Note: See TracBrowser for help on using the browser.