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 AwsS3Resolver for new SDK version #227

Merged
merged 1 commit into from
Aug 21, 2013
Merged
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
225 changes: 225 additions & 0 deletions Imagine/Cache/Resolver/AwsS3Resolver.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,225 @@
<?php

namespace Liip\ImagineBundle\Imagine\Cache\Resolver;

use Aws\S3\Enum\CannedAcl;
use Aws\S3\S3Client;

use Liip\ImagineBundle\Imagine\Cache\CacheManagerAwareInterface;
use Liip\ImagineBundle\Imagine\Cache\CacheManager;

use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpFoundation\Response;

use Symfony\Component\HttpKernel\Log\LoggerInterface;

class AwsS3Resolver implements ResolverInterface, CacheManagerAwareInterface
{
/**
* @var S3Client
*/
protected $storage;

/**
* @var string
*/
protected $bucket;

/**
* @var string
*/
protected $acl;

/**
* @var CacheManager
*/
protected $cacheManager;

/**
* @var array
*/
protected $objUrlOptions;

/**
* @var LoggerInterface
*/
protected $logger;

/**
* Constructs a cache resolver storing images on Amazon S3.
*
* @param S3Client $storage The Amazon S3 storage API. It's required to know authentication information.
* @param string $bucket The bucket name to operate on.
* @param string $acl The ACL to use when storing new objects. Default: owner read/write, public read
* @param array $objUrlOptions A list of options to be passed when retrieving the object url from Amazon S3.
*/
public function __construct(S3Client $storage, $bucket, $acl = CannedAcl::PUBLIC_READ, array $objUrlOptions = array())
{
$this->storage = $storage;

$this->bucket = $bucket;
$this->acl = $acl;

$this->objUrlOptions = $objUrlOptions;
}

/**
* Sets the logger to be used.
*
* @param LoggerInterface $logger
*/
public function setLogger(LoggerInterface $logger)
{
$this->logger = $logger;
}

/**
* @param CacheManager $cacheManager
*/
public function setCacheManager(CacheManager $cacheManager)
{
$this->cacheManager = $cacheManager;
}

/**
* {@inheritDoc}
*/
public function resolve(Request $request, $path, $filter)
{
$objectPath = $this->getObjectPath($path, $filter);
if ($this->objectExists($objectPath)) {
return new RedirectResponse($this->getObjectUrl($objectPath), 301);
}

return $objectPath;
}

/**
* {@inheritDoc}
*/
public function store(Response $response, $targetPath, $filter)
{
try {
$storageResponse = $this->storage->putObject(array(
'ACL' => $this->acl,
'Bucket' => $this->bucket,
'Key' => $targetPath,
'Body' => $response->getContent(),
));
} catch (\Exception $e) {
if ($this->logger) {
$this->logger->warn('The object could not be created on Amazon S3.', array(
'targetPath' => $targetPath,
'filter' => $filter,
));
}

return $response;
}

$response->setStatusCode(301);
$response->headers->set('Location', $storageResponse->get('ObjectURL'));

return $response;
}

/**
* {@inheritDoc}
*/
public function getBrowserPath($path, $filter, $absolute = false)
{
$objectPath = $this->getObjectPath($path, $filter);
if ($this->objectExists($objectPath)) {
return $this->getObjectUrl($objectPath);
}

return $this->cacheManager->generateUrl($path, $filter, $absolute);
}

/**
* {@inheritDoc}
*/
public function remove($targetPath, $filter)
{
if (!$this->objectExists($targetPath)) {
// A non-existing object to delete: done!
return true;
}

try {
$response = $this->storage->deleteObject(array(
'Bucket' => $this->bucket,
'Key' => $targetPath,
));

return true;
} catch (\Exception $e) {
return false;
}
}

/**
* Sets a single option to be passed when retrieving an objects URL.
*
* If the option is already set, it will be overwritten.
*
* @see Aws\S3\S3Client::getObjectUrl() for available options.
*
* @param string $key The name of the option.
* @param mixed $value The value to be set.
*
* @return AmazonS3Resolver $this
*/
public function setObjectUrlOption($key, $value)
{
$this->objUrlOptions[$key] = $value;

return $this;
}

/**
* {@inheritDoc}
*/
public function clear($cachePrefix)
{
// TODO: implement cache clearing for Amazon S3 service
}

/**
* Returns the object path within the bucket.
*
* @param string $path The base path of the resource.
* @param string $filter The name of the imagine filter in effect.
*
* @return string The path of the object on S3.
*/
protected function getObjectPath($path, $filter)
{
return str_replace('//', '/', $filter.'/'.$path);
}

/**
* Returns the URL for an object saved on Amazon S3.
*
* @param string $targetPath
*
* @return string
*/
protected function getObjectUrl($targetPath)
{
return $this->storage->getObjectUrl($this->bucket, $targetPath, 0, $this->objUrlOptions);
}

/**
* Checks whether an object exists.
*
* @param string $objectPath
*
* @return bool
*/
protected function objectExists($objectPath)
{
return $this->storage->doesObjectExist($this->bucket, $objectPath);
}
}
89 changes: 89 additions & 0 deletions Resources/doc/cache-resolver/aws_s3.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
# AwsS3Resolver

