Last active
January 31, 2019 16:30
-
-
Save narthur/e1a5d7c36dd9957e3753b3af673164d8 to your computer and use it in GitHub Desktop.
[Filesystem object] #php
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
namespace Resume; | |
class Filesystem | |
{ | |
private $recursiveMatchingScans = []; | |
public function getFile($path) | |
{ | |
return file_get_contents($path); | |
} | |
/** | |
* @param $projectRelativePath | |
* @return bool|string | |
* @throws \Exception | |
*/ | |
public function deleteTree($projectRelativePath) | |
{ | |
if (!$projectRelativePath) { | |
throw new \Exception("Directory path required"); | |
} | |
if (!BASEDIR) { | |
throw new \Exception("Basedir not defined"); | |
} | |
$realPath = realpath(BASEDIR . "/$projectRelativePath"); | |
if (!$realPath) { | |
throw new \Exception("Could not resolve directory to be deleted"); | |
} | |
if (substr($realPath, 0, strlen(BASEDIR)) !== BASEDIR) { | |
throw new \Exception("Specified directory not inside basedir"); | |
} | |
$result = system("rm -r $projectRelativePath/*"); | |
if ($result === false) { | |
throw new \Exception("Failed to delete directory"); | |
} | |
return $result; | |
} | |
public function fileForceContents($path, $contents) | |
{ | |
$parts = explode('/', $path); | |
array_pop($parts); | |
$dir = implode("/", $parts); | |
$this->makeTree($dir); | |
file_put_contents($path, $contents); | |
} | |
/** | |
* @param $path | |
*/ | |
public function makeTree($path) | |
{ | |
$parts = explode("/", $path); | |
$dir = ""; | |
foreach ($parts as $part) { | |
if (!is_dir($dir .= "/$part")) $this->makeDir($dir); | |
} | |
} | |
public function makeDir($path) | |
{ | |
mkdir($path); | |
} | |
public function scanDir($path) | |
{ | |
return array_diff(scandir($path), ["..", "."]); | |
} | |
public function isDir($path) | |
{ | |
return is_dir($path); | |
} | |
public function findPathsMatchingRecursive($path, $regex) | |
{ | |
$key = "$path:$regex"; | |
if (!isset($this->recursiveMatchingScans[$key])) { | |
$this->recursiveMatchingScans[$key] = $this->doRecursivePathMatching($path, $regex); | |
} | |
return $this->recursiveMatchingScans[$key]; | |
} | |
/** | |
* @param $path | |
* @param $regex | |
* @return array | |
*/ | |
private function doRecursivePathMatching($path, $regex): array | |
{ | |
$paths = $this->getPathsInPath($path); | |
$dirPaths = $this->filterPathsForDirs($paths); | |
$filePaths = array_diff($paths, $dirPaths); | |
$matchingPaths = $this->filterPaths($regex, $filePaths); | |
return array_reduce($dirPaths, function ($carry, $dirPath) use ($regex) { | |
$matches = $this->doRecursivePathMatching($dirPath, $regex); | |
return array_merge($carry, $matches); | |
}, $matchingPaths); | |
} | |
/** | |
* @param $path | |
* @return array | |
*/ | |
private function getPathsInPath($path): array | |
{ | |
$scan = array_diff($this->scanDir($path), [".", "..", ".git"]); | |
return array_map(function ($scanName) use ($path) { | |
return "$path/$scanName"; | |
}, $scan); | |
} | |
/** | |
* @param $paths | |
* @return array | |
*/ | |
private function filterPathsForDirs($paths): array | |
{ | |
return array_filter($paths, function ($path) { | |
return $this->isDir($path); | |
}); | |
} | |
/** | |
* @param $regex | |
* @param $filePaths | |
* @return array | |
*/ | |
private function filterPaths($regex, $filePaths): array | |
{ | |
$matchingPaths = array_filter($filePaths, function ($filePath) use ($regex) { | |
return preg_match($regex, $filePath); | |
}); | |
return $matchingPaths; | |
} | |
} | |
class StubFilesystem extends Filesystem | |
{ | |
use Stub { | |
__construct as traitConstruct; | |
} | |
private $fileStructure; | |
public function __construct(\PHPUnit\Framework\TestCase $testCase) | |
{ | |
$this->traitConstruct($testCase); | |
$this->loadFileStructure([]); | |
} | |
public function createFile($path, $contents) | |
{ | |
$this->handleCall(__FUNCTION__, func_get_args()); | |
} | |
public function fileExists($filename) | |
{ | |
return $this->handleCall(__FUNCTION__, func_get_args()); | |
} | |
public function getFileContents($filename) | |
{ | |
$fragments = $this->getPathFragments($filename); | |
$contents = array_reduce($fragments, function($carry, $fragment) { | |
return $carry[$fragment] ?? null; | |
}, $this->fileStructure); | |
return $this->handleCall(__FUNCTION__, func_get_args()) ?? $contents; | |
} | |
public function getFileList($pathGlob) | |
{ | |
$paths = $this->structureToPaths($this->fileStructure); | |
$matchingPaths = array_filter($paths, function($path) use($pathGlob) { | |
return fnmatch($pathGlob, $path); | |
}); | |
return $this->handleCall(__FUNCTION__, func_get_args()) ?? $matchingPaths; | |
} | |
public function getTimeSinceLastUpdate($path) | |
{ | |
return $this->handleCall(__FUNCTION__, func_get_args()); | |
} | |
public function scanDir($dir) | |
{ | |
$contents = $this->getFileContents($dir); | |
$fileNames = array_keys($contents); | |
return $this->handleCall(__FUNCTION__, func_get_args()) ?? $fileNames; | |
} | |
public function isDir($path) | |
{ | |
$contents = $this->getFileContents($path); | |
$isDir = is_array($contents); | |
return $this->handleCall(__FUNCTION__, func_get_args()) ?? $isDir; | |
} | |
public function realPath($path) | |
{ | |
return $this->handleCall(__FUNCTION__, func_get_args()) ?? $path; | |
} | |
public function file($path) | |
{ | |
$contents = $this->getFileContents($path); | |
$lines = explode("\r\n", $contents); | |
return $this->handleCall(__FUNCTION__, func_get_args()) ?? $lines; | |
} | |
public function findPathsMatchingRecursive($path, $regex) | |
{ | |
$structure = $this->getFileContents($path); | |
$paths = $this->structureToPaths($structure, $path); | |
$matchingPaths = array_filter($paths, function($path) use($regex) { | |
return preg_match($regex, $path); | |
}); | |
return $this->handleCall(__FUNCTION__, func_get_args()) ?? $matchingPaths; | |
} | |
public function loadXml($path) | |
{ | |
return $this->handleCall(__FUNCTION__, func_get_args()); | |
} | |
public function saveXml(\SimpleXMLElement $xml, $path) | |
{ | |
return $this->handleCall(__FUNCTION__, func_get_args()); | |
} | |
/* helper functions */ | |
/** | |
* @param array $paths | |
*/ | |
public function loadFilePaths(array $paths) | |
{ | |
array_map(function($path) { | |
$structure = $this->pathToStructure($path,""); | |
$this->loadFileStructure($structure); | |
}, $paths); | |
} | |
/** | |
* @param $path | |
* @param $tailContents | |
* @return array | |
*/ | |
private function pathToStructure($path, $tailContents): array | |
{ | |
$basePathFragments = $this->getPathFragments($path); | |
return $this->pathFragmentsToStructure($basePathFragments, $tailContents); | |
} | |
/** | |
* @param $filename | |
* @return array | |
*/ | |
private function getPathFragments($filename): array | |
{ | |
$trimmedFilename = trim($filename, "/"); | |
$fragments = explode("/", $trimmedFilename); | |
return array_filter($fragments); | |
} | |
/** | |
* @param $structure | |
*/ | |
public function loadFileStructure($structure) | |
{ | |
$this->fileStructure = $structure; | |
} | |
/** | |
* @param $pathFragments | |
* @param array $tailContents | |
* @return array | |
*/ | |
private function pathFragmentsToStructure($pathFragments, $tailContents = []) { | |
if (!$pathFragments) return $tailContents; | |
$fragment = array_pop($pathFragments); | |
return $this->pathFragmentsToStructure($pathFragments, [$fragment => $tailContents]); | |
} | |
/** | |
* @param $structure | |
* @param string $dir | |
* @return mixed | |
*/ | |
private function structureToPaths($structure, $dir = LOCAL_DOCUMENT_ROOT) { | |
$keys = array_keys($structure); | |
$array_reduce = array_reduce($keys, function ($carry, $key) use ($structure, $dir) { | |
$item = $structure[$key]; | |
$trimmedDir = rtrim($dir, "/"); | |
$path = "$trimmedDir/$key"; | |
$paths = is_array($item) ? $this->structureToPaths($item, $path) : [$path]; | |
return array_merge($carry, $paths); | |
}, []); | |
return $array_reduce; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment