From 9cfd06866ea6dd44a66e718949a024c644cd4fc6 Mon Sep 17 00:00:00 2001 From: frostealth Date: Fri, 8 Apr 2016 15:50:37 +0600 Subject: [PATCH] initial commit --- .editorconfig | 14 + .gitattributes | 4 + .gitignore | 12 + LICENSE.md | 21 ++ README.md | 106 +++++++ composer.json | 36 +++ grumphp.yml | 12 + src/Service.php | 273 ++++++++++++++++++ src/base/Bus.php | 38 +++ src/base/CommandBuilder.php | 68 +++++ src/base/CommandFactory.php | 160 ++++++++++ src/base/HandlerResolver.php | 98 +++++++ src/base/commands/ExecutableCommand.php | 35 +++ src/base/commands/traits/Async.php | 34 +++ src/base/commands/traits/Options.php | 47 +++ src/base/handlers/Handler.php | 27 ++ src/commands/DeleteCommand.php | 104 +++++++ src/commands/ExistCommand.php | 65 +++++ src/commands/GetCommand.php | 108 +++++++ src/commands/GetPresignedUrlCommand.php | 90 ++++++ src/commands/GetUrlCommand.php | 62 ++++ src/commands/PutCommand.php | 185 ++++++++++++ src/commands/RestoreCommand.php | 122 ++++++++ src/commands/UploadCommand.php | 198 +++++++++++++ src/handlers/ExistCommandHandler.php | 28 ++ .../GetPresignedUrlCommandHandler.php | 27 ++ src/handlers/GetUrlCommandHandler.php | 24 ++ src/handlers/PlainCommandHandler.php | 53 ++++ src/handlers/UploadCommandHandler.php | 53 ++++ src/interfaces/Bus.php | 20 ++ src/interfaces/CommandBuilder.php | 20 ++ src/interfaces/HandlerResolver.php | 27 ++ src/interfaces/Service.php | 27 ++ src/interfaces/commands/Asynchronous.php | 21 ++ src/interfaces/commands/Command.php | 12 + src/interfaces/commands/ExecutableCommand.php | 16 + src/interfaces/commands/HasAcl.php | 16 + src/interfaces/commands/HasBucket.php | 16 + src/interfaces/commands/PlainCommand.php | 21 ++ src/interfaces/handlers/Handler.php | 12 + 40 files changed, 2312 insertions(+) create mode 100644 .editorconfig create mode 100644 .gitattributes create mode 100644 .gitignore create mode 100644 LICENSE.md create mode 100644 README.md create mode 100644 composer.json create mode 100644 grumphp.yml create mode 100644 src/Service.php create mode 100644 src/base/Bus.php create mode 100644 src/base/CommandBuilder.php create mode 100644 src/base/CommandFactory.php create mode 100644 src/base/HandlerResolver.php create mode 100644 src/base/commands/ExecutableCommand.php create mode 100644 src/base/commands/traits/Async.php create mode 100644 src/base/commands/traits/Options.php create mode 100644 src/base/handlers/Handler.php create mode 100644 src/commands/DeleteCommand.php create mode 100644 src/commands/ExistCommand.php create mode 100644 src/commands/GetCommand.php create mode 100644 src/commands/GetPresignedUrlCommand.php create mode 100644 src/commands/GetUrlCommand.php create mode 100644 src/commands/PutCommand.php create mode 100644 src/commands/RestoreCommand.php create mode 100644 src/commands/UploadCommand.php create mode 100644 src/handlers/ExistCommandHandler.php create mode 100644 src/handlers/GetPresignedUrlCommandHandler.php create mode 100644 src/handlers/GetUrlCommandHandler.php create mode 100644 src/handlers/PlainCommandHandler.php create mode 100644 src/handlers/UploadCommandHandler.php create mode 100644 src/interfaces/Bus.php create mode 100644 src/interfaces/CommandBuilder.php create mode 100644 src/interfaces/HandlerResolver.php create mode 100644 src/interfaces/Service.php create mode 100644 src/interfaces/commands/Asynchronous.php create mode 100644 src/interfaces/commands/Command.php create mode 100644 src/interfaces/commands/ExecutableCommand.php create mode 100644 src/interfaces/commands/HasAcl.php create mode 100644 src/interfaces/commands/HasBucket.php create mode 100644 src/interfaces/commands/PlainCommand.php create mode 100644 src/interfaces/handlers/Handler.php diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..4a21708 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,14 @@ +# editorconfig.org + +root = true + +[*] +charset = utf-8 +end_of_line = lf +insert_final_new_line = true +indent_style = space +indent_size = 4 +trim_trailing_whitespace = true + +[*.md] +trim_trailing_whitespace = false \ No newline at end of file diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..0d4cc5d --- /dev/null +++ b/.gitattributes @@ -0,0 +1,4 @@ +.gitattributes export-ignore +.gitignore export-ignore +.editorconfig export-ignore +grumphp.yml export-ignore \ No newline at end of file diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..2ef3443 --- /dev/null +++ b/.gitignore @@ -0,0 +1,12 @@ +.DS_Store +thumbs.db +*.class +*.pyc +*.pyo +*.swp +.project +.settings +.idea +composer.phar +composer.lock +vendor diff --git a/LICENSE.md b/LICENSE.md new file mode 100644 index 0000000..40b1bcb --- /dev/null +++ b/LICENSE.md @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2016 Ivan Kudinov + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..2986533 --- /dev/null +++ b/README.md @@ -0,0 +1,106 @@ +# Yii2 AWS S3 + +An Amazon S3 component for Yii2. + +[![License](https://poser.pugx.org/frostealth/yii2-aws-s3/license)](https://github.com/frostealth/yii2-aws-s3/blob/2.x/LICENSE.md) +[![Latest Stable Version](https://poser.pugx.org/frostealth/yii2-aws-s3/v/stable)](https://packagist.org/packages/frostealth/yii2-aws-s3) +[![Total Downloads](https://poser.pugx.org/frostealth/yii2-aws-s3/downloads)](https://packagist.org/packages/frostealth/yii2-aws-s3) +[![Latest Unstable Version](https://poser.pugx.org/frostealth/yii2-aws-s3/v/unstable)](https://packagist.org/packages/frostealth/yii2-aws-s3) + +## Installation + +1. Run the [Composer](http://getcomposer.org/download/) command to install the latest stable version: + + ```bash + composer require frostealth/yii2-aws-s3 ~2.0@stable + ``` + +2. Add the component to `config/main.php` + + ```php + 'components' => [ + // ... + 's3' => [ + 'class' => 'frostealth\yii2\aws\s3\Service', + 'credentials' => [ // Aws\Credentials\CredentialsInterface|array|callable + 'key' => 'my-key', + 'secret' => 'my-secret', + ], + 'region' => 'my-region', + 'defaultBucket' => 'my-bucket', + 'defaultAcl' => 'public-read', + ], + // ... + ], + ``` + +## Basic usage + +### Usage the command factory and additional params + +```php +/** @var \frostealth\yii2\aws\s3\Service $s3 */ +$s3 = Yii::$app->get('s3'); + +/** @var \Aws\ResultInterface $result */ +$result = $s3->commands()->get('filename.ext')->saveAs('/path/to/local/file.ext')->execute(); + +$result = $s3->commands()->put('filename.ext', 'body')->setContentType('text/plain')->execute(); + +$result = $s3->commands()->delete('filename.ext')->execute(); + +$result = $s3->commands()->upload('filename.ext', '/path/to/local/file.ext')->setAcl('private')->execute(); + +$result = $s3->commands()->restore('filename.ext', $days = 7)->execute(); + +$isExisting = $s3->commands()->exist('filename.ext')->execute(); + +$url = $s3->commands()->getUrl('filename.ext')->execute(); + +$signedUrl = $s3->commands()->getPresignedUrl('filename.ext', '+2 days')->execute(); +``` + +### Short syntax + +```php +/** @var \frostealth\yii2\aws\s3\Service $s3 */ +$s3 = Yii::$app->get('s3'); + +/** @var \Aws\ResultInterface $result */ +$result = $s3->get('filename.ext'); + +$result = $s3->put('filename.ext', 'body'); + +$result = $s3->delete('filename.ext'); + +$result = $s3->upload('filename.ext', '/path/to/local/file.ext'); + +$result = $s3->restore('filename.ext', $days = 7); + +$isExisting = $s3->exist('filename.ext'); + +$url = $s3->getUrl('filename.ext'); + +$signedUrl = $s3->getPresignedUrl('filename.ext', '+2 days'); +``` + +### Asynchronous execution + +```php +/** @var \frostealth\yii2\aws\s3\Service $s3 */ +$s3 = Yii::$app->get('s3'); + +/** @var \GuzzleHttp\Promise\PromiseInterface $promise */ +$promise = $s3->commands()->get('filename.ext')->async()->execute(); + +$promise = $s3->commands()->put('filename.ext', 'body')->async()->execute(); + +$promise = $s3->commands()->delete('filename.ext')->async()->execute(); + +$promise = $s3->commands()->upload('filename.ext', 'source')->async()->execute(); +``` + +## License + +Yii2 AWS S3 is licensed under the MIT License. +See the [LICENSE.md](LICENSE.md) file for more information. \ No newline at end of file diff --git a/composer.json b/composer.json new file mode 100644 index 0000000..b65fa0e --- /dev/null +++ b/composer.json @@ -0,0 +1,36 @@ +{ + "name": "frostealth/yii2-aws-s3", + "type": "yii2-extension", + "description": "An Amazon S3 component for Yii2", + "keywords": ["yii2", "aws", "s3", "aws-s3", "yii2-aws", "yii2-s3"], + "homepage": "https://github.com/frostealth/yii2-aws-s3", + "license": "MIT", + "authors": [ + { + "name": "Ivan Kudinov", + "email": "i.kudinov@frostealth.ru", + "homepage": "http://frostealth.ru" + }, + { + "name": "Constantine Chuprik", + "email": "constantinchuprik@gmail.com" + } + ], + "support": { + "issues": "https://github.com/frostealth/yii2-aws-s3/issues?state=open" + }, + "require": { + "php": ">=7.0.0", + "aws/aws-sdk-php": "~3.17", + "yiisoft/yii2": "~2.0" + }, + "require-dev": { + "phpro/grumphp": "~0.8", + "squizlabs/php_codesniffer": "~2.3" + }, + "autoload": { + "psr-4": { + "frostealth\\yii2\\aws\\s3\\": "src/" + } + } +} diff --git a/grumphp.yml b/grumphp.yml new file mode 100644 index 0000000..baf1ca1 --- /dev/null +++ b/grumphp.yml @@ -0,0 +1,12 @@ +parameters: + git_dir: . + bin_dir: ./vendor/bin + tasks: + git_blacklist: + keywords: + - "die(" + - "die;" + - "exit(" + - "exit;" + - "print_r(" + - "var_dump(" diff --git a/src/Service.php b/src/Service.php new file mode 100644 index 0000000..4493a6c --- /dev/null +++ b/src/Service.php @@ -0,0 +1,273 @@ + '2006-03-01']; + + /** @var array */ + private $components = []; + + /** @var array */ + private $definitions = [ + 'client' => ['class' => 'Aws\S3\S3Client'], + 'resolver' => ['class' => 'frostealth\yii2\aws\s3\base\HandlerResolver'], + 'bus' => ['class' => 'frostealth\yii2\aws\s3\base\Bus'], + 'builder' => ['class' => 'frostealth\yii2\aws\s3\base\CommandBuilder'], + 'factory' => ['class' => 'frostealth\yii2\aws\s3\base\CommandFactory'], + ]; + + /** + * Initializes the object. + * This method is invoked at the end of the constructor after the object is initialized with the + * given configuration. + */ + public function init() + { + if (empty($this->clientConfig['credentials'])) { + throw new InvalidConfigException('Credentials is not set.'); + } + + if (empty($this->clientConfig['region'])) { + throw new InvalidConfigException('Region is not set.'); + } + + if (empty($this->defaultBucket)) { + throw new InvalidConfigException('Default bucket name is not set.'); + } + + foreach ($this->definitions as $name => $definition) { + $this->components[$name] = $this->components[$name] ?? $definition; + } + } + + /** + * Executes a command. + * + * @param \frostealth\yii2\aws\s3\interfaces\commands\Command $command + * + * @return mixed + */ + public function execute(Command $command) + { + return $this->getComponent('bus')->execute($command); + } + + /** + * Creates a command with default params. + * + * @param string $commandClass + * + * @return \frostealth\yii2\aws\s3\interfaces\commands\Command + */ + public function create(string $commandClass): Command + { + return $this->getComponent('builder')->build($commandClass); + } + + /** + * Returns command factory. + * + * @return \frostealth\yii2\aws\s3\base\CommandFactory + */ + public function commands(): CommandFactory + { + return $this->getComponent('factory'); + } + + /** + * Returns handler resolver. + * + * @return \frostealth\yii2\aws\s3\interfaces\HandlerResolver + */ + public function getResolver(): HandlerResolver + { + return $this->getComponent('resolver'); + } + + /** + * @param string $name + * @param array $params + * + * @return mixed + */ + public function __call($name, $params) + { + if (method_exists($this->commands(), $name)) { + $result = call_user_func_array([$this->commands(), $name], $params); + + return $result instanceof Command ? $this->execute($result) : $result; + } + + return parent::__call($name, $params); + } + + /** + * @param \Aws\Credentials\CredentialsInterface|array|callable $credentials + */ + public function setCredentials($credentials) + { + $this->clientConfig['credentials'] = $credentials; + } + + /** + * @param string $region + */ + public function setRegion(string $region) + { + $this->clientConfig['region'] = $region; + } + + /** + * @param array|bool $debug + */ + public function setDebug($debug) + { + $this->clientConfig['debug'] = $debug; + } + + /** + * @param string|array|object $resolver + */ + public function setResolver($resolver) + { + $this->setComponent('resolver', $resolver); + } + + /** + * @param string|array|object $bus + */ + public function setBus($bus) + { + $this->setComponent('bus', $bus); + } + + /** + * @param string|array|object $builder + */ + public function setBuilder($builder) + { + $this->setComponent('builder', $builder); + } + + /** + * @param string|array|object $factory + */ + public function setFactory($factory) + { + $this->setComponent('factory', $factory); + } + + /** + * @param string $name + * + * @return object + */ + protected function getComponent(string $name) + { + if (!is_object($this->components[$name])) { + $this->components[$name] = $this->createComponent($name); + } + + return $this->components[$name]; + } + + /** + * @param string $name + * @param array|object|string $definition + */ + protected function setComponent(string $name, $definition) + { + if (!is_object($definition)) { + $definition = !is_array($definition) ? ['class' => $definition] : $definition; + $definition = ArrayHelper::merge($this->definitions[$name], $definition); + } + + $this->components[$name] = $definition; + } + + /** + * @param string $name + * + * @return object + * @throws \yii\base\InvalidConfigException + */ + protected function createComponent(string $name) + { + $definition = $this->components[$name]; + $params = $this->getComponentParams($name); + + return \Yii::createObject($definition, $params); + } + + /** + * @param string $name + * + * @return array + */ + protected function getComponentParams(string $name): array + { + switch ($name) { + case 'client': + $params = [$this->clientConfig]; + break; + case 'resolver': + $params = [$this->getComponent('client')]; + break; + case 'bus': + $params = [$this->getComponent('resolver')]; + break; + case 'builder': + $params = [$this->getComponent('bus'), $this->defaultBucket, $this->defaultAcl]; + break; + case 'factory': + $params = [$this->getComponent('builder')]; + break; + default: + $params = []; + } + + return $params; + } +} diff --git a/src/base/Bus.php b/src/base/Bus.php new file mode 100644 index 0000000..91d7626 --- /dev/null +++ b/src/base/Bus.php @@ -0,0 +1,38 @@ +resolver = $inflector; + } + + /** + * @param \frostealth\yii2\aws\s3\interfaces\commands\Command $command + * + * @return mixed + */ + public function execute(interfaces\commands\Command $command) + { + $handler = $this->resolver->resolve($command); + + return call_user_func([$handler, 'handle'], $command); + } +} diff --git a/src/base/CommandBuilder.php b/src/base/CommandBuilder.php new file mode 100644 index 0000000..1aff7ea --- /dev/null +++ b/src/base/CommandBuilder.php @@ -0,0 +1,68 @@ +bus = $bus; + $this->bucket = $bucket; + $this->acl = $acl; + } + + /** + * @param string $className + * + * @return \frostealth\yii2\aws\s3\interfaces\commands\Command + * @throws \yii\base\InvalidConfigException + */ + public function build(string $className): interfaces\commands\Command + { + $params = is_subclass_of($className, interfaces\commands\ExecutableCommand::class) ? [$this->bus] : []; + + /** @var interfaces\commands\Command $command */ + $command = \Yii::createObject($className, $params); + + $this->prepareCommand($command); + + return $command; + } + + /** + * @param \frostealth\yii2\aws\s3\interfaces\commands\Command $command + */ + protected function prepareCommand(interfaces\commands\Command $command) + { + if ($command instanceof interfaces\commands\HasBucket) { + $command->setBucket($this->bucket); + } + + if ($command instanceof interfaces\commands\HasAcl) { + $command->setAcl($this->acl); + } + } +} diff --git a/src/base/CommandFactory.php b/src/base/CommandFactory.php new file mode 100644 index 0000000..40abfc4 --- /dev/null +++ b/src/base/CommandFactory.php @@ -0,0 +1,160 @@ +builder = $builder; + } + + /** + * @param string $filename + * + * @return \frostealth\yii2\aws\s3\commands\GetCommand + */ + public function get(string $filename): GetCommand + { + /** @var GetCommand $command */ + $command = $this->builder->build(GetCommand::class); + $command->setFilename($filename); + + return $command; + } + + /** + * @param string $filename + * @param mixed $body + * + * @return \frostealth\yii2\aws\s3\commands\PutCommand + */ + public function put(string $filename, $body): PutCommand + { + /** @var PutCommand $command */ + $command = $this->builder->build(PutCommand::class); + $command->setFilename($filename)->setBody($body); + + return $command; + } + + /** + * @param string $filename + * + * @return \frostealth\yii2\aws\s3\commands\DeleteCommand + */ + public function delete(string $filename): DeleteCommand + { + /** @var DeleteCommand $command */ + $command = $this->builder->build(DeleteCommand::class); + $command->setFilename($filename); + + return $command; + } + + /** + * @param string $filename + * @param mixed $source + * + * @return \frostealth\yii2\aws\s3\commands\UploadCommand + */ + public function upload(string $filename, $source): UploadCommand + { + /** @var UploadCommand $command */ + $command = $this->builder->build(UploadCommand::class); + $command->setFilename($filename)->setSource($source); + + return $command; + } + + /** + * @param string $filename + * @param int $days lifetime of the active copy in days + * + * @return \frostealth\yii2\aws\s3\commands\RestoreCommand + */ + public function restore(string $filename, int $days): RestoreCommand + { + /** @var RestoreCommand $command */ + $command = $this->builder->build(RestoreCommand::class); + $command->setFilename($filename)->setDays($days); + + return $command; + } + + /** + * @param string $filename + * + * @return \frostealth\yii2\aws\s3\commands\ExistCommand + */ + public function exist(string $filename): ExistCommand + { + /** @var ExistCommand $command */ + $command = $this->builder->build(ExistCommand::class); + $command->setFilename($filename); + + return $command; + } + + /** + * @param string $filename + * + * @return \frostealth\yii2\aws\s3\commands\GetUrlCommand + */ + public function getUrl(string $filename): GetUrlCommand + { + /** @var GetUrlCommand $command */ + $command = $this->builder->build(GetUrlCommand::class); + $command->setFilename($filename); + + return $command; + } + + /** + * @param string $filename + * @param mixed $expires + * + * @return \frostealth\yii2\aws\s3\commands\GetPresignedUrlCommand + */ + public function getPresignedUrl(string $filename, $expires): GetPresignedUrlCommand + { + /** @var GetPresignedUrlCommand $command */ + $command = $this->builder->build(GetPresignedUrlCommand::class); + $command->setFilename($filename)->setExpires($expires); + + return $command; + } + + /** + * @param string $commandClass + * + * @return \frostealth\yii2\aws\s3\interfaces\commands\Command + */ + final protected function createCommand(string $commandClass) + { + return $this->builder->build($commandClass); + } +} diff --git a/src/base/HandlerResolver.php b/src/base/HandlerResolver.php new file mode 100644 index 0000000..3129ec0 --- /dev/null +++ b/src/base/HandlerResolver.php @@ -0,0 +1,98 @@ +s3Client = $s3Client; + parent::__construct($config); + } + + /** + * @param \frostealth\yii2\aws\s3\interfaces\commands\Command $command + * + * @return \frostealth\yii2\aws\s3\interfaces\handlers\Handler + * @throws \yii\base\Exception + */ + public function resolve(interfaces\commands\Command $command): interfaces\handlers\Handler + { + $commandClass = get_class($command); + + if (isset($this->handlers[$commandClass])) { + $handler = $this->handlers[$commandClass]; + + return is_object($handler) ? $handler : $this->createHandler($handler); + } + + if ($command instanceof interfaces\commands\PlainCommand) { + return $this->createHandler(PlainCommandHandler::class); + } + + $handlerClass = $commandClass . 'Handler'; + if (class_exists($handlerClass)) { + return $this->createHandler($handlerClass); + } + + $handlerClass = str_replace('\\commands\\', '\\handlers\\', $handlerClass); + if (class_exists($handlerClass)) { + return $this->createHandler($handlerClass); + } + + throw new Exception("Could not terminate the handler of a command of type \"{$commandClass}\""); + } + + /** + * @param string $commandClass + * @param mixed $handler + */ + public function bindHandler(string $commandClass, $handler) + { + $this->handlers[$commandClass] = $handler; + } + + /** + * @param array $handlers + */ + public function setHandlers(array $handlers) + { + foreach ($handlers as $commandClass => $handler) { + $this->bindHandler($commandClass, $handler); + } + } + + /** + * @param string|array $type + * + * @return \frostealth\yii2\aws\s3\interfaces\handlers\Handler + * @throws \yii\base\InvalidConfigException + */ + protected function createHandler($type): interfaces\handlers\Handler + { + return \Yii::createObject($type, [$this->s3Client]); + } +} diff --git a/src/base/commands/ExecutableCommand.php b/src/base/commands/ExecutableCommand.php new file mode 100644 index 0000000..f8c7431 --- /dev/null +++ b/src/base/commands/ExecutableCommand.php @@ -0,0 +1,35 @@ +bus = $bus; + } + + /** + * @return mixed + */ + public function execute() + { + return $this->bus->execute($this); + } +} diff --git a/src/base/commands/traits/Async.php b/src/base/commands/traits/Async.php new file mode 100644 index 0000000..af46bce --- /dev/null +++ b/src/base/commands/traits/Async.php @@ -0,0 +1,34 @@ +isAsync = $async; + + return $this; + } + + /** + * @return bool + */ + final public function isAsync(): bool + { + return $this->isAsync; + } +} diff --git a/src/base/commands/traits/Options.php b/src/base/commands/traits/Options.php new file mode 100644 index 0000000..4dca597 --- /dev/null +++ b/src/base/commands/traits/Options.php @@ -0,0 +1,47 @@ +options = $value; + + return $this; + } + + /** + * @return array + */ + final public function getOptions(): array + { + return $this->options; + } + + /** + * @param string $name + * @param mixed $value + * + * @return $this + */ + final public function setOption(string $name, $value) + { + $this->options[$name] = $value; + + return $this; + } +} diff --git a/src/base/handlers/Handler.php b/src/base/handlers/Handler.php new file mode 100644 index 0000000..672af47 --- /dev/null +++ b/src/base/handlers/Handler.php @@ -0,0 +1,27 @@ +s3Client = $s3Client; + } +} diff --git a/src/commands/DeleteCommand.php b/src/commands/DeleteCommand.php new file mode 100644 index 0000000..7c09dd5 --- /dev/null +++ b/src/commands/DeleteCommand.php @@ -0,0 +1,104 @@ +args['Bucket'] ?? ''; + } + + /** + * @param string $bucket + * + * @return $this + */ + public function setBucket(string $bucket) + { + $this->args['Bucket'] = $bucket; + + return $this; + } + + /** + * @return string + */ + public function getFilename(): string + { + return $this->args['Key'] ?? ''; + } + + /** + * @param string $filename + * + * @return $this + */ + public function setFilename(string $filename) + { + $this->args['Key'] = $filename; + + return $this; + } + + /** + * @return string + */ + public function getVersionId(): string + { + return $this->args['VersionId'] ?? ''; + } + + /** + * @param string $versionId + * + * @return $this + */ + public function setVersionId(string $versionId) + { + $this->args['VersionId'] = $versionId; + + return $this; + } + + /** + * @return string + */ + public function getName(): string + { + return 'DeleteObject'; + } + + /** + * @return array + */ + public function toArgs(): array + { + return array_replace($this->options, $this->args); + } +} diff --git a/src/commands/ExistCommand.php b/src/commands/ExistCommand.php new file mode 100644 index 0000000..3a43da7 --- /dev/null +++ b/src/commands/ExistCommand.php @@ -0,0 +1,65 @@ +bucket; + } + + /** + * @param string $bucket + * + * @return $this + */ + public function setBucket(string $bucket) + { + $this->bucket = $bucket; + + return $this; + } + + /** + * @return string + */ + public function getFilename(): string + { + return $this->filename; + } + + /** + * @param string $filename + * + * @return $this + */ + public function setFilename(string $filename) + { + $this->filename = $filename; + + return $this; + } +} diff --git a/src/commands/GetCommand.php b/src/commands/GetCommand.php new file mode 100644 index 0000000..1881c68 --- /dev/null +++ b/src/commands/GetCommand.php @@ -0,0 +1,108 @@ +args['Bucket'] ?? ''; + } + + /** + * @param string $bucket + * + * @return $this + */ + public function setBucket(string $bucket) + { + $this->args['Bucket'] = $bucket; + + return $this; + } + + /** + * @return string + */ + public function getFilename(): string + { + return $this->args['Key'] ?? ''; + } + + /** + * @param string $filename + * + * @return $this + */ + public function setFilename(string $filename) + { + $this->args['Key'] = $filename; + + return $this; + } + + /** + * @param string $value + * + * @return $this + */ + public function saveAs(string $value) + { + $this->args['SaveAs'] = $value; + + return $this; + } + + /** + * @param string $ifMatch + * + * @return $this + */ + public function ifMatch(string $ifMatch) + { + $this->args['IfMatch'] = $ifMatch; + + return $this; + } + + /** + * @return string + */ + public function getName(): string + { + return 'GetObject'; + } + + /** + * @return array + */ + public function toArgs(): array + { + return array_replace($this->options, $this->args); + } +} diff --git a/src/commands/GetPresignedUrlCommand.php b/src/commands/GetPresignedUrlCommand.php new file mode 100644 index 0000000..5c88895 --- /dev/null +++ b/src/commands/GetPresignedUrlCommand.php @@ -0,0 +1,90 @@ +args['Bucket'] ?? ''; + } + + /** + * @param string $bucket + * + * @return $this + */ + public function setBucket(string $bucket) + { + $this->args['Bucket'] = $bucket; + + return $this; + } + + /** + * @return string + */ + public function getFilename(): string + { + return $this->args['Key'] ?? ''; + } + + /** + * @param string $filename + * + * @return $this + */ + public function setFilename(string $filename) + { + $this->args['Key'] = $filename; + + return $this; + } + + /** + * @return mixed + */ + public function getExpires() + { + return $this->expires; + } + + /** + * @param int|string|\DateTime $expires + * + * @return $this + */ + public function setExpires($expires) + { + $this->expires = $expires; + + return $this; + } + + /** + * @return array + */ + public function getArgs(): array + { + return $this->args; + } +} diff --git a/src/commands/GetUrlCommand.php b/src/commands/GetUrlCommand.php new file mode 100644 index 0000000..a01e271 --- /dev/null +++ b/src/commands/GetUrlCommand.php @@ -0,0 +1,62 @@ +bucket; + } + + /** + * @param string $bucket + * + * @return $this + */ + public function setBucket(string $bucket) + { + $this->bucket = $bucket; + + return $this; + } + + /** + * @return string + */ + public function getFilename(): string + { + return $this->filename; + } + + /** + * @param string $filename + * + * @return $this + */ + public function setFilename(string $filename) + { + $this->filename = $filename; + + return $this; + } +} diff --git a/src/commands/PutCommand.php b/src/commands/PutCommand.php new file mode 100644 index 0000000..ce93e40 --- /dev/null +++ b/src/commands/PutCommand.php @@ -0,0 +1,185 @@ +args['Bucket'] ?? ''; + } + + /** + * @param string $bucket + * + * @return $this + */ + public function setBucket(string $bucket) + { + $this->args['Bucket'] = $bucket; + + return $this; + } + + /** + * @return string + */ + public function getFilename(): string + { + return $this->args['Key'] ?? ''; + } + + /** + * @param string $filename + * + * @return $this + */ + public function setFilename(string $filename) + { + $this->args['Key'] = $filename; + + return $this; + } + + /** + * @return string + */ + public function getAcl(): string + { + return $this->args['ACL'] ?? ''; + } + + /** + * @param string $acl + * + * @return $this + */ + public function setAcl(string $acl) + { + $this->args['ACL'] = $acl; + + return $this; + } + + /** + * @return mixed + */ + public function getBody() + { + return $this->args['Body'] ?? null; + } + + /** + * @param mixed $body + * + * @return $this + */ + public function setBody($body) + { + $this->args['Body'] = $body; + + return $this; + } + + /** + * @return array + */ + public function getMetadata(): array + { + return $this->args['Metadata'] ?? []; + } + + /** + * @param array $metadata + * + * @return $this + */ + public function setMetadata(array $metadata) + { + $this->args['Metadata'] = $metadata; + + return $this; + } + + /** + * @return string + */ + public function getContentType(): string + { + return $this->args['ContentType'] ?? ''; + } + + /** + * @param string $contentType + * + * @return $this + */ + public function setContentType(string $contentType) + { + $this->args['ContentType'] = $contentType; + + return $this; + } + + /** + * @return mixed + */ + public function getExpires() + { + return $this->args['Expires'] ?? null; + } + + /** + * @param mixed $expires + * + * @return $this + */ + public function setExpires($expires) + { + $this->args['Expires'] = $expires; + + return $this; + } + + /** + * @return string + */ + public function getName(): string + { + return 'PutObject'; + } + + /** + * @return array + */ + public function toArgs(): array + { + return array_replace($this->options, $this->args); + } +} diff --git a/src/commands/RestoreCommand.php b/src/commands/RestoreCommand.php new file mode 100644 index 0000000..ba15c0a --- /dev/null +++ b/src/commands/RestoreCommand.php @@ -0,0 +1,122 @@ +args['Bucket'] ?? ''; + } + + /** + * @param string $bucket + * + * @return $this + */ + public function setBucket(string $bucket) + { + $this->args['Bucket'] = $bucket; + + return $this; + } + + /** + * @return string + */ + public function getFilename(): string + { + return $this->args['Key'] ?? ''; + } + + /** + * @param string $filename + * + * @return $this + */ + public function setFilename(string $filename) + { + $this->args['Key'] = $filename; + + return $this; + } + + /** + * @return int lifetime of the active copy in days + */ + public function getDays(): int + { + return $this->args['Days'] ?? 0; + } + + /** + * @param int $days lifetime of the active copy in days + * + * @return $this + */ + public function setDays(int $days) + { + $this->args['Days'] = $days; + + return $this; + } + + /** + * @return string + */ + public function getVersionId(): string + { + return $this->args['VersionId'] ?? ''; + } + + /** + * @param string $versionId + * + * @return $this + */ + public function setVersionId(string $versionId) + { + $this->args['VersionId'] = $versionId; + + return $this; + } + + /** + * @return string + */ + public function getName(): string + { + return 'RestoreObject'; + } + + /** + * @return array + */ + public function toArgs(): array + { + return $this->args; + } +} diff --git a/src/commands/UploadCommand.php b/src/commands/UploadCommand.php new file mode 100644 index 0000000..6909e0d --- /dev/null +++ b/src/commands/UploadCommand.php @@ -0,0 +1,198 @@ +bucket; + } + + /** + * @param string $bucket + * + * @return $this + */ + public function setBucket(string $bucket) + { + $this->bucket = $bucket; + + return $this; + } + + /** + * @return string + */ + public function getAcl(): string + { + return (string)$this->acl; + } + + /** + * @param string $acl + * + * @return $this + */ + public function setAcl(string $acl) + { + $this->acl = $acl; + + return $this; + } + + /** + * @return mixed + */ + public function getSource() + { + return $this->source; + } + + /** + * @param mixed $source + * + * @return $this + */ + public function setSource($source) + { + $this->source = $source; + + return $this; + } + + /** + * @return string + */ + public function getFilename(): string + { + return (string)$this->filename; + } + + /** + * @param string $filename + * + * @return $this + */ + public function setFilename(string $filename) + { + $this->filename = $filename; + + return $this; + } + + /** + * @return int + */ + public function getPartSize(): int + { + return $this->options['part_size'] ?? 0; + } + + /** + * @param int $partSize + * + * @return $this + */ + public function setPartSize(int $partSize) + { + $this->options['part_size'] = $partSize; + + return $this; + } + + /** + * @return int + */ + public function getConcurrency(): int + { + return $this->options['concurrency'] ?? 0; + } + + /** + * @param int $concurrency + * + * @return $this + */ + public function setConcurrency(int $concurrency) + { + $this->options['concurrency'] = $concurrency; + + return $this; + } + + /** + * @return int + */ + public function getMupThreshold(): int + { + return $this->options['mup_threshold'] ?? 0; + } + + /** + * @param int $mupThreshold + * + * @return $this + */ + public function setMupThreshold(int $mupThreshold) + { + $this->options['mup_threshold'] = $mupThreshold; + + return $this; + } + + /** + * @return array + */ + public function getOptions(): array + { + return $this->options; + } + + /** + * @param callable $beforeUpload + * + * @return $this + */ + public function beforeUpload(callable $beforeUpload) + { + $this->options['before_upload'] = $beforeUpload; + + return $this; + } +} diff --git a/src/handlers/ExistCommandHandler.php b/src/handlers/ExistCommandHandler.php new file mode 100644 index 0000000..3adafbe --- /dev/null +++ b/src/handlers/ExistCommandHandler.php @@ -0,0 +1,28 @@ +s3Client->doesObjectExist( + $command->getBucket(), + $command->getFilename(), + $command->getOptions() + ); + } +} diff --git a/src/handlers/GetPresignedUrlCommandHandler.php b/src/handlers/GetPresignedUrlCommandHandler.php new file mode 100644 index 0000000..c33b582 --- /dev/null +++ b/src/handlers/GetPresignedUrlCommandHandler.php @@ -0,0 +1,27 @@ +s3Client->getCommand('GetObject', $command->getArgs()); + $request = $this->s3Client->createPresignedRequest($awsCommand, $command->getExpires()); + + return (string)$request->getUri(); + } +} diff --git a/src/handlers/GetUrlCommandHandler.php b/src/handlers/GetUrlCommandHandler.php new file mode 100644 index 0000000..0fd93f6 --- /dev/null +++ b/src/handlers/GetUrlCommandHandler.php @@ -0,0 +1,24 @@ +s3Client->getObjectUrl($command->getBucket(), $command->getFilename()); + } +} diff --git a/src/handlers/PlainCommandHandler.php b/src/handlers/PlainCommandHandler.php new file mode 100644 index 0000000..f1a4f06 --- /dev/null +++ b/src/handlers/PlainCommandHandler.php @@ -0,0 +1,53 @@ +toAwsCommand($command); + + /** @var \GuzzleHttp\Promise\PromiseInterface $promise */ + $promise = $this->s3Client->executeAsync($awsCommand); + + return $this->commandIsAsync($command) ? $promise : $promise->wait(); + } + + /** + * @param \frostealth\yii2\aws\s3\interfaces\commands\PlainCommand $command + * + * @return bool + */ + protected function commandIsAsync(PlainCommand $command): bool + { + return $command instanceof Asynchronous && $command->isAsync(); + } + + /** + * @param \frostealth\yii2\aws\s3\interfaces\commands\PlainCommand $command + * + * @return \Aws\CommandInterface + */ + protected function toAwsCommand(PlainCommand $command): AwsCommand + { + $args = array_filter($command->toArgs()); + + return $this->s3Client->getCommand($command->getName(), $args); + } +} diff --git a/src/handlers/UploadCommandHandler.php b/src/handlers/UploadCommandHandler.php new file mode 100644 index 0000000..1439c43 --- /dev/null +++ b/src/handlers/UploadCommandHandler.php @@ -0,0 +1,53 @@ +toStream($command->getSource()); + $options = array_filter($command->getOptions()); + + $promise = $this->s3Client->uploadAsync( + $command->getBucket(), + $command->getFilename(), + $source, + $command->getAcl(), + $options + ); + + return $command->isAsync() ? $promise : $promise->wait(); + } + + /** + * Create a new stream based on the input type. + * + * @param resource|string|StreamInterface $source path to a local file, resource or stream + * + * @return StreamInterface + */ + protected function toStream($source): StreamInterface + { + if (is_string($source)) { + $source = Psr7\try_fopen($source, 'r+'); + } + + return Psr7\stream_for($source); + } +} diff --git a/src/interfaces/Bus.php b/src/interfaces/Bus.php new file mode 100644 index 0000000..bbb6ae7 --- /dev/null +++ b/src/interfaces/Bus.php @@ -0,0 +1,20 @@ +