Completed
Push — 2.0 ( 6cd6ae...d9081a )
by Rob
11s
created

AwsS3Resolver::setObjectUrlOption()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

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