Development

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

You must first sign up to be able to contribute.

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

Revision 17858, 11.0 kB (checked in by FabianLange, 5 years ago)

[1.1, 1.2, 1.3] fixed some codeing standards (fixes #6376 - patch from gimler)

  • 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     $configuration = null,
27     $handlers      = array(),
28     $userHandlers  = array();
29
30   /**
31    * Constructor
32    *
33    * @param sfApplicationConfiguration $configuration A sfApplicationConfiguration instance
34    */
35   public function __construct(sfApplicationConfiguration $configuration)
36   {
37     $this->configuration = $configuration;
38   }
39
40   /**
41    * Loads a configuration handler.
42    *
43    * @param string $handler The handler to use when parsing a configuration file
44    * @param array  $configs An array of absolute filesystem paths to configuration files
45    * @param string $cache   An absolute filesystem path to the cache file that will be written
46    *
47    * @throws <b>sfConfigurationException</b> If a requested configuration file does not have an associated configuration handler
48    */
49   protected function callHandler($handler, $configs, $cache)
50   {
51     if (count($this->handlers) == 0)
52     {
53       // we need to load the handlers first
54       $this->loadConfigHandlers();
55     }
56
57     if (count($this->userHandlers) != 0)
58     {
59       // we load user defined handlers
60       $this->mergeUserConfigHandlers();
61     }
62
63     // handler key to call for this configuration file
64     $handlerKey = 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       $handlerKey = $handler;
74     }
75     else if (isset($this->handlers[$basename]))
76     {
77       // we have a handler associated with the configuration base name
78       $handlerKey = $basename;
79     }
80     else
81     {
82       // let's see if we have any wildcard handlers registered that match this basename
83       foreach (array_keys($this->handlers) as $key)
84       {
85         // replace wildcard chars in the configuration
86         $pattern = strtr($key, array('.' => '\.', '*' => '.*?'));
87
88         // create pattern from config
89         if (preg_match('#'.$pattern.'$#', $handler))
90         {
91           $handlerKey = $key;
92
93           break;
94         }
95       }
96     }
97
98     if (!$handlerKey)
99     {
100       // we do not have a registered handler for this file
101       throw new sfConfigurationException(sprintf('Configuration file "%s" does not have a registered handler.', implode(', ', $configs)));
102     }
103
104     // call the handler and retrieve the cache data
105     $data = $this->getHandler($handlerKey)->execute($configs);
106
107     $this->writeCacheFile($handler, $cache, $data);
108   }
109
110   /**
111    * Returns the config handler configured for the given name
112    *
113    * @param string $name The config handler name
114    *
115    * @return sfConfigHandler A sfConfigHandler instance
116    */
117   protected function getHandler($name)
118   {
119     if (is_array($this->handlers[$name]))
120     {
121       $class = $this->handlers[$name][0];
122       $this->handlers[$name] = new $class($this->handlers[$name][1]);
123     }
124
125     return $this->handlers[$name];
126   }
127
128   /**
129    * Checks to see if a configuration file has been modified and if so
130    * recompile the cache file associated with it.
131    *
132    * The recompilation only occurs in a non debug environment.
133    *
134    * If the configuration file path is relative, symfony will look in directories
135    * defined in the sfConfiguration::getConfigPaths() method.
136    *
137    * @param string  $configPath A filesystem path to a configuration file
138    * @param boolean $optional   If true, config path does not need to exist
139    *
140    * @return string An absolute filesystem path to the cache filename associated with this specified configuration file
141    *
142    * @throws <b>sfConfigurationException</b> If a requested configuration file does not exist
143    *
144    * @see sfConfiguration::getConfigPaths()
145    */
146   public function checkConfig($configPath, $optional = false)
147   {
148     if (sfConfig::get('sf_debug') && sfConfig::get('sf_logging_enabled'))
149     {
150       $timer = sfTimerManager::getTimer('Configuration');
151     }
152
153     // the cache filename we'll be using
154     $cache = $this->getCacheName($configPath);
155
156     if (!sfConfig::get('sf_debug') && !sfConfig::get('sf_test') && is_readable($cache))
157     {
158       return $cache;
159     }
160
161     if (!sfToolkit::isPathAbsolute($configPath))
162     {
163       $files = $this->configuration->getConfigPaths($configPath);
164     }
165     else
166     {
167       $files = is_readable($configPath) ? array($configPath) : array();
168     }
169
170     if (!isset($files[0]))
171     {
172       if ($optional)
173       {
174         return null;
175       }
176
177       // configuration does not exist
178       throw new sfConfigurationException(sprintf('Configuration "%s" does not exist or is unreadable.', $configPath));
179     }
180
181     // find the more recent configuration file last modification time
182     $mtime = 0;
183     foreach ($files as $file)
184     {
185       if (filemtime($file) > $mtime)
186       {
187         $mtime = filemtime($file);
188       }
189     }
190
191     if (!is_readable($cache) || $mtime > filemtime($cache))
192     {
193       // configuration has changed so we need to reparse it
194       $this->callHandler($configPath, $files, $cache);
195     }
196
197     if (sfConfig::get('sf_debug') && sfConfig::get('sf_logging_enabled'))
198     {
199       $timer->addTime();
200     }
201
202     return $cache;
203   }
204
205   /**
206    * Clears all configuration cache files.
207    */
208   public function clear()
209   {
210     sfToolkit::clearDirectory(sfConfig::get('sf_config_cache_dir'));
211   }
212
213   /**
214    * Converts a normal filename into a cache filename.
215    *
216    * @param string $config A normal filename
217    *
218    * @return string An absolute filesystem path to a cache filename
219    */
220   public function getCacheName($config)
221   {
222     if (strlen($config) > 3 && ctype_alpha($config[0]) && $config[1] == ':' && ($config[2] == '\\' || $config[2] == '/'))
223     {
224       // file is a windows absolute path, strip off the drive letter
225       $config = substr($config, 3);
226     }
227
228     // replace unfriendly filename characters with an underscore
229     $config  = str_replace(array('\\', '/', ' '), '_', $config);
230     $config .= '.php';
231
232     return sfConfig::get('sf_config_cache_dir').'/'.$config;
233   }
234
235   /**
236    * Imports a configuration file.
237    *
238    * @param string $config   A filesystem path to a configuration file
239    * @param bool   $once     Only allow this configuration file to be included once per request?
240    * @param bool   $optional Only include if true
241    *
242    * @see checkConfig()
243    */
244   public function import($config, $once = true, $optional = false)
245   {
246     $cache = $this->checkConfig($config, $optional);
247
248     if ($optional && !$cache)
249     {
250       return;
251     }
252
253     // include cache file
254     if ($once)
255     {
256       include_once($cache);
257     }
258     else
259     {
260       include($cache);
261     }
262   }
263
264   /**
265    * Loads all configuration application and module level handlers.
266    *
267    * @throws <b>sfConfigurationException</b> If a configuration related error occurs.
268    */
269   protected function loadConfigHandlers()
270   {
271     // manually create our config_handlers.yml handler
272     $this->handlers['config_handlers.yml'] = new sfRootConfigHandler();
273
274     // application configuration handlers
275
276     require $this->checkConfig('config/config_handlers.yml');
277
278     // module level configuration handlers
279
280     // checks modules directory exists
281     if (!is_readable($sf_app_modules_dir = sfConfig::get('sf_app_modules_dir')))
282     {
283       return;
284     }
285
286     // ignore names
287     $ignore = array('.', '..', 'CVS', '.svn');
288
289     // create a file pointer to the module dir
290     $fp = opendir($sf_app_modules_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         continue;
298       }
299
300       $configPath = $sf_app_modules_dir.'/'.$directory.'/config/config_handlers.yml';
301
302       if (is_readable($configPath))
303       {
304         // initialize the root configuration handler with this module name
305         $params = array('module_level' => true, 'module_name' => $directory);
306
307         $this->handlers['config_handlers.yml']->initialize($params);
308
309         // replace module dir path with a special keyword that
310         // checkConfig knows how to use
311         $configPath = 'modules/'.$directory.'/config/config_handlers.yml';
312
313         require $this->checkConfig($configPath);
314       }
315     }
316
317     // close file pointer
318     closedir($fp);
319   }
320
321   /**
322    * Writes a cache file.
323    *
324    * @param string $config An absolute filesystem path to a configuration file
325    * @param string $cache  An absolute filesystem path to the cache file that will be written
326    * @param string $data   Data to be written to the cache file
327    *
328    * @throws sfCacheException If the cache file cannot be written
329    */
330   protected function writeCacheFile($config, $cache, $data)
331   {
332     $current_umask = umask(0000);
333     if (!is_dir(dirname($cache)))
334     {
335       if (false === @mkdir(dirname($cache), 0777, true))
336       {
337         throw new sfCacheException(sprintf('Failed to make cache directory "%s" while generating cache for configuration file "%s".', dirname($cache), $config));
338       }
339     }
340
341     $tmpFile = tempnam(dirname($cache), basename($cache));
342
343     if (!$fp = @fopen($tmpFile, 'wb'))
344     {
345       throw new sfCacheException(sprintf('Failed to write cache file "%s" generated from configuration file "%s".', $tmpFile, $config));
346     }
347
348     @fwrite($fp, $data);
349     @fclose($fp);
350
351     // Hack from Agavi (http://trac.agavi.org/changeset/3979)
352     // With php < 5.2.6 on win32, renaming to an already existing file doesn't work, but copy does,
353     // so we simply assume that when rename() fails that we are on win32 and try to use copy()
354     if (!@rename($tmpFile, $cache))
355     {
356       if (copy($tmpFile, $cache))
357       {
358         unlink($tmpFile);
359       }
360     }
361
362     chmod($cache, 0666);
363     umask($current_umask);
364   }
365
366   /**
367    * Registers a configuration handler.
368    *
369    * @param string $handler The handler to use when parsing a configuration file
370    * @param class  $class   A configuration handler class
371    * @param string $params  An array of options for the handler class initialization
372    */
373   public function registerConfigHandler($handler, $class, $params = array())
374   {
375     class_exists($class);
376     $this->userHandlers[$handler] = new $class($params);
377   }
378
379   /**
380    * Merges configuration handlers from the config_handlers.yml 
381    * and the ones defined with registerConfigHandler()
382    *
383    */
384   protected function mergeUserConfigHandlers()
385   {
386     // user defined configuration handlers
387     $this->handlers = array_merge($this->handlers, $this->userHandlers);
388
389     $this->userHandlers = array();
390   }
391 }
392
Note: See TracBrowser for help on using the browser.