Skip to content

Instantly share code, notes, and snippets.

@narthur
Last active January 31, 2019 16:30
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save narthur/e1a5d7c36dd9957e3753b3af673164d8 to your computer and use it in GitHub Desktop.
Save narthur/e1a5d7c36dd9957e3753b3af673164d8 to your computer and use it in GitHub Desktop.
[Filesystem object] #php
<?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