AwsS3Resolver::remove()   B
last analyzed

Complexity

Conditions 9
Paths 8

Size

Total Lines 46

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
c 0
b 0
f 0
dl 0
loc 46
rs 7.6226
cc 9
nc 8
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
    public function setLogger(LoggerInterface $logger)
77
    {
78
        $this->logger = $logger;
79
    }
80
81
    /**
82
     * @param string $cachePrefix
83
     */
84
    public function setCachePrefix($cachePrefix)
85
    {
86
        $this->cachePrefix = $cachePrefix;
87
    }
88
89
    /**
90
     * {@inheritdoc}
91
     */
92
    public function isStored($path, $filter)
93
    {
94
        return $this->objectExists($this->getObjectPath($path, $filter));
95
    }
96
97
    /**
98
     * {@inheritdoc}
99
     */
100
    public function resolve($path, $filter)
101
    {
102
        return $this->getObjectUrl($this->getObjectPath($path, $filter));
103
    }
104
105
    /**
106
     * {@inheritdoc}
107
     */
108
    public function store(BinaryInterface $binary, $path, $filter)
109
    {
110
        $objectPath = $this->getObjectPath($path, $filter);
111
112
        try {
113
            $this->storage->putObject(
114
                array_merge(
115
                    $this->putOptions,
116
                    [
117
                        'ACL' => $this->acl,
118
                        'Bucket' => $this->bucket,
119
                        'Key' => $objectPath,
120
                        'Body' => $binary->getContent(),
121
                        'ContentType' => $binary->getMimeType(),
122
                    ]
123
                )
124
            );
125
        } catch (\Exception $e) {
126
            $this->logError('The object could not be created on Amazon S3.', [
127
                'objectPath' => $objectPath,
128
                'filter' => $filter,
129
                'bucket' => $this->bucket,
130
                'exception' => $e,
131
            ]);
132
133
            throw new NotStorableException('The object could not be created on Amazon S3.', null, $e);
134
        }
135
    }
136
137
    /**
138
     * {@inheritdoc}
139
     */
140
    public function remove(array $paths, array $filters)
141
    {
142
        if (empty($paths) && empty($filters)) {
143
            return;
144
        }
145
146
        if (empty($paths)) {
147
            try {
148
                $this->storage->deleteMatchingObjects($this->bucket, null, sprintf(
149
                    '/%s/i',
150
                    implode('|', $filters)
151
                ));
152
            } catch (\Exception $e) {
153
                $this->logError('The objects could not be deleted from Amazon S3.', [
154
                    'filter' => implode(', ', $filters),
155
                    'bucket' => $this->bucket,
156
                    'exception' => $e,
157
                ]);
158
            }
159
160
            return;
161
        }
162
163
        foreach ($filters as $filter) {
164
            foreach ($paths as $path) {
165
                $objectPath = $this->getObjectPath($path, $filter);
166
                if (!$this->objectExists($objectPath)) {
167
                    continue;
168
                }
169
170
                try {
171
                    $this->storage->deleteObject([
172
                        'Bucket' => $this->bucket,
173
                        'Key' => $objectPath,
174
                    ]);
175
                } catch (\Exception $e) {
176
                    $this->logError('The object could not be deleted from Amazon S3.', [
177
                        'objectPath' => $objectPath,
178
                        'filter' => $filter,
179
                        'bucket' => $this->bucket,
180
                        'exception' => $e,
181
                    ]);
182
                }
183
            }
184
        }
185
    }
186
187
    /**
188
     * Sets a single option to be passed when retrieving an objects URL.
189
     *
190
     * If the option is already set, it will be overwritten.
191
     *
192
     * @see \Aws\S3\S3Client::getObjectUrl() for available options
193
     *
194
     * @param string $key   The name of the option
195
     * @param mixed  $value The value to be set
196
     *
197
     * @return $this
198
     */
199
    public function setGetOption($key, $value)
200
    {
201
        $this->getOptions[$key] = $value;
202
203
        return $this;
204
    }
205
206
    /**
207
     * Sets a single option to be passed when saving an object.
208
     *
209
     * If the option is already set, it will be overwritten.
210
     *
211
     * @see \Aws\S3\S3Client::putObject() for available options
212
     *
213
     * @param string $key   The name of the option
214
     * @param mixed  $value The value to be set
215
     *
216
     * @return $this
217
     */
218
    public function setPutOption($key, $value)
219
    {
220
        $this->putOptions[$key] = $value;
221
222
        return $this;
223
    }
224
225
    /**
226
     * Returns the object path within the bucket.
227
     *
228
     * @param string $path   The base path of the resource
229
     * @param string $filter The name of the imagine filter in effect
230
     *
231
     * @return string The path of the object on S3
232
     */
233
    protected function getObjectPath($path, $filter)
234
    {
235
        $path = $this->cachePrefix
236
            ? sprintf('%s/%s/%s', $this->cachePrefix, $filter, $path)
237
            : sprintf('%s/%s', $filter, $path);
238
239
        return str_replace('//', '/', $path);
240
    }
241
242
    /**
243
     * Returns the URL for an object saved on Amazon S3.
244
     *
245
     * @param string $path
246
     *
247
     * @return string
248
     */
249
    protected function getObjectUrl($path)
250
    {
251
        return $this->storage->getObjectUrl($this->bucket, $path, 0, $this->getOptions);
252
    }
253
254
    /**
255
     * Checks whether an object exists.
256
     *
257
     * @param string $objectPath
258
     *
259
     * @return bool
260
     */
261
    protected function objectExists($objectPath)
262
    {
263
        return $this->storage->doesObjectExist($this->bucket, $objectPath);
264
    }
265
266
    /**
267
     * @param mixed $message
268
     */
269
    protected function logError($message, array $context = [])
270
    {
271
        if ($this->logger) {
272
            $this->logger->error($message, $context);
273
        }
274
    }
275
}
276