Issues (45)

src/Commands/Handlers/GetItemsInABucket.php (4 issues)

1
<?php
2
/**
3
 *  This file is part of the Simple S3 package.
4
 *
5
 * (c) Mauro Cassani<https://github.com/mauretto78>
6
 *
7
 * For the full copyright and license information, please view the LICENSE
8
 * file that was distributed with this source code.
9
 *
10
 */
11
12
namespace Matecat\SimpleS3\Commands\Handlers;
13
14
use Aws\S3\Exception\S3Exception;
15
use Matecat\SimpleS3\Commands\CommandHandler;
16
use Matecat\SimpleS3\Helpers\File;
17
18
class GetItemsInABucket extends CommandHandler
19
{
20
    /**
21
     * Get the list of keys in a bucket.
22
     * If 'hydrate' parameter is set to true, an array of hydrated Aws\Result is returned instead.
23
     *
24
     * @param array $params
25
     *
26
     * @return array|mixed
27
     * @throws \Exception
28
     */
29
    public function handle($params = [])
30
    {
31
        $bucketName = $params['bucket'];
32
33
        try {
34
            $config = [
35
                'Bucket' => $bucketName,
36
            ];
37
38
            if (isset($params['prefix'])) {
39
40
                // add a final slash to prefix
41
                if (false === File::endsWith($params['prefix'], $this->client->getPrefixSeparator())) {
42
                    $params['prefix'] .= $this->client->getPrefixSeparator();
43
                }
44
45
                $config['Delimiter'] = (isset($params['delimiter'])) ? $params['delimiter'] : $this->client->getPrefixSeparator();
46
                $config['Prefix'] = $params['prefix'];
47
            }
48
49
            // 1. If 'exclude-cache' is set, return records always from S3
50
            if (isset($params['exclude-cache']) and true === $params['exclude-cache']) {
51
                return $this->returnItemsFromS3($bucketName, $config, (isset($params['hydrate'])) ? $params['hydrate'] : null);
52
            }
53
54
            // 2. If the cache is set and there is a prefix, return records from cache
55
            if ($this->client->hasCache() and isset($config['Prefix'])) {
56
                return $this->returnItemsFromCache($bucketName, $config, (isset($params['hydrate'])) ? $params['hydrate'] : null);
57
            }
58
59
            // 3. Otherwise, return records from S3
60
            return $this->returnItemsFromS3($bucketName, $config, (isset($params['hydrate'])) ? $params['hydrate'] : null);
61
        } catch (S3Exception $e) {
62
            if (null !== $this->commandHandlerLogger) {
63
                $this->commandHandlerLogger->logExceptionAndReturnFalse($e);
64
            }
65
66
            throw $e;
67
        }
68
    }
69
70
    /**
71
     * @param array $params
72
     *
73
     * @return bool
74
     */
75
    public function validateParams($params = [])
76
    {
77
        return (isset($params['bucket']));
78
    }
79
80
    /**
81
     * @param string $bucketName
82
     * @param array $config
83
     * @param null $hydrate
0 ignored issues
show
Documentation Bug introduced by
Are you sure the doc-type for parameter $hydrate is correct as it would always require null to be passed?
Loading history...
84
     *
85
     * @return array
86
     */
87
    protected function returnItemsFromCache($bucketName, $config, $hydrate = null)
88
    {
89
        $itemsFromCache = $this->client->getCache()->search($bucketName, $config['Prefix']);
90
91
        // no data was found, try to retrieve data from S3
92
        if (count($itemsFromCache) == 0) {
93
            return $this->returnItemsFromS3($bucketName, $config, $hydrate);
94
        }
95
96
        // no hydrate, simply return the array of keys stored in redis
97
        if (null == $hydrate) {
0 ignored issues
show
The condition null == $hydrate is always true.
Loading history...
98
            if (null !== $this->commandHandlerLogger) {
99
                $this->commandHandlerLogger->log($this, sprintf('Files of \'%s\' bucket were successfully obtained from CACHE', $bucketName));
100
            }
101
102
            return $itemsFromCache;
103
        }
104
105
        // hydrate the key with the entire AWS\Result Object
106
        $items = [];
107
        foreach ($itemsFromCache as $key) {
108
            $version = null;
109
            $originalKey = $key;
110
111
            if (strpos($key, '<VERSION_ID:') !== false) {
112
                $v = explode('<VERSION_ID:', $key);
113
                $version = str_replace('>', '', $v[1]);
114
                $key = $v[0];
115
            }
116
117
            if ($this->client->hasEncoder()) {
118
                $key = $this->client->getEncoder()->decode($key);
119
            }
120
121
            $items[$originalKey] = $this->client->getItem(['bucket' => $bucketName, 'key' => $key, 'version' => $version]);
122
        }
123
124
        if (null !== $this->commandHandlerLogger) {
125
            $this->commandHandlerLogger->log($this, sprintf('Files of \'%s\' bucket were successfully obtained from CACHE', $bucketName));
126
        }
127
128
        return $items;
129
    }
130
131
    /**
132
     * @param string $bucketName
133
     * @param array $config
134
     *
135
     * @return array
136
     */
137
    protected function returnItemsFromS3($bucketName, $config, $hydrate = null)
138
    {
139
        if ($this->client->isBucketVersioned(['bucket' => $bucketName])) {
140
            return $this->returnVersionedItemsFromS3($bucketName, $config, $hydrate);
141
        }
142
143
        $resultPaginator = $this->client->getConn()->getPaginator('ListObjects', $config);
144
        $items = [];
145
146
        foreach ($resultPaginator as $result) {
147
            if (is_array($contents = $result->get('Contents'))) {
148
                for ($i = 0; $i < count($contents); $i++) {
0 ignored issues
show
Performance Best Practice introduced by
It seems like you are calling the size function count() as part of the test condition. You might want to compute the size beforehand, and not on each iteration.

If the size of the collection does not change during the iteration, it is generally a good practice to compute it beforehand, and not on each iteration:

for ($i=0; $i<count($array); $i++) { // calls count() on each iteration
}

// Better
for ($i=0, $c=count($array); $i<$c; $i++) { // calls count() just once
}
Loading history...
149
                    $key = $contents[$i]['Key'];
150
151
                    if (false === File::endsWith($key, $this->client->getPrefixSeparator())) {
152
                        if ($this->client->hasEncoder()) {
153
                            $key = $this->client->getEncoder()->decode($key);
154
                        }
155
156
                        if (null != $hydrate and true === $hydrate) {
157
                            $items[$key] = $this->client->getItem(['bucket' => $bucketName, 'key' => $key]);
158
                        } else {
159
                            $items[] = $key;
160
                        }
161
162
                        // send to cache, just to be sure that S3 is syncronized with cache
163
                        if ($this->client->hasCache()) {
164
                            $this->client->getCache()->set($bucketName, $contents[$i]['Key'], $this->client->getItem(['bucket' => $bucketName, 'key' => $key]));
165
                        }
166
                    }
167
                }
168
            }
169
        }
170
171
        if (null !== $this->commandHandlerLogger) {
172
            $this->commandHandlerLogger->log($this, sprintf('Files were successfully obtained from \'%s\' bucket', $bucketName));
173
        }
174
175
        return $items;
176
    }
177
178
    /**
179
     * @param string $bucketName
180
     * @param array $config
181
     * @param null $hydrate
0 ignored issues
show
Documentation Bug introduced by
Are you sure the doc-type for parameter $hydrate is correct as it would always require null to be passed?
Loading history...
182
     *
183
     * @return array
184
     */
185
    protected function returnVersionedItemsFromS3($bucketName, $config, $hydrate = null)
186
    {
187
        $results = $this->client->getConn()->listObjectVersions($config);
188
        $items = [];
189
190
        if (false === isset($results['Versions'])) {
191
            return $items;
192
        }
193
194
        foreach ($results['Versions'] as $result) {
195
            $key = $result['Key'];
196
            $version = $result['VersionId'];
197
198
            if (false === File::endsWith($key, $this->client->getPrefixSeparator())) {
199
                if ($this->client->hasEncoder()) {
200
                    $key = $this->client->getEncoder()->decode($key);
201
                }
202
203
                $index = $key.'<VERSION_ID:'.$version.'>';
204
205
                if (null != $hydrate and true === $hydrate) {
206
                    $items[$index] = $this->client->getItem(['bucket' => $bucketName, 'key' => $key, 'version' => $version]);
207
                } else {
208
                    $items[] = $index;
209
                }
210
211
                // send to cache, just to be sure that S3 is syncronized with cache
212
                if ($this->client->hasCache()) {
213
                    $this->client->getCache()->set($bucketName, $result['Key'], $this->client->getItem(['bucket' => $bucketName, 'key' => $key, 'version' => $version]), $version);
214
                }
215
            }
216
        }
217
218
        if (null !== $this->commandHandlerLogger) {
219
            $this->commandHandlerLogger->log($this, sprintf('Files (versioned) were successfully obtained from \'%s\' bucket', $bucketName));
220
        }
221
222
        return $items;
223
    }
224
}
225