DirectoryResource.php 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106
  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. /**
  37. * {@inheritdoc}
  38. */
  39. public function __toString(): string
  40. {
  41. return md5(serialize([$this->resource, $this->pattern]));
  42. }
  43. /**
  44. * @return string The file path to the resource
  45. */
  46. public function getResource(): string
  47. {
  48. return $this->resource;
  49. }
  50. /**
  51. * Returns the pattern to restrict monitored files.
  52. */
  53. public function getPattern(): ?string
  54. {
  55. return $this->pattern;
  56. }
  57. /**
  58. * {@inheritdoc}
  59. */
  60. public function isFresh(int $timestamp): bool
  61. {
  62. if (!is_dir($this->resource)) {
  63. return false;
  64. }
  65. if ($timestamp < filemtime($this->resource)) {
  66. return false;
  67. }
  68. foreach (new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($this->resource), \RecursiveIteratorIterator::SELF_FIRST) as $file) {
  69. // if regex filtering is enabled only check matching files
  70. if ($this->pattern && $file->isFile() && !preg_match($this->pattern, $file->getBasename())) {
  71. continue;
  72. }
  73. // always monitor directories for changes, except the .. entries
  74. // (otherwise deleted files wouldn't get detected)
  75. if ($file->isDir() && '/..' === substr($file, -3)) {
  76. continue;
  77. }
  78. // for broken links
  79. try {
  80. $fileMTime = $file->getMTime();
  81. } catch (\RuntimeException $e) {
  82. continue;
  83. }
  84. // early return if a file's mtime exceeds the passed timestamp
  85. if ($timestamp < $fileMTime) {
  86. return false;
  87. }
  88. }
  89. return true;
  90. }
  91. }