The AwsS3Resolver requires the [aws-sdk-php](https://github.com/aws/aws-sdk-for-php).

You can add the SDK by adding those lines to your `deps` file.

``` ini
[aws-sdk]
git=git://github.com/aws/aws-sdk-php.git
```

Afterwards, you only need to configure some information regarding your AWS account and the bucket.

``` yaml
parameters:
amazon_s3.key: 'your-aws-key'
amazon_s3.secret: 'your-aws-secret'
amazon_s3.bucket: 'your-bucket.example.com'
amazon_s3.region: 'your-bucket-region'
```

Now you can set up the services required:

``` yaml
services:
acme.amazon_s3:
class: Aws\S3\S3Client
factory_class: Aws\S3\S3Client
factory_method: factory
arguments:
-
key: %amazon_s3.key%
secret: %amazon_s3.secret%
region: %amazon_s3.region%

acme.imagine.cache.resolver.amazon_s3:
class: Liip\ImagineBundle\Imagine\Cache\Resolver\AwsS3Resolver
arguments:
- "@acme.amazon_s3"
- "%amazon_s3.bucket%"
tags:
- { name: 'liip_imagine.cache.resolver', resolver: 'amazon_s3' }
```

Now you are ready to use the `AwsS3Resolver` by configuring the bundle.
The following example will configure the resolver is default.

``` yaml
liip_imagine:
cache: 'amazon_s3'
```

If you want to use other buckets for other images, simply alter the parameter names and create additional services!

## Object URL Options

In order to make use of the object URL options, you can simply add a call to the service, to alter those options you need.

``` yaml
services:
acme.imagine.cache.resolver.amazon_s3:
class: Liip\ImagineBundle\Imagine\Cache\Resolver\AwsS3Resolver
arguments:
- "@acme.amazon_s3"
- "%amazon_s3.bucket%"
calls:
# This calls $service->setObjectUrlOption('Scheme', 'https');
- [ setObjectUrlOption, [ 'Scheme', 'https' ] ]
tags:
- { name: 'liip_imagine.cache.resolver', resolver: 'amazon_s3' }
```

You can also use the constructor of the resolver to directly inject multiple options.

``` yaml
services:
acme.imagine.cache.resolver.amazon_s3:
class: Liip\ImagineBundle\Imagine\Cache\Resolver\AwsS3Resolver
arguments:
- "@acme.amazon_s3"
- "%amazon_s3.bucket%"
- "public-read" # Aws\S3\Enum\CannedAcl::PUBLIC_READ (default)
- { Scheme: https }
tags:
- { name: 'liip_imagine.cache.resolver', resolver: 'amazon_s3' }
```

- [Back to cache resolvers](../cache-resolvers.md)
- [Back to the index](../index.md)
1 change: 1 addition & 0 deletions Resources/doc/cache-resolvers.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# Built-In CacheResolver

* [AmazonS3](cache-resolver/amazons3.md)
* [AwsS3](cache-resolver/aws_s3.md) - for SDK version 2
* [CacheResolver](cache-resolver/cache.md)

# Custom cache resolver
Expand Down
13 changes: 13 additions & 0 deletions Tests/Fixtures/CannedAcl.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<?php

namespace Aws\S3\Enum;

class CannedAcl
{
const PRIVATE_ACCESS = 'private';
const PUBLIC_READ = 'public-read';
const PUBLIC_READ_WRITE = 'public-read-write';
const AUTHENTICATED_READ = 'authenticated-read';
const BUCKET_OWNER_READ = 'bucket-owner-read';
const BUCKET_OWNER_FULL_CONTROL = 'bucket-owner-full-control';
}
8 changes: 8 additions & 0 deletions Tests/Fixtures/Model.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<?php

namespace Guzzle\Service\Resource;

class Model
{
public function get($key) { }
}
16 changes: 16 additions & 0 deletions Tests/Fixtures/S3Client.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<?php

namespace Aws\S3;

class S3Client
{
public function doesBucketExist($bucket, $accept403, $options = array()) { }

public function doesObjectExist($bucket, $key, $options = array()) { }

public function putObject($args) { }

public function deleteObject($args) { }

public function getObjectUrl($bucket, $key, $expires = 0, $args = array()) { }
}
Loading