1: <?php
2: /**
3: * CDirectoryCacheDependency class file.
4: *
5: * @author Qiang Xue <qiang.xue@gmail.com>
6: * @link http://www.yiiframework.com/
7: * @copyright 2008-2013 Yii Software LLC
8: * @license http://www.yiiframework.com/license/
9: */
10:
11: /**
12: * CDirectoryCacheDependency represents a dependency based on change of a directory.
13: *
14: * CDirectoryCacheDependency performs dependency checking based on the
15: * modification time of the files contained in the specified directory.
16: * The directory being checked is specified via {@link directory}.
17: *
18: * By default, all files under the specified directory and subdirectories
19: * will be checked. If the last modification time of any of them is changed
20: * or if different number of files are contained in a directory, the dependency
21: * is reported as changed. By specifying {@link recursiveLevel},
22: * one can limit the checking to a certain depth of the directory.
23: *
24: * Note, dependency checking for a directory is expensive because it involves
25: * accessing modification time of multiple files under the directory.
26: *
27: * @author Qiang Xue <qiang.xue@gmail.com>
28: * @package system.caching.dependencies
29: * @since 1.0
30: */
31: class CDirectoryCacheDependency extends CCacheDependency
32: {
33: /**
34: * @var string the directory whose change is used to determine if the dependency has been changed.
35: * If any of the files under the directory is changed, the dependency is considered as changed.
36: */
37: public $directory;
38: /**
39: * @var integer the depth of the subdirectories to be recursively checked.
40: * If the value is less than 0, it means unlimited depth.
41: * If the value is 0, it means checking the files directly under the specified directory.
42: */
43: public $recursiveLevel=-1;
44: /**
45: * @var string the regular expression matching valid file/directory names.
46: * Only the matching files or directories will be checked for changes.
47: * Defaults to null, meaning all files/directories will qualify.
48: */
49: public $namePattern;
50:
51: /**
52: * Constructor.
53: * @param string $directory the directory to be checked
54: */
55: public function __construct($directory=null)
56: {
57: $this->directory=$directory;
58: }
59:
60: /**
61: * Generates the data needed to determine if dependency has been changed.
62: * This method returns the modification timestamps for files under the directory.
63: * @throws CException if {@link directory} is empty
64: * @return mixed the data needed to determine if dependency has been changed.
65: */
66: protected function generateDependentData()
67: {
68: if($this->directory!==null)
69: return $this->generateTimestamps($this->directory);
70: else
71: throw new CException(Yii::t('yii','CDirectoryCacheDependency.directory cannot be empty.'));
72: }
73:
74: /**
75: * Determines the last modification time for files under the directory.
76: * This method may go recursively into subdirectories if {@link recursiveLevel} is not 0.
77: * @param string $directory the directory name
78: * @param integer $level level of the recursion
79: * @throws CException if given directory is not valid
80: * @return array list of file modification time indexed by the file path
81: */
82: protected function generateTimestamps($directory,$level=0)
83: {
84: if(($dir=@opendir($directory))===false)
85: throw new CException(Yii::t('yii','"{path}" is not a valid directory.',
86: array('{path}'=>$directory)));
87: $timestamps=array();
88: while(($file=readdir($dir))!==false)
89: {
90: $path=$directory.DIRECTORY_SEPARATOR.$file;
91: if($file==='.' || $file==='..')
92: continue;
93: if($this->namePattern!==null && !preg_match($this->namePattern,$file))
94: continue;
95: if(is_file($path))
96: {
97: if($this->validateFile($path))
98: $timestamps[$path]=filemtime($path);
99: }
100: else
101: {
102: if(($this->recursiveLevel<0 || $level<$this->recursiveLevel) && $this->validateDirectory($path))
103: $timestamps=array_merge($timestamps, $this->generateTimestamps($path,$level+1));
104: }
105: }
106: closedir($dir);
107: return $timestamps;
108: }
109:
110: /**
111: * Checks to see if the file should be checked for dependency.
112: * This method is invoked when dependency of the whole directory is being checked.
113: * By default, it always returns true, meaning the file should be checked.
114: * You may override this method to check only certain files.
115: * @param string $fileName the name of the file that may be checked for dependency.
116: * @return boolean whether this file should be checked.
117: */
118: protected function validateFile($fileName)
119: {
120: return true;
121: }
122:
123: /**
124: * Checks to see if the specified subdirectory should be checked for dependency.
125: * This method is invoked when dependency of the whole directory is being checked.
126: * By default, it always returns true, meaning the subdirectory should be checked.
127: * You may override this method to check only certain subdirectories.
128: * @param string $directory the name of the subdirectory that may be checked for dependency.
129: * @return boolean whether this subdirectory should be checked.
130: */
131: protected function validateDirectory($directory)
132: {
133: return true;
134: }
135: }
136: