Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add support for Google Cloud Storage #183

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@
"php": ">=5.4",
"symfony/http-foundation": "~2.3|~3.0",
"imagine/imagine": "~0.6.2",
"doctrine/inflector": "~1"
"doctrine/inflector": "~1",
"superbalist/flysystem-google-storage": "^3.0|^4.0|^5.0"
},
"require-dev": {
"mockery/mockery": "0.8.0",
Expand Down
34 changes: 25 additions & 9 deletions src/Attachment.php
Original file line number Diff line number Diff line change
Expand Up @@ -532,15 +532,10 @@ public function jsonSerialize()
*/
protected function flushWrites()
{
foreach ($this->queuedForWrite as $style) {
if ($style->dimensions && $this->uploadedFile->isImage()) {
$file = $this->resizer->resize($this->uploadedFile, $style);
} else {
$file = $this->uploadedFile->getRealPath();
}

$filePath = $this->path($style->name);
$this->move($file, $filePath);
if ($this->uploadedFile->isImage()) {
$this->queueImages();
} else {
$this->queueFile();
}

$this->queuedForWrite = [];
Expand All @@ -555,6 +550,27 @@ protected function flushDeletes()
$this->queuedForDeletion = [];
}

protected function queueImages()
{
foreach ($this->queuedForWrite as $style) {
if ($style->dimensions) {
$file = $this->resizer->resize($this->uploadedFile, $style);
} else {
$file = $this->uploadedFile->getRealPath();
}

$filePath = $this->path($style->name);
$this->move($file, $filePath);
}
}

protected function queueFile()
{
$file = $this->uploadedFile->getRealPath();
$filePath = $this->path($this->config->default_style);
$this->move($file, $filePath);
}

/**
* Fill the queuedForWrite que with all of this attachment's styles.
*/
Expand Down
7 changes: 7 additions & 0 deletions src/Factories/Storage.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

use Codesleeve\Stapler\Attachment as AttachedFile;
use Codesleeve\Stapler\Storage\Filesystem;
use Codesleeve\Stapler\Storage\GCS;
use Codesleeve\Stapler\Storage\S3;
use Codesleeve\Stapler\Stapler;

Expand All @@ -29,6 +30,12 @@ public static function create(AttachedFile $attachment)
return new S3($attachment, $s3Client);
break;

case 'gcs':
$gcsFilesystem = Stapler::getGCSClientInstance($attachment);

return new GCS($attachment, $gcsFilesystem);
break;

default:
return new Filesystem($attachment);
break;
Expand Down
23 changes: 23 additions & 0 deletions src/Stapler.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@
use Codesleeve\Stapler\Interfaces\Attachment as AttachmentInterface;
use Codesleeve\Stapler\Interfaces\Config as ConfigInterface;
use Codesleeve\Stapler\File\Image\Resizer;
use League\Flysystem\Filesystem as LeagueFilesystem;
use Superbalist\Flysystem\GoogleStorage\GoogleStorageAdapter;
use Google\Cloud\Storage\StorageClient;
use Aws\S3\S3Client;

/**
Expand Down Expand Up @@ -187,6 +190,26 @@ public static function getS3ClientInstance(AttachmentInterface $attachedFile)
return static::$s3Clients[$key];
}

/**
* Return an Filesystem object for Google Cloud Storage.
*
* @param AttachmentInterface $attachedFile
*
* @return \League\Flysystem\Filesystem
*/
public static function getGCSClientInstance(AttachmentInterface $attachedFile)
{
$storageClient = new StorageClient([
'projectId' => $attachedFile->google_cloud_project_id,
'keyFilePath' => $attachedFile->google_cloud_key_file,
]);

$bucket = $storageClient->bucket($attachedFile->google_cloud_storage_bucket);
$adapter = new GoogleStorageAdapter($storageClient, $bucket);
$filesystem = new LeagueFilesystem($adapter);
return $filesystem;
}

/**
* Return a configuration object instance.
* If no instance is currently set, we'll return an instance
Expand Down
85 changes: 85 additions & 0 deletions src/Storage/GCS.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
<?php

namespace Codesleeve\Stapler\Storage;

use Codesleeve\Stapler\Interfaces\Storage as StorageInterface;
use Codesleeve\Stapler\Attachment;
use League\Flysystem\Filesystem;

class GCS implements StorageInterface
{
/**
* The current attachedFile object being processed.
*
* @var \Codesleeve\Stapler\Attachment
*/
public $attachedFile;

/**
* The AWS S3Client instance.
*
* @var Filesystem
*/
protected $filesystem;

/**
* Constructor method.
*
* @param Attachment $attachedFile
* @param Filesystem $filesystem
*/
public function __construct(Attachment $attachedFile, Filesystem $filesystem)
{
$this->attachedFile = $attachedFile;
$this->filesystem = $filesystem;
}

/**
* Return the url for a file upload.
*
* @param string $styleName
*
* @return string
*/
public function url($styleName)
{
return $this->filesystem->getAdapter()->getUrl($this->path($styleName));
}

/**
* Return the key the uploaded file object is stored under within a bucket.
*
* @param string $styleName
*
* @return string
*/
public function path($styleName)
{
return $this->attachedFile->getInterpolator()->interpolate($this->attachedFile->path, $this->attachedFile, $styleName);
}

/**
* Remove an attached file.
*
* @param array $filePaths
*/
public function remove(array $filePaths)
{
if ($filePaths) {
$this->filesystem->delete($filePaths);
}
}

/**
* Move an uploaded file to it's intended destination.
*
* @param string $file
* @param string $filePath
*/
public function move($file, $filePath)
{
$this->filesystem->put($filePath, fopen($file, 'r+'));

unlink($file);
}
}
35 changes: 34 additions & 1 deletion src/Validator.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,17 @@ class Validator implements ValidatorInterface
*/
public function validateOptions(array $options)
{
$options['storage'] == 'filesystem' ? $this->validateFilesystemOptions($options) : $this->validateS3Options($options);
switch ($options['storage']) {
case 's3':
$this->validateS3Options($options);
break;
case 'gcs':
$this->validateGCSOptions($options);
break;
case 'filesystem':
default:
$this->validateFilesystemOptions($options);
}
}

/**
Expand Down Expand Up @@ -54,4 +64,27 @@ protected function validateS3Options(array $options)
throw new Exceptions\InvalidUrlOptionException('Invalid Path: a key is required for s3 storage.', 1);
}
}

/**
* Validate the attachment options for an attachment type when the storage
* driver is set to 'gcs'.
*
* @throws InvalidUrlOptionException
*
* @param array $options
*/
protected function validateGCSOptions(array $options)
{
if (!$options['google_cloud_project_id']) {
throw new Exceptions\InvalidUrlOptionException('Invalid Path: a google project id is required for gcs storage.', 1);
}

if (!$options['google_cloud_key_file']) {
throw new Exceptions\InvalidUrlOptionException('Invalid Path: a google key file is required for gcs storage.', 1);
}

if (!$options['google_cloud_storage_bucket']) {
throw new Exceptions\InvalidUrlOptionException('Invalid Path: a bucket is required for gcs storage.', 1);
}
}
}