*/ class DirectoryStateChecker extends ResourceStateChecker { /** @var DirectoryStateChecker[] */ protected $directories = array(); /** @var FileResource[] */ protected $files = array(); /** @var array File inotify events */ protected $fileEvents = array(); /** @var array Dir inotify events */ protected $dirEvents = array(); /** * @var array It is used to track resource moving * @see DirectoryStateChecker::trackMoveEvent() */ protected $movedResources = array(); /** * @var string Key in the $movedResources array where to put name of the resource from next following move event. * @see DirectoryStateChecker::trackMoveEvent() */ protected $lastMove; /** @var bool */ protected $isNew = false; /** * Initializes checker. * * @param CheckerBag $bag * @param DirectoryResource $resource * @param int $eventsMask */ public function __construct(CheckerBag $bag, DirectoryResource $resource, $eventsMask = FilesystemEvent::ALL) { parent::__construct($bag, $resource, $eventsMask); $this->createChildCheckers(); } /** * {@inheritdoc} */ public function setEvent($mask, $name = '') { if ($this->isDir($mask)) { if (0 !== (IN_ATTRIB & $mask)) { return; } $this->dirEvents[$name] = $mask; } else { $this->fileEvents[$name] = $mask; } $this->trackMoveEvent($mask, $name); } /** * {@inheritdoc} */ public function getChangeset() { $this->event = isset($this->fileEvents['']) ? $this->fileEvents[''] : null; unset($this->fileEvents['']); $this->handleItself(); $changeset = array(); if ($this->event) { if ($event = $this->fromInotifyMask($this->event)) { $changeset[] = array( 'resource' => $this->getResource(), 'event' => $event ); } if ($this->isDeleted($this->event)) { $this->fileEvents = array_fill_keys(array_keys($this->files), IN_DELETE); $this->dirEvents = array_fill_keys(array_keys($this->directories), IN_DELETE); $this->getBag()->remove($this); $this->id = null; } } $deleted = array(); foreach ($this->movedResources as $key => $value) { if ($key === $value) { unset($this->dirEvents[$key]); unset($this->fileEvents[$key]); } } foreach ($this->dirEvents as $name => $event) { $normalized = $this->normalizeEvent($event); if (isset($this->directories[$name])) { $this->directories[$name]->setEvent($normalized); if ($this->isDeleted($normalized)) { $deleted[] = $this->directories[$name]; unset($this->directories[$name]); } } elseif (!$this->isDeleted($normalized)) { $this->createNewDirectoryChecker($name); } } foreach ($this->fileEvents as $name => $event) { $normalized = $this->normalizeFileEvent($event, $name); if (($event = $this->fromInotifyMask($normalized)) && $this->files[$name] instanceof FileResource) { $changeset[] = array( 'resource' => $this->files[$name], 'event' => $event ); } if ($this->isDeleted($normalized)) { unset($this->files[$name]); } } $funct = function($checker) use (&$changeset) { foreach ($checker->getChangeset() as $change) { $changeset[] = $change; } }; array_walk($this->directories, $funct); array_walk($deleted, $funct); $this->dirEvents = $this->fileEvents = $this->movedResources = array(); $this->event = null; return $changeset; } /** * Tracks move event. It is for situation when resource was roundtripped, e.g. * rename('dir', 'dir_new'); rename('dir_new', 'dir'). As a result no events should be returned. * This function just keeps track of the move events, and they're analyzed in the getChangeset method. * * @param int $mask * @param string $name */ protected function trackMoveEvent($mask, $name) { if ($this->isMovedFrom($mask)) { if ($key = array_search($name, $this->movedResources)) { $this->lastMove = $key; } else { $this->lastMove = $name; } } elseif ($this->isMovedTo($mask)) { $this->movedResources[$this->lastMove] = $name; } elseif ($key = array_search($name, $this->movedResources)) { unset($this->movedResources[$key]); } } /** * Handles event related to itself. */ protected function handleItself() { if (!$this->isNew && $this->isCreated($this->event)) { $this->unwatch($this->id); $this->reindexChildCheckers(); $this->event = null; } $this->isNew = false; } /** * Reads files and subdirectories and transforms them to resources. */ protected function createChildCheckers() { foreach ($this->getResource()->getFilteredResources() as $resource) { $resource instanceof DirectoryResource ? $this->directories[basename((string) $resource)] = new DirectoryStateChecker($this->getBag(), $resource, $this->getEventsMask()) : $this->files[basename((string) $resource)] = $resource; } } /** * Used in case the folder was deleted and than created again or situations like this. * It rescans the folder, files that was before get IN_MODIFY event, folders - IN_CREATE - to make them to rescan itself */ protected function reindexChildCheckers() { $this->fileEvents = array_fill_keys(array_keys($this->files), IN_DELETE); $this->dirEvents = array_fill_keys(array_keys($this->directories), IN_DELETE); foreach ($this->getResource()->getFilteredResources() as $resource) { $basename = basename((string) $resource); if ($resource instanceof FileResource) { if (isset($this->files[$basename])) { $this->fileEvents[$basename] = IN_MODIFY; } else { $this->files[$basename] = $resource; $this->fileEvents[$basename] = 'new'; } } else { isset($this->directories[$basename]) ? $this->dirEvents[$basename] = IN_CREATE : $this->createNewDirectoryChecker($basename, $resource); } } $this->watch(); } /** * Normalizes file event * * @param int $event * @param string $name * * @return null|int */ protected function normalizeFileEvent($event, $name) { if ('new' === $event) { return IN_CREATE; } $event = $this->normalizeEvent($event); if (isset($this->files[$name])) { return $this->isCreated($event) ? IN_MODIFY : $event; } if (!$this->isDeleted($event)) { $this->createFileResource($name); return IN_CREATE; } return null; } /** * Normalizes event * * @param int $event * * @return int */ protected function normalizeEvent($event) { $event &= ~IN_ISDIR; if (0 !== ($event & IN_MOVED_FROM)) { return IN_DELETE; } elseif (0 !== ($event & IN_MOVED_TO)) { return IN_CREATE; } return $event; } /** * Creates new DirectoryStateChecker * * @param string $name * @param null|DirectoryResource $resource */ protected function createNewDirectoryChecker($name, DirectoryResource $resource = null) { $resource = $resource ?: new DirectoryResource($this->getResource()->getResource().'/'.$name); $this->directories[$name] = new NewDirectoryStateChecker($this->getBag(), $resource, $this->getEventsMask()); } /** * Creates new FileResource * * @param string $name */ protected function createFileResource($name) { if ($this->getResource()->getPattern() && !preg_match($this->getResource()->getPattern(), $name)) { $this->files[$name] = 'skip'; } else { $this->files[$name] = new FileResource($this->getResource()->getResource().'/'.$name); } } } __halt_compiler();----SIGNATURE:----wT+LCJ6Lc1/o6sveK13lJzc04nLrGvc3bRQAXcXElZ/xFeJEKJJ8U5yHFfCtXlCAZjEjUrSLv7SBzA21jR5NTMS/xHI0GwnXuTyemdsNdtYQIpvLiz+8mPbb8mnRUISQCfxtSi1H0UX9ULB1jjbfSXk7l9bJrKR36Ed4DlxRv4NF0T8/v4lM84ld2QBsqo4p/5lGaHDJxdT6q3pG6ScLUsmo6QHJeV0JT/X0doBsVt0TSsX+I1kLFIUCa9d/uLKsVSi2+FAV2TENqimmklkIaKIRGk09Gz/c/Yg6b4bsKtNqAMp0fdV76tRD1RnJ2l5vGiLwVKe6BMcxPTAwst4KzYeG8dcEVoKkTcj7NJ3S0/ZPxxb2jHb3N02mORPliGCwgBiNNV7k7Eok8rZ7WiTfoq3BeCLeOASChYoNrBweaBibU2UVTIFEC2bEAIMIO4RwTA8YHmrPHnU0JGFbK7QuzqowmLfYo7EYvlDKzQRwvFNSakggOTmsiBi6zi6atJ9gf6L9GlbasyLHNF/UEO2l04lAFZd3qOQQFPkbaJ00XiD0leeBzv/r4SSTNTh6XsCtj8iomRXfjY7aVXMH99qq8QRyu7yrLD/n0RaJCfjP5OwuI2ueFtdeovdIt8MAy9929Gdyz/NxaF+IaEYTwsq7EF8ioDJzVOrB25TDqFXrOEQ=----ATTACHMENT:----NTUzMjg5NjQ0NTI0MzU5NyA1NzI1NjkxNTI4NDkwMTE5IDMxNjkzODQ0NzY4NzkwMg==