DirectoryResource.php 2.6 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697
  1. <?php
  2. /*
  3. * This file is part of the Symfony package.
  4. *
  5. * (c) Fabien Potencier <fabien@symfony.com>
  6. *
  7. * For the full copyright and license information, please view the LICENSE
  8. * file that was distributed with this source code.
  9. */
  10. namespace Symfony\Component\Config\Resource;
  11. /**
  12. * DirectoryResource represents a resources stored in a subdirectory tree.
  13. *
  14. * @author Fabien Potencier <fabien@symfony.com>
  15. *
  16. * @final
  17. */
  18. class DirectoryResource implements SelfCheckingResourceInterface
  19. {
  20. private $resource;
  21. private $pattern;
  22. /**
  23. * @param string $resource The file path to the resource
  24. * @param string|null $pattern A pattern to restrict monitored files
  25. *
  26. * @throws \InvalidArgumentException
  27. */
  28. public function __construct(string $resource, ?string $pattern = null)
  29. {
  30. $this->resource = realpath($resource) ?: (file_exists($resource) ? $resource : false);
  31. $this->pattern = $pattern;
  32. if (false === $this->resource || !is_dir($this->resource)) {
  33. throw new \InvalidArgumentException(sprintf('The directory "%s" does not exist.', $resource));
  34. }
  35. }
  36. public function __toString(): string
  37. {
  38. return md5(serialize([$this->resource, $this->pattern]));
  39. }
  40. public function getResource(): string
  41. {
  42. return $this->resource;
  43. }
  44. public function getPattern(): ?string
  45. {
  46. return $this->pattern;
  47. }
  48. /**
  49. * {@inheritdoc}
  50. */
  51. public function isFresh(int $timestamp): bool
  52. {
  53. if (!is_dir($this->resource)) {
  54. return false;
  55. }
  56. if ($timestamp < filemtime($this->resource)) {
  57. return false;
  58. }
  59. foreach (new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($this->resource), \RecursiveIteratorIterator::SELF_FIRST) as $file) {
  60. // if regex filtering is enabled only check matching files
  61. if ($this->pattern && $file->isFile() && !preg_match($this->pattern, $file->getBasename())) {
  62. continue;
  63. }
  64. // always monitor directories for changes, except the .. entries
  65. // (otherwise deleted files wouldn't get detected)
  66. if ($file->isDir() && str_ends_with($file, '/..')) {
  67. continue;
  68. }
  69. // for broken links
  70. try {
  71. $fileMTime = $file->getMTime();
  72. } catch (\RuntimeException $e) {
  73. continue;
  74. }
  75. // early return if a file's mtime exceeds the passed timestamp
  76. if ($timestamp < $fileMTime) {
  77. return false;
  78. }
  79. }
  80. return true;
  81. }
  82. }