Completed
Pull Request — master (#732)
by 12345
03:41
created

AwsS3Resolver   A

Complexity

Total Complexity 25

Size/Duplication

Total Lines 280
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 4

Importance

Changes 2
Bugs 1 Features 0
Metric Value
wmc 25
c 2
b 1
f 0
lcom 1
cbo 4
dl 0
loc 280
rs 10

14 Methods

Rating   Name   Duplication   Size   Complexity  
A setLogger() 0 4 1
A setCachePrefix() 0 4 1
A isStored() 0 4 1
A resolve() 0 4 1
A objectExists() 0 4 1
A setObjectUrlOption() 0 4 1
A getObjectUrl() 0 4 1
A __construct() 0 8 1
B store() 0 28 2
C remove() 0 46 9
A setGetOption() 0 6 1
A setPutOption() 0 6 1
A getObjectPath() 0 8 2
A logError() 0 6 2
1
<?php
2
3
namespace Liip\ImagineBundle\Imagine\Cache\Resolver;
4
5
use Aws\S3\S3Client;
6
use Liip\ImagineBundle\Binary\BinaryInterface;
7
use Liip\ImagineBundle\Exception\Imagine\Cache\Resolver\NotStorableException;
8
use Psr\Log\LoggerInterface;
9
10
class AwsS3Resolver implements ResolverInterface
11
{
12
    /**
13
     * @var S3Client
14
     */
15
    protected $storage;
16
17
    /**
18
     * @var string
19
     */
20
    protected $bucket;
21
22
    /**
23
     * @var string
24
     */
25
    protected $acl;
26
27
    /**
28
     * @var array
29
     */
30
    protected $getOptions;
31
32
    /**
33
     * Object options added to PUT requests.
34
     *
35
     * @var array
36
     */
37
    protected $putOptions;
38
39
    /**
40
     * @var LoggerInterface
41
     */
42
    protected $logger;
43
44
    /**
45
     * @var string
46
     */
47
    protected $cachePrefix;
48
49
    /**
50
     * Constructs a cache resolver storing images on Amazon S3.
51
     *
52
     * @param S3Client $storage    The Amazon S3 storage API. It's required to know authentication information.
53
     * @param string   $bucket     The bucket name to operate on.
54
     * @param string   $acl        The ACL to use when storing new objects. Default: owner read/write, public read
55
     * @param array    $getOptions A list of options to be passed when retrieving the object url from Amazon S3.
56
     * @param array    $putOptions A list of options to be passed when saving the object to Amazon S3.
57
     */
58
    public function __construct(S3Client $storage, $bucket, $acl = 'public-read', array $getOptions = array(), $putOptions = array())
59
    {
60
        $this->storage = $storage;
61
        $this->bucket = $bucket;
62
        $this->acl = $acl;
63
        $this->getOptions = $getOptions;
64
        $this->putOptions = $putOptions;
65
    }
66
67
    /**
68
     * @param LoggerInterface $logger
69
     */
70
    public function setLogger(LoggerInterface $logger)
71
    {
72
        $this->logger = $logger;
73
    }
74
75
    /**
76
     * @param string $cachePrefix
77
     */
78
    public function setCachePrefix($cachePrefix)
79
    {
80
        $this->cachePrefix = $cachePrefix;
81
    }
82
83
    /**
84
     * {@inheritdoc}
85
     */
86
    public function isStored($path, $filter)
87
    {
88
        return $this->objectExists($this->getObjectPath($path, $filter));
89
    }
90
91
    /**
92
     * {@inheritdoc}
93
     */
94
    public function resolve($path, $filter)
95
    {
96
        return $this->getObjectUrl($this->getObjectPath($path, $filter));
97
    }
98
99
    /**
100
     * {@inheritdoc}
101
     */
102
    public function store(BinaryInterface $binary, $path, $filter)
103
    {
104
        $objectPath = $this->getObjectPath($path, $filter);
105
106
        try {
107
            $this->storage->putObject(
108
                array_merge(
109
                    $this->putOptions,
110
                    array(
111
                        'ACL' => $this->acl,
112
                        'Bucket' => $this->bucket,
113
                        'Key' => $objectPath,
114
                        'Body' => $binary->getContent(),
115
                        'ContentType' => $binary->getMimeType(),
116
                    )
117
                )
118
            );
119
        } catch (\Exception $e) {
120
            $this->logError('The object could not be created on Amazon S3.', array(
121
                'objectPath' => $objectPath,
122
                'filter' => $filter,
123
                'bucket' => $this->bucket,
124
                'exception' => $e,
125
            ));
126
127
            throw new NotStorableException('The object could not be created on Amazon S3.', null, $e);
128
        }
129
    }
130
131
    /**
132
     * {@inheritdoc}
133
     */
134
    public function remove(array $paths, array $filters)
135
    {
136
        if (empty($paths) && empty($filters)) {
137
            return;
138
        }
139
140
        if (empty($paths)) {
141
            try {
142
                $this->storage->deleteMatchingObjects($this->bucket, null, sprintf(
143
                    '/%s/i',
144
                    implode('|', $filters)
145
                ));
146
            } catch (\Exception $e) {
147
                $this->logError('The objects could not be deleted from Amazon S3.', array(
148
                    'filter' => implode(', ', $filters),
149
                    'bucket' => $this->bucket,
150
                    'exception' => $e,
151
                ));
152
            }
153
154
            return;
155
        }
156
157
        foreach ($filters as $filter) {
158
            foreach ($paths as $path) {
159
                $objectPath = $this->getObjectPath($path, $filter);
160
                if (!$this->objectExists($objectPath)) {
161
                    continue;
162
                }
163
164
                try {
165
                    $this->storage->deleteObject(array(
166
                        'Bucket' => $this->bucket,
167
                        'Key' => $objectPath,
168
                    ));
169
                } catch (\Exception $e) {
170
                    $this->logError('The object could not be deleted from Amazon S3.', array(
171
                        'objectPath' => $objectPath,
172
                        'filter' => $filter,
173
                        'bucket' => $this->bucket,
174
                        'exception' => $e,
175
                    ));
176
                }
177
            }
178
        }
179
    }
180
181
    /**
182
     * Sets a single option to be passed when retrieving an objects URL.
183
     *
184
     * If the option is already set, it will be overwritten.
185
     *
186
     * @see Aws\S3\S3Client::getObjectUrl() for available options.
187
     *
188
     * @param string $key   The name of the option.
189
     * @param mixed  $value The value to be set.
190
     *
191
     * @return AmazonS3Resolver $this
192
     *
193
     * @deprecated Use `setGetOption` instead
194
     */
195
    public function setObjectUrlOption($key, $value)
196
    {
197
        return $this->setGetOption($key, $value);
198
    }
199
200
    /**
201
     * Sets a single option to be passed when retrieving an objects URL.
202
     *
203
     * If the option is already set, it will be overwritten.
204
     *
205
     * @see Aws\S3\S3Client::getObjectUrl() for available options.
206
     *
207
     * @param string $key   The name of the option.
208
     * @param mixed  $value The value to be set.
209
     *
210
     * @return AmazonS3Resolver $this
211
     */
212
    public function setGetOption($key, $value)
213
    {
214
        $this->getOptions[$key] = $value;
215
216
        return $this;
217
    }
218
219
    /**
220
     * Sets a single option to be passed when saving an object.
221
     *
222
     * If the option is already set, it will be overwritten.
223
     *
224
     * @see Aws\S3\S3Client::putObject() for available options.
225
     *
226
     * @param string $key   The name of the option.
227
     * @param mixed  $value The value to be set.
228
     *
229
     * @return AmazonS3Resolver $this
230
     */
231
    public function setPutOption($key, $value)
232
    {
233
        $this->putOptions[$key] = $value;
234
235
        return $this;
236
    }
237
238
    /**
239
     * Returns the object path within the bucket.
240
     *
241
     * @param string $path   The base path of the resource.
242
     * @param string $filter The name of the imagine filter in effect.
243
     *
244
     * @return string The path of the object on S3.
245
     */
246
    protected function getObjectPath($path, $filter)
247
    {
248
        $path = $this->cachePrefix
249
            ? sprintf('%s/%s/%s', $this->cachePrefix, $filter, $path)
250
            : sprintf('%s/%s', $filter, $path);
251
252
        return str_replace('//', '/', $path);
253
    }
254
255
    /**
256
     * Returns the URL for an object saved on Amazon S3.
257
     *
258
     * @param string $path
259
     *
260
     * @return string
261
     */
262
    protected function getObjectUrl($path)
263
    {
264
        return $this->storage->getObjectUrl($this->bucket, $path, 0, $this->getOptions);
265
    }
266
267
    /**
268
     * Checks whether an object exists.
269
     *
270
     * @param string $objectPath
271
     *
272
     * @return bool
273
     */
274
    protected function objectExists($objectPath)
275
    {
276
        return $this->storage->doesObjectExist($this->bucket, $objectPath);
277
    }
278
279
    /**
280
     * @param mixed $message
281
     * @param array $context
282
     */
283
    protected function logError($message, array $context = array())
284
    {
285
        if ($this->logger) {
286
            $this->logger->error($message, $context);
287
        }
288
    }
289
}
290