PageRenderTime 48ms CodeModel.GetById 21ms RepoModel.GetById 0ms app.codeStats 0ms

/Slick/Utility/Folder.php

https://bitbucket.org/fsilva/slick-framework
PHP | 295 lines | 180 code | 16 blank | 99 comment | 4 complexity | c9d60e9f74669f0e23063b6ad8645d84 MD5 | raw file
  1. <?php
  2. /**
  3. * Folder
  4. *
  5. * PHP version 5
  6. *
  7. * Licensed under the Apache License, Version 2.0 (the "License");
  8. * you may not use this file except in compliance with the License.
  9. * You may obtain a copy of the License at
  10. *
  11. * http://www.apache.org/licenses/LICENSE-2.0
  12. *
  13. * Unless required by applicable law or agreed to in writing, software
  14. * distributed under the License is distributed on an "AS IS" BASIS,
  15. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  16. * See the License for the specific language governing permissions and
  17. * limitations under the License.
  18. *
  19. * @package Slick
  20. * @subpackage Utility
  21. * @author Filipe Silva <silvam.filipe@gmail.com>
  22. * @copyright Filipe Silva 2013
  23. * @license Apache License, Version 2.0 (the "License")
  24. * @since Version 1.0.0
  25. */
  26. namespace Slick\Utility;
  27. use Slick\Base;
  28. use Slick\Utility\Exception;
  29. /**
  30. * Folder
  31. *
  32. * Folder class is an utility that wrapps a file system folder/directory
  33. *
  34. * @package Slick
  35. * @subpackage Utility
  36. * @author Filipe Silva <silvam.filipe@gmail.com>
  37. */
  38. class Folder extends Base
  39. {
  40. /**
  41. * Regular expression to validate folder paths.
  42. */
  43. const PATH = '/^[\\0-9a-z\/\.\-\_]+$/i';
  44. /**
  45. * The folder path
  46. * @readwrite
  47. * @var string
  48. */
  49. protected $_path;
  50. /**
  51. * Flag for directory presence
  52. * @read
  53. * @var boolean
  54. */
  55. protected $_exists = false;
  56. /**
  57. * Flag for folder write permissions
  58. * @read
  59. * @var boolean
  60. */
  61. protected $_writable = false;
  62. /**
  63. * The default mode when craeting new folders
  64. * @readwrite
  65. * @var integer
  66. */
  67. protected $_defaultMode = 0775;
  68. /**
  69. * Tells the system to create is folder isn't found.
  70. * @readwrite
  71. * @var boolean
  72. */
  73. protected $_createIfNotFound = true;
  74. /**
  75. * A collection of files
  76. * @read
  77. * @var Slick\Utility\FileList
  78. */
  79. protected $_files;
  80. /**
  81. * Check if folder exists and sets the folder flags appropriately.
  82. *
  83. * By default Slick will try to create recursively the folder if
  84. * it doesn't exists.
  85. *
  86. * @param array|Object $options The properties for the object
  87. * beeing constructed.
  88. *
  89. * @throws \Slick\Utility\Exception\Permissions If folder cant be
  90. * created due to invalid or insufficient permissions to create
  91. * the folder.
  92. * @throws \Slick\Utility\Exception\Argument If The path passed to
  93. * constructor is an invalid or malformed path string.
  94. * Eg. NULL, empty, etc...
  95. */
  96. public function __construct($options = array())
  97. {
  98. parent::__construct($options);
  99. if (!preg_match(Folder::PATH, $this->_path)) {
  100. throw new Exception\Argument("Invalid folder path supplied");
  101. }
  102. $this->refresh();
  103. }
  104. /**
  105. * Checks if the folder is writeable.
  106. *
  107. * @return boolean True if folder is writable, false otherwise.
  108. */
  109. public function isWritable()
  110. {
  111. return $this->writable;
  112. }
  113. /**
  114. * Adds a new file to this folder.
  115. *
  116. * This accepts a string as a file name or a File object. If File object
  117. * is given then the internal file folder will be set to this folder and
  118. * file contents will be copied for the new file location.
  119. *
  120. * @param \Slick\Utility\File $file A string containing the new file
  121. * name to add or an File object.
  122. *
  123. * @return Slick\Utility\Folder A self instance for method chain call.
  124. */
  125. public function addFile($file)
  126. {
  127. if (is_string($file)) {
  128. $file = new File(
  129. array(
  130. 'name' => $file,
  131. 'folder' => $this
  132. )
  133. );
  134. } else {
  135. $file->setFolder($this);
  136. }
  137. if (!is_null($this->_files->findByName($file->name))) {
  138. throw new Exception\FileExists(
  139. "There's a file with the same name " .
  140. "in current folder: {$file->name}"
  141. );
  142. }
  143. $this->files->add($file);
  144. return $this;
  145. }
  146. /**
  147. * Adds a folder to current folder path.
  148. *
  149. * @param string $folder The folder name to add.
  150. *
  151. */
  152. public function addFolder($folder)
  153. {
  154. $path = $this->_path . DIRECTORY_SEPARATOR . $folder;
  155. return new Folder(array('path' => $path));
  156. }
  157. /**
  158. * Checks if a given file exists in this folder.
  159. *
  160. * @param \Slick\Utility\File $file A string containing the file
  161. * name or an File object.
  162. *
  163. * @return boolean True if file already exists, false otherwise.
  164. */
  165. public function hasFile($file)
  166. {
  167. $name = $file;
  168. if (is_a($name, '\Slick\Utility\File')) {
  169. $name = $file->name;
  170. }
  171. return (boolean) $this->_files->findByName($name);
  172. }
  173. /**
  174. * Deletes a file (fisically) from this folder.
  175. *
  176. * @param \Slick\Utility\File $file A string containing the file
  177. * name or an File object.
  178. *
  179. * @return \Slick\Utility\Folder A self instance for method chain call.
  180. */
  181. public function deleteFile($file)
  182. {
  183. $name = $file;
  184. if (is_a($name, 'Slick\Utility\File')) {
  185. $name = $file->name;
  186. }
  187. $file = $this->_files->findByName($file->name);
  188. if (!empty($file)) {
  189. if ($file->exists) {
  190. $file->delete();
  191. }
  192. $this->files->remove();
  193. }
  194. return $this;
  195. }
  196. /**
  197. * Deletes current forlder and all its files.
  198. *
  199. * @return boolean Returns TRUE on success or FALSE on failure.
  200. */
  201. public function delete()
  202. {
  203. foreach ($this->_files as $file) {
  204. $this->deleteFile($file);
  205. }
  206. return rmdir($this->_path);
  207. }
  208. /**
  209. * Reloads this directory files and settings.
  210. *
  211. * @return \Slick\Utility\Folder A self instance for method chain call.
  212. */
  213. public function refresh()
  214. {
  215. if (is_dir($this->_path)) {
  216. $this->_exists = true;
  217. if (is_writable($this->path)) {
  218. $this->_writable = true;
  219. }
  220. } else if ($this->_createIfNotFound) {
  221. $old = umask(0);
  222. if (!@mkdir($this->_path, $this->_defaultMode, true)) {
  223. throw new Exception\Permissions(
  224. "Cannot create folder '{$this->_path}'"
  225. );
  226. } else {
  227. $this->_exists = true;
  228. $this->_writable = true;
  229. }
  230. umask($old);
  231. }
  232. $this->_files = new FileList();
  233. $excludeList = array(".", "..");
  234. if ($this->_exists) {
  235. $files = array_diff(scandir($this->_path), $excludeList);
  236. foreach ($files as $file) {
  237. $this->_files->add(
  238. new File(array('folder' => $this, 'name' => $file))
  239. );
  240. }
  241. }
  242. return $this;
  243. }
  244. /**
  245. * Returns the path to the folder when requested to conver to string.
  246. *
  247. * @return string The path to the folder.
  248. */
  249. public function __toString()
  250. {
  251. return $this->_path;
  252. }
  253. /**
  254. * Overrides the base implementaion exception calling.
  255. *
  256. * @param String $method The method name.
  257. *
  258. * @return Exception\Implementation The implementation exception.
  259. */
  260. protected function _getExceptionForImplementation($method)
  261. {
  262. return new Exception\Implementation(
  263. "{$method} method not implemented"
  264. );
  265. }
  266. }