DirectoryResource.php 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123
  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. class DirectoryResource implements SelfCheckingResourceInterface, \Serializable
  17. {
  18. private $resource;
  19. private $pattern;
  20. /**
  21. * @param string $resource The file path to the resource
  22. * @param string|null $pattern A pattern to restrict monitored files
  23. *
  24. * @throws \InvalidArgumentException
  25. */
  26. public function __construct(string $resource, string $pattern = null)
  27. {
  28. $this->resource = realpath($resource) ?: (file_exists($resource) ? $resource : false);
  29. $this->pattern = $pattern;
  30. if (false === $this->resource || !is_dir($this->resource)) {
  31. throw new \InvalidArgumentException(sprintf('The directory "%s" does not exist.', $resource));
  32. }
  33. }
  34. /**
  35. * {@inheritdoc}
  36. */
  37. public function __toString()
  38. {
  39. return md5(serialize([$this->resource, $this->pattern]));
  40. }
  41. /**
  42. * @return string The file path to the resource
  43. */
  44. public function getResource()
  45. {
  46. return $this->resource;
  47. }
  48. /**
  49. * Returns the pattern to restrict monitored files.
  50. *
  51. * @return string|null
  52. */
  53. public function getPattern()
  54. {
  55. return $this->pattern;
  56. }
  57. /**
  58. * {@inheritdoc}
  59. */
  60. public function isFresh($timestamp)
  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. /**
  92. * @internal
  93. */
  94. public function serialize()
  95. {
  96. return serialize([$this->resource, $this->pattern]);
  97. }
  98. /**
  99. * @internal
  100. */
  101. public function unserialize($serialized)
  102. {
  103. list($this->resource, $this->pattern) = unserialize($serialized);
  104. }
  105. }