Created
September 25, 2018 15:53
-
-
Save sasin91/0c3485bae60d6d5ec90dcb169934cdf5 to your computer and use it in GitHub Desktop.
Create archives with a pretty fluent syntax
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 App; | |
use Illuminate\Contracts\Filesystem\Filesystem; | |
use Illuminate\Support\Facades\Storage; | |
use Phar; | |
use PharData; | |
use function is_dir; | |
use function is_file; | |
use function is_null; | |
use function starts_with; | |
use function str_contains; | |
use function str_random; | |
use function strstr; | |
use function substr; | |
use function unlink; | |
/** | |
* Class Archive | |
* | |
* @package \App | |
* @api (new Archive)->containing($arrayOfFiles)->storeOn($laravelDiskName)->storeIn($directory)->storeAs($filename)->create() or forceCreate() | |
*/ | |
class Archive | |
{ | |
/** | |
* The files to stuff in the archive | |
* | |
* @var array | |
*/ | |
protected $files = []; | |
/** | |
* The archive format | |
* | |
* @var string | |
*/ | |
protected $format; | |
/** | |
* The target file name | |
* | |
* @var string | |
*/ | |
protected $targetFilename = null; | |
/** | |
* Store the archive in target directory | |
* | |
* @var string | |
*/ | |
protected $targetDirectory = null; | |
/** | |
* Filesystem disk name | |
* | |
* @var string | |
*/ | |
protected $disk = null; | |
/** | |
* The filesystem adapter for the disk | |
* | |
* @var Filesystem | |
*/ | |
private $storage; | |
/** | |
* Whether to force create the archive | |
* | |
* @var bool | |
*/ | |
private $forceCreating = false; | |
/** | |
* Archive constructor. | |
* | |
* @param array $files | |
* @param string $format | |
*/ | |
public function __construct(array $files = [], string $format = 'tar.gz') | |
{ | |
$this->files = $files; | |
$this->format = $format; | |
} | |
/** | |
* Set the files to compress | |
* | |
* @param array $files | |
* @return Archive | |
*/ | |
public function containing(array $files): Archive | |
{ | |
$this->files = $files; | |
return $this; | |
} | |
/** | |
* Set the target file name | |
* | |
* @param string $targetFilename | |
* @return Archive | |
*/ | |
public function storeAs(string $targetFilename): Archive | |
{ | |
// When the target file name contains an extension, | |
// strip that format and use it as Archive.format | |
if (str_contains($targetFilename, '.')) { | |
$this->format(strstr($targetFilename, '.')); | |
$this->targetFilename = strstr($targetFilename, '.', true); | |
return $this; | |
} | |
$this->targetFilename = $targetFilename; | |
return $this; | |
} | |
/** | |
* Set the archive format | |
* | |
* @param string $format | |
* @return Archive | |
*/ | |
public function format(string $format): Archive | |
{ | |
if (starts_with($format, '.')) { | |
$format = substr($format, 1); | |
} | |
$this->format = $format; | |
return $this; | |
} | |
/** | |
* Set the target directory | |
* | |
* @param string $targetDirectory | |
* @return Archive | |
*/ | |
public function storeIn(string $targetDirectory): Archive | |
{ | |
$this->targetDirectory = $targetDirectory; | |
return $this; | |
} | |
/** | |
* Set the filesystem disk name | |
* | |
* @param string $disk | |
* @return Archive | |
*/ | |
public function storeOn(string $disk): Archive | |
{ | |
$this->disk = $disk; | |
return $this; | |
} | |
/** | |
* Force creating the archive | |
* | |
* @return string | |
*/ | |
public function forceCreate(): string | |
{ | |
return $this->useForce(true)->create(); | |
} | |
/** | |
* Create the archive then return the path to it | |
* | |
* @return string | |
*/ | |
public function create(): string | |
{ | |
if (is_null($this->targetFilename)) { | |
$this->targetFilename = $this->makeFileName(); | |
} | |
switch ($this->format) { | |
case 'tar.gz': | |
$archivePath = $this->fullTargetFilePath(); | |
if (is_file("{$archivePath}.tar.gz") && $this->isForceCreating()) { | |
unlink("{$archivePath}.tar.gz"); | |
} | |
$archive = $this->compressIntoTarArchive($archivePath); | |
$archive->compress(Phar::GZ); | |
$this->storage()->delete("{$this->targetFilename}.tar"); | |
return "{$this->targetFilename}.tar.gz"; | |
break; | |
default: | |
$this->compressIntoTarArchive(); | |
return "{$this->targetFilename}.tar"; | |
break; | |
} | |
} | |
private function makeFileName(): string | |
{ | |
return str_random(); | |
} | |
private function fullTargetFilePath(): string | |
{ | |
$targetDirectory = $this->fullTargetDirectory(); | |
return "{$targetDirectory}/{$this->targetFilename}"; | |
} | |
private function fullTargetDirectory(): string | |
{ | |
$storageRoot = config("filesystems.disks.{$this->disk}.root"); | |
if (is_null($this->targetDirectory)) { | |
return $storageRoot; | |
} | |
if (is_dir($this->targetDirectory)) { | |
return $this->targetDirectory; | |
} | |
return "{$storageRoot}/{$this->targetDirectory}"; | |
} | |
/** | |
* Whether we're forcing archive creation | |
* | |
* @return bool | |
*/ | |
public function isForceCreating(): bool | |
{ | |
return $this->forceCreating; | |
} | |
protected function compressIntoTarArchive(string $archivePath = null): PharData | |
{ | |
$archivePath = $archivePath ?? $this->fullTargetFilePath(); | |
$archive = new PharData("{$archivePath}.tar"); | |
$this->addFilesToArchive($archive); | |
return $archive; | |
} | |
private function addFilesToArchive($archive): void | |
{ | |
if ($archive instanceof PharData) { | |
$this->addFilesToPharArchive($archive); | |
} | |
} | |
private function addFilesToPharArchive(PharData $archive): void | |
{ | |
foreach ($this->files as $file) { | |
$archive->addFromString($file, $this->storage()->get($file)); | |
} | |
} | |
protected function storage(): Filesystem | |
{ | |
if ($this->storage) { | |
return $this->storage; | |
} | |
return $this->storage = Storage::disk($this->disk); | |
} | |
/** | |
* Determine whether to force creating the archive | |
* | |
* @param bool $force | |
* @return Archive | |
*/ | |
public function useForce(bool $force = true): Archive | |
{ | |
$this->forceCreating = $force; | |
return $this; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment