Hoa central
Finder.php
Go to the documentation of this file.
1 <?php
2 
37 namespace Hoa\File;
38 
39 use Hoa\Iterator;
40 
49 class Finder implements Iterator\Aggregate
50 {
56  protected $_splFileInfo = 'Hoa\File\SplFileInfo';
57 
63  protected $_paths = [];
64 
70  protected $_maxDepth = -1;
71 
77  protected $_filters = [];
78 
84  protected $_flags = -1;
85 
91  protected $_types = [];
92 
98  protected $_first = -1;
99 
105  protected $_sorts = [];
106 
107 
108 
114  public function __construct()
115  {
116  $this->_flags = Iterator\FileSystem::KEY_AS_PATHNAME
117  | Iterator\FileSystem::CURRENT_AS_FILEINFO
118  | Iterator\FileSystem::SKIP_DOTS;
119  $this->_first = Iterator\Recursive\Iterator::SELF_FIRST;
120 
121  return;
122  }
123 
130  public function in($path)
131  {
132  if (!is_array($path)) {
133  $path = [$path];
134  }
135 
136  foreach ($path as $p) {
137  $this->_paths[] = $p;
138  }
139 
140  return $this;
141  }
142 
149  public function maxDepth($depth)
150  {
151  $this->_maxDepth = $depth;
152 
153  return $this;
154  }
155 
161  public function files()
162  {
163  $this->_types[] = 'file';
164 
165  return $this;
166  }
167 
173  public function directories()
174  {
175  $this->_types[] = 'dir';
176 
177  return $this;
178  }
179 
185  public function links()
186  {
187  $this->_types[] = 'link';
188 
189  return $this;
190  }
191 
198  public function followSymlinks($flag = true)
199  {
200  if (true === $flag) {
201  $this->_flags ^= Iterator\FileSystem::FOLLOW_SYMLINKS;
202  } else {
203  $this->_flags |= Iterator\FileSystem::FOLLOW_SYMLINKS;
204  }
205 
206  return $this;
207  }
208 
216  public function name($regex)
217  {
218  $this->_filters[] = function ($current) use ($regex) {
219  return 0 !== preg_match($regex, $current->getBasename());
220  };
221 
222  return $this;
223  }
224 
232  public function notIn($regex)
233  {
234  $this->_filters[] = function ($current) use ($regex) {
235  foreach (explode(DS, $current->getPathname()) as $part) {
236  if (0 !== preg_match($regex, $part)) {
237  return false;
238  }
239  }
240 
241  return true;
242  };
243 
244  return $this;
245  }
246 
261  public function size($size)
262  {
263  if (0 === preg_match('#^(<|<=|>|>=|=)\s*(\d+)\s*((?:[KMGTPEZY])b)?$#', $size, $matches)) {
264  return $this;
265  }
266 
267  $number = floatval($matches[2]);
268  $unit = isset($matches[3]) ? $matches[3] : 'b';
269  $operator = $matches[1];
270 
271  switch ($unit) {
272 
273  case 'b':
274  break;
275 
276  // kilo
277  case 'Kb':
278  $number <<= 10;
279 
280  break;
281 
282  // mega.
283  case 'Mb':
284  $number <<= 20;
285 
286  break;
287 
288  // giga.
289  case 'Gb':
290  $number <<= 30;
291 
292  break;
293 
294  // tera.
295  case 'Tb':
296  $number *= 1099511627776;
297 
298  break;
299 
300  // peta.
301  case 'Pb':
302  $number *= pow(1024, 5);
303 
304  break;
305 
306  // exa.
307  case 'Eb':
308  $number *= pow(1024, 6);
309 
310  break;
311 
312  // zetta.
313  case 'Zb':
314  $number *= pow(1024, 7);
315 
316  break;
317 
318  // yota.
319  case 'Yb':
320  $number *= pow(1024, 8);
321 
322  break;
323  }
324 
325  $filter = null;
326 
327  switch ($operator) {
328 
329  case '<':
330  $filter = function ($current, $key, $iterator) use ($number) {
331  return $current->getSize() < $number;
332  };
333 
334  break;
335 
336  case '<=':
337  $filter = function ($current, $key, $iterator) use ($number) {
338  return $current->getSize() <= $number;
339  };
340 
341  break;
342 
343  case '>':
344  $filter = function ($current, $key, $iterator) use ($number) {
345  return $current->getSize() > $number;
346  };
347 
348  break;
349 
350  case '>=':
351  $filter = function ($current, $key, $iterator) use ($number) {
352  return $current->getSize() >= $number;
353  };
354 
355  break;
356 
357  case '=':
358  $filter = function ($current, $key, $iterator) use ($number) {
359  return $current->getSize() === $number;
360  };
361 
362  break;
363  }
364 
365  $this->_filters[] = $filter;
366 
367  return $this;
368  }
369 
376  public function dots($flag = true)
377  {
378  if (true === $flag) {
379  $this->_flags ^= Iterator\FileSystem::SKIP_DOTS;
380  } else {
381  $this->_flags |= Iterator\FileSystem::SKIP_DOTS;
382  }
383 
384  return $this;
385  }
386 
393  public function owner($owner)
394  {
395  $this->_filters[] = function ($current) use ($owner) {
396 
397  return $current->getOwner() === $owner;
398  };
399 
400  return $this;
401  }
402 
417  protected function formatDate($date, &$operator)
418  {
419  $time = 0;
420  $operator = -1;
421 
422  if (0 === preg_match('#\bago\b#', $date)) {
423  $date .= ' ago';
424  }
425 
426  if (0 !== preg_match('#^(since|until)\b(.+)$#', $date, $matches)) {
427  $time = strtotime($matches[2]);
428 
429  if ('until' === $matches[1]) {
430  $operator = 1;
431  }
432  } else {
433  $time = strtotime($date);
434  }
435 
436  return $time;
437  }
438 
447  public function changed($date)
448  {
449  $time = $this->formatDate($date, $operator);
450 
451  if (-1 === $operator) {
452  $this->_filters[] = function ($current) use ($time) {
453  return $current->getCTime() >= $time;
454  };
455  } else {
456  $this->_filters[] = function ($current) use ($time) {
457  return $current->getCTime() < $time;
458  };
459  }
460 
461  return $this;
462  }
463 
472  public function modified($date)
473  {
474  $time = $this->formatDate($date, $operator);
475 
476  if (-1 === $operator) {
477  $this->_filters[] = function ($current) use ($time) {
478  return $current->getMTime() >= $time;
479  };
480  } else {
481  $this->_filters[] = function ($current) use ($time) {
482  return $current->getMTime() < $time;
483  };
484  }
485 
486  return $this;
487  }
488 
502  public function filter($callback)
503  {
504  $this->_filters[] = $callback;
505 
506  return $this;
507  }
508 
519  public function sortByName($locale = 'root')
520  {
521  if (true === class_exists('Collator', false)) {
522  $collator = new \Collator($locale);
523 
524  $this->_sorts[] = function ($a, $b) use ($collator) {
525  return $collator->compare($a->getPathname(), $b->getPathname());
526  };
527  } else {
528  $this->_sorts[] = function ($a, $b) {
529  return strcmp($a->getPathname(), $b->getPathname());
530  };
531  }
532 
533  return $this;
534  }
535 
543  public function sortBySize()
544  {
545  $this->_sorts[] = function ($a, $b) {
546  return $a->getSize() < $b->getSize();
547  };
548 
549  return $this;
550  }
551 
565  public function sort($callable)
566  {
567  $this->_sorts[] = $callable;
568 
569  return $this;
570  }
571 
577  public function childFirst()
578  {
579  $this->_first = Iterator\Recursive\Iterator::CHILD_FIRST;
580 
581  return $this;
582  }
583 
589  public function getIterator()
590  {
591  $_iterator = new Iterator\Append();
592  $types = $this->getTypes();
593 
594  if (!empty($types)) {
595  $this->_filters[] = function ($current) use ($types) {
596  return in_array($current->getType(), $types);
597  };
598  }
599 
600  $maxDepth = $this->getMaxDepth();
601  $splFileInfo = $this->getSplFileInfo();
602 
603  foreach ($this->getPaths() as $path) {
604  if (1 == $maxDepth) {
605  $iterator = new Iterator\IteratorIterator(
606  new Iterator\Recursive\Directory(
607  $path,
608  $this->getFlags(),
609  $splFileInfo
610  ),
611  $this->getFirst()
612  );
613  } else {
614  $iterator = new Iterator\Recursive\Iterator(
615  new Iterator\Recursive\Directory(
616  $path,
617  $this->getFlags(),
618  $splFileInfo
619  ),
620  $this->getFirst()
621  );
622 
623  if (1 < $maxDepth) {
624  $iterator->setMaxDepth($maxDepth - 1);
625  }
626  }
627 
628  $_iterator->append($iterator);
629  }
630 
631  foreach ($this->getFilters() as $filter) {
632  $_iterator = new Iterator\CallbackFilter(
633  $_iterator,
634  $filter
635  );
636  }
637 
638  $sorts = $this->getSorts();
639 
640  if (empty($sorts)) {
641  return $_iterator;
642  }
643 
644  $array = iterator_to_array($_iterator);
645 
646  foreach ($sorts as $sort) {
647  uasort($array, $sort);
648  }
649 
650  return new Iterator\Map($array);
651  }
652 
659  public function setSplFileInfo($splFileInfo)
660  {
661  $old = $this->_splFileInfo;
662  $this->_splFileInfo = $splFileInfo;
663 
664  return $old;
665  }
666 
672  public function getSplFileInfo()
673  {
674  return $this->_splFileInfo;
675  }
676 
682  protected function getPaths()
683  {
684  return $this->_paths;
685  }
686 
692  public function getMaxDepth()
693  {
694  return $this->_maxDepth;
695  }
696 
702  public function getTypes()
703  {
704  return $this->_types;
705  }
706 
712  public function getName()
713  {
714  return $this->_name;
715  }
716 
722  protected function getFilters()
723  {
724  return $this->_filters;
725  }
726 
732  protected function getSorts()
733  {
734  return $this->_sorts;
735  }
736 
742  public function getFlags()
743  {
744  return $this->_flags;
745  }
746 
752  public function getFirst()
753  {
754  return $this->_first;
755  }
756 }
followSymlinks($flag=true)
Definition: Finder.php:198
filter($callback)
Definition: Finder.php:502
formatDate($date, &$operator)
Definition: Finder.php:417
owner($owner)
Definition: Finder.php:393
sort($callable)
Definition: Finder.php:565
sortByName($locale= 'root')
Definition: Finder.php:519
modified($date)
Definition: Finder.php:472
setSplFileInfo($splFileInfo)
Definition: Finder.php:659
changed($date)
Definition: Finder.php:447
maxDepth($depth)
Definition: Finder.php:149
name($regex)
Definition: Finder.php:216
size($size)
Definition: Finder.php:261
notIn($regex)
Definition: Finder.php:232
dots($flag=true)
Definition: Finder.php:376