Development

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

You must first sign up to be able to contribute.

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

Revision 23810, 11.2 kB (checked in by Kris.Wallsmith, 4 years ago)

[1.3] set svn:eol-style property to native and svn:keywords property to Id on all .php files

  • Property svn:mime-type set to text/x-php
  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
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 instance to call for this configuration file
64     $handlerInstance = 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       $handlerInstance = $this->getHandler($handler);
74     }
75     else if (isset($this->handlers[$basename]))
76     {
77       // we have a handler associated with the configuration base name
78       $handlerInstance = $this->getHandler($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         $matches = array();
88
89         // create pattern from config
90         if (preg_match('#'.$pattern.'$#', $handler, $matches))
91         {
92           $handlerInstance = $this->getHandler($key);
93           array_shift($matches);
94           $handlerInstance->getParameterHolder()->set('wildcardValues', $matches);
95
96           break;
97         }
98       }
99     }
100
101     if (!$handlerInstance)
102     {
103       // we do not have a registered handler for this file
104       throw new sfConfigurationException(sprintf('Configuration file "%s" does not have a registered handler.', implode(', ', $configs)));
105     }
106
107     // call the handler and retrieve the cache data
108     $data = $handlerInstance->execute($configs);
109
110     $this->writeCacheFile($handler, $cache, $data);
111   }
112
113   /**
114    * Returns the config handler configured for the given name
115    *
116    * @param string $name The config handler name
117    *
118    * @return sfConfigHandler A sfConfigHandler instance
119    */
120   protected function getHandler($name)
121   {
122     if (is_array($this->handlers[$name]))
123     {
124       $class = $this->handlers[$name][0];
125       $this->handlers[$name] = new $class($this->handlers[$name][1]);
126     }
127
128     return $this->handlers[$name];
129   }
130
131   /**
132    * Checks to see if a configuration file has been modified and if so
133    * recompile the cache file associated with it.
134    *
135    * The recompilation only occurs in a non debug environment.
136    *
137    * If the configuration file path is relative, symfony will look in directories
138    * defined in the sfConfiguration::getConfigPaths() method.
139    *
140    * @param string  $configPath A filesystem path to a configuration file
141    * @param boolean $optional   If true, config path does not need to exist
142    *
143    * @return string An absolute filesystem path to the cache filename associated with this specified configuration file
144    *
145    * @throws <b>sfConfigurationException</b> If a requested configuration file does not exist
146    *
147    * @see sfConfiguration::getConfigPaths()
148    */
149   public function checkConfig($configPath, $optional = false)
150   {
151     if (sfConfig::get('sf_debug') && sfConfig::get('sf_logging_enabled'))
152     {
153       $timer = sfTimerManager::getTimer('Configuration');
154     }
155
156     // the cache filename we'll be using
157     $cache = $this->getCacheName($configPath);
158
159     if (!sfConfig::get('sf_debug') && !sfConfig::get('sf_test') && is_readable($cache))
160     {
161       return $cache;
162     }
163
164     if (!sfToolkit::isPathAbsolute($configPath))
165     {
166       $files = $this->configuration->getConfigPaths($configPath);
167     }
168     else
169     {
170       $files = is_readable($configPath) ? array($configPath) : array();
171     }
172
173     if (!isset($files[0]))
174     {
175       if ($optional)
176       {
177         return null;
178       }
179
180       // configuration does not exist
181       throw new sfConfigurationException(sprintf('Configuration "%s" does not exist or is unreadable.', $configPath));
182     }
183
184     // find the more recent configuration file last modification time
185     $mtime = 0;
186     foreach ($files as $file)
187     {
188       if (filemtime($file) > $mtime)
189       {
190         $mtime = filemtime($file);
191       }
192     }
193
194     if (!is_readable($cache) || $mtime > filemtime($cache))
195     {
196       // configuration has changed so we need to reparse it
197       $this->callHandler($configPath, $files, $cache);
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 $config 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 $config   A filesystem path to a configuration file
242    * @param bool   $once     Only allow this configuration file to be included once per request?
243    * @param bool   $optional Only include if true
244    *
245    * @see checkConfig()
246    */
247   public function import($config, $once = true, $optional = false)
248   {
249     $cache = $this->checkConfig($config, $optional);
250
251     if ($optional && !$cache)
252     {
253       return;
254     }
255
256     // include cache file
257     if ($once)
258     {
259       include_once($cache);
260     }
261     else
262     {
263       include($cache);
264     }
265   }
266
267   /**
268    * Loads all configuration application and module level handlers.
269    *
270    * @throws <b>sfConfigurationException</b> If a configuration related error occurs.
271    */
272   protected function loadConfigHandlers()
273   {
274     // manually create our config_handlers.yml handler
275     $this->handlers['config_handlers.yml'] = new sfRootConfigHandler();
276
277     // application configuration handlers
278
279     require $this->checkConfig('config/config_handlers.yml');
280
281     // module level configuration handlers
282
283     // checks modules directory exists
284     if (!is_readable($sf_app_modules_dir = sfConfig::get('sf_app_modules_dir')))
285     {
286       return;
287     }
288
289     // ignore names
290     $ignore = array('.', '..', 'CVS', '.svn');
291
292     // create a file pointer to the module dir
293     $fp = opendir($sf_app_modules_dir);
294
295     // loop through the directory and grab the modules
296     while (($directory = readdir($fp)) !== false)
297     {
298       if (in_array($directory, $ignore))
299       {
300         continue;
301       }
302
303       $configPath = $sf_app_modules_dir.'/'.$directory.'/config/config_handlers.yml';
304
305       if (is_readable($configPath))
306       {
307         // initialize the root configuration handler with this module name
308         $params = array('module_level' => true, 'module_name' => $directory);
309
310         $this->handlers['config_handlers.yml']->initialize($params);
311
312         // replace module dir path with a special keyword that
313         // checkConfig knows how to use
314         $configPath = 'modules/'.$directory.'/config/config_handlers.yml';
315
316         require $this->checkConfig($configPath);
317       }
318     }
319
320     // close file pointer
321     closedir($fp);
322   }
323
324   /**
325    * Writes a cache file.
326    *
327    * @param string $config An absolute filesystem path to a configuration file
328    * @param string $cache  An absolute filesystem path to the cache file that will be written
329    * @param string $data   Data to be written to the cache file
330    *
331    * @throws sfCacheException If the cache file cannot be written
332    */
333   protected function writeCacheFile($config, $cache, $data)
334   {
335     $current_umask = umask(0000);
336     if (!is_dir(dirname($cache)))
337     {
338       if (false === @mkdir(dirname($cache), 0777, true))
339       {
340         throw new sfCacheException(sprintf('Failed to make cache directory "%s" while generating cache for configuration file "%s".', dirname($cache), $config));
341       }
342     }
343
344     $tmpFile = tempnam(dirname($cache), basename($cache));
345
346     if (!$fp = @fopen($tmpFile, 'wb'))
347     {
348       throw new sfCacheException(sprintf('Failed to write cache file "%s" generated from configuration file "%s".', $tmpFile, $config));
349     }
350
351     @fwrite($fp, $data);
352     @fclose($fp);
353
354     // Hack from Agavi (http://trac.agavi.org/changeset/3979)
355     // With php < 5.2.6 on win32, renaming to an already existing file doesn't work, but copy does,
356     // so we simply assume that when rename() fails that we are on win32 and try to use copy()
357     if (!@rename($tmpFile, $cache))
358     {
359       if (copy($tmpFile, $cache))
360       {
361         unlink($tmpFile);
362       }
363     }
364
365     chmod($cache, 0666);
366     umask($current_umask);
367   }
368
369   /**
370    * Registers a configuration handler.
371    *
372    * @param string $handler The handler to use when parsing a configuration file
373    * @param class  $class   A configuration handler class
374    * @param string $params  An array of options for the handler class initialization
375    */
376   public function registerConfigHandler($handler, $class, $params = array())
377   {
378     $this->userHandlers[$handler] = new $class($params);
379   }
380
381   /**
382    * Merges configuration handlers from the config_handlers.yml 
383    * and the ones defined with registerConfigHandler()
384    *
385    */
386   protected function mergeUserConfigHandlers()
387   {
388     // user defined configuration handlers
389     $this->handlers = array_merge($this->handlers, $this->userHandlers);
390
391     $this->userHandlers = array();
392   }
393 }
394
Note: See TracBrowser for help on using the browser.