Continued:
[core.git] / framework / main / classes / file_directories / directory / class_FrameworkDirectoryPointer.php
1 <?php
2 // Own namespace
3 namespace Org\Mxchange\CoreFramework\Filesytem\Pointer;
4
5 // Import framework stuff
6 use Org\Mxchange\CoreFramework\Filesystem\FrameworkDirectory;
7 use Org\Mxchange\CoreFramework\Generic\NullPointerException;
8 use Org\Mxchange\CoreFramework\Object\BaseFrameworkSystem;
9
10 // Deprecated imports
11 use Org\Mxchange\CoreFramework\Deprecated\PathIsNoDirectoryException;
12
13 // Import SPL stuff
14 use \DirectoryIterator;
15 use \InvalidArgumentException;
16
17 /**
18  * A class for directory reading and getting its contents, no recursion!
19  *
20  * @author              Roland Haeder <webmaster@shipsimu.org>
21  * @version             0.0.0
22  * @copyright   Copyright (c) 2007, 2008 Roland Haeder, 2009 - 2021 Core Developer Team
23  * @license             GNU GPL 3.0 or any newer version
24  * @link                http://www.shipsimu.org
25  *
26  * This program is free software: you can redistribute it and/or modify
27  * it under the terms of the GNU General Public License as published by
28  * the Free Software Foundation, either version 3 of the License, or
29  * (at your option) any later version.
30  *
31  * This program is distributed in the hope that it will be useful,
32  * but WITHOUT ANY WARRANTY; without even the implied warranty of
33  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
34  * GNU General Public License for more details.
35  *
36  * You should have received a copy of the GNU General Public License
37  * along with this program. If not, see <http://www.gnu.org/licenses/>.
38  */
39 class FrameworkDirectoryPointer extends BaseFrameworkSystem implements FrameworkDirectory {
40         /**
41          * The current path we are working in
42          */
43         private $pathName = '';
44
45         /**
46          * The directory iterator instance
47          */
48         private $iteratorInstance = NULL;
49
50         /**
51          * Protected constructor
52          */
53         private function __construct () {
54                 // Call parent constructor
55                 parent::__construct(__CLASS__);
56         }
57
58         /**
59          * Destructor for cleaning purposes, etc
60          */
61         public function __destruct() {
62                 // Is there a resource pointer? Then we have to close the directory here!
63                 if ($this->getDirectoryIteratorInstance() instanceof DirectoryIterator) {
64                         // Try to close a directory
65                         $this->closeDirectory();
66                 }
67
68                 // Call the parent destructor
69                 parent::__destruct();
70         }
71
72         /**
73          * Create a directory pointer based on the given path. The path will also
74          * be verified here.
75          *
76          * @param       $pathName               The path name we shall pass to opendir()
77          * @return      $pointerInstance        A prepared instance of FrameworkDirectoryPointer
78          * @throws      NullPointerException    If the provided path name is null
79          * @throws      InvalidPathStringException      If the provided path name is not a string
80          * @throws      PathIsNoDirectoryException      If the provided path name is not valid
81          * @throws      PathReadProtectedException      If the provided path name is read-protected
82          */
83         public static final function createFrameworkDirectoryPointer (string $pathName) {
84                 // Some pre-sanity checks...
85                 if (empty($pathName)) {
86                         // Throw IAE
87                         throw new InvalidArgumentException('Parameter "pathName" is empty');
88                 } elseif (!is_dir($pathName)) {
89                         // Not a directory
90                         throw new PathIsNoDirectoryException($pathName, self::EXCEPTION_INVALID_PATH_NAME);
91                 } elseif (!is_readable($pathName)) {
92                         // Not readable
93                         throw new PathReadProtectedException($pathName, self::EXCEPTION_READ_PROTECED_PATH);
94                 }
95
96                 // Create new instance
97                 $pointerInstance = new FrameworkDirectoryPointer();
98
99                 // Get an iterator for the directory
100                 $iteratorInstance = new DirectoryIterator($pathName);
101
102                 // ... and rewind back
103                 $iteratorInstance->rewind();
104
105                 // Set directory pointer and path name
106                 $pointerInstance->setDirectoryIteratorInstance($iteratorInstance);
107                 $pointerInstance->setPathName($pathName);
108
109                 // Return the instance
110                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput('DIRECTORY-POINTER: Opened pathName=' . $pathName . ' - EXIT!');
111                 return $pointerInstance;
112         }
113
114         /**
115          * Read raw lines of data from a directory pointer and return the data
116          *
117          * @return      $currentEntry   Current entry from encapsulated iterator
118          */
119         public function readRawDirectory () {
120                 // Can the next entry be read?
121                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput('DIRECTORY-POINTER: CALLED!');
122                 assert($this->getDirectoryIteratorInstance()->valid());
123
124                 // Read data from the directory pointer and return it
125                 $currentEntry = $this->getDirectoryIteratorInstance()->current();
126
127                 // Return found entry
128                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('DIRECTORY-POINTER: currentEntry[%s]=%s - EXIT!', gettype($currentEntry), $currentEntry));
129                 return $currentEntry;
130         }
131
132         /**
133          * Read lines from the current directory pointer except some parts
134          *
135          * @param       $except         Some parts of a directory we want to ignore. Valid: directory and file names, other values will be silently ignored
136          * @return      SplFileInfo             An instance of a SplFileInfo class
137          */
138         public function readDirectoryExcept (array $except = []) {
139                 // No exceptions given?
140                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('DIRECTORY-POINTER: except()=%d - CALLED!', count($except)));
141                 if (count($except) == 0) {
142                         // No exception given, so read all files and directories, but not recursive
143                         self::createDebugInstance(__CLASS__, __LINE__)->debugOutput('DIRECTORY-POINTER: No exceptions given, please use readRawDirectory() instead!');
144                         return $this->readRawDirectory();
145                 } elseif (!$this->getDirectoryIteratorInstance()->valid()) {
146                         // No more left to read
147                         //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput('DIRECTORY-POINTER: EOD reached - EXIT!');
148                         return NULL;
149                 }
150
151                 // Init raw line
152                 $fileInfoInstance = NULL;
153
154                 // Read a raw line...
155                 $currentEntry = $this->readRawDirectory();
156
157                 // Shall we exclude directories?
158                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('DIRECTORY-POINTER: currentEntry[]=%s', gettype($currentEntry)));
159                 if (is_object($currentEntry)) {
160                         // Get file name
161                         $fileInfoInstance = $currentEntry;
162
163                         // Is it a dot-directory or excluded?
164                         //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('DIRECTORY-POINTER: fileInfoInstance->filename=%s,isDot=%d', $fileInfoInstance->getFilename(), intval($this->getDirectoryIteratorInstance()->isDot())));
165                         while ($this->getDirectoryIteratorInstance()->valid() && ($this->getDirectoryIteratorInstance()->isDot() || in_array($fileInfoInstance->getFilename(), $except))) {
166                                 // Update current instance
167                                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('DIRECTORY-POINTER: fileInfoInstance->filename=%s,isDot=%d', $fileInfoInstance->getFilename(), intval($this->getDirectoryIteratorInstance()->isDot())));
168                                 $fileInfoInstance = $this->readRawDirectory();
169
170                                 // To next entry
171                                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput('DIRECTORY-POINTER: Invoking directoryIteratorInstance->next() ...');
172                                 $this->getDirectoryIteratorInstance()->next();
173                         }
174                 }
175
176                 // Return read line
177                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('DIRECTORY-POINTER: fileInfoInstance[%s]=%s - EXIT!', gettype($fileInfoInstance), $fileInfoInstance));
178                 return $fileInfoInstance;
179         }
180
181         /**
182          * Close a directory source and set it's instance to null and the path name
183          * to empty
184          *
185          * @return      void
186          */
187         public function closeDirectory () {
188                 // Close the directory by unsetting it
189                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput('DIRECTORY-POINTER: CALLED!');
190                 $this->unsetDirectoryIteratorInstance();
191                 $this->setPathName('');
192         }
193
194         /**
195          * Setter for the directory pointer
196          *
197          * @param       $iteratorInstance       An instanceof a DirectoryIterator class
198          * @return      void
199          */
200         protected final function setDirectoryIteratorInstance (DirectoryIterator $iteratorInstance) {
201                 // Set instance
202                 $this->iteratorInstance = $iteratorInstance;
203         }
204
205         /**
206          * Getter for the directory pointer
207          *
208          * @return      $iteratorInstance       The directory pointer which shall be a valid directory resource
209          */
210         public final function getDirectoryIteratorInstance () {
211                 return $this->iteratorInstance;
212         }
213
214         /**
215          * Remove directory iterator instance (effectively closing it) by setting
216          * it to NULL. This will trigger a call on the destructor which will then
217          * "close" the iterator.
218          *
219          * @param       $iteratorInstance       An instanceof a DirectoryIterator class
220          * @return      void
221          */
222         protected final function unsetDirectoryIteratorInstance () {
223                 // "Unset" the instance
224                 $this->iteratorInstance = NULL;
225         }
226
227         /**
228          * Setter for path name
229          *
230          * @param       $pathName       The new path name
231          * @return      void
232          */
233         protected final function setPathName (string $pathName) {
234                 $this->pathName = $pathName;
235         }
236
237         /**
238          * Getter for path name
239          *
240          * @return      $pathName       The current path name
241          */
242         public final function getPathName () {
243                 return $this->pathName;
244         }
245
246 }