GetItemsInABucket   A
last analyzed

Complexity

Total Complexity 37

Size/Duplication

Total Lines 195
Duplicated Lines 0 %

Test Coverage

Coverage 92.31%

Importance

Changes 0
Metric Value
wmc 37
eloc 76
dl 0
loc 195
ccs 72
cts 78
cp 0.9231
rs 9.44
c 0
b 0
f 0

5 Methods

Rating   Name   Duplication   Size   Complexity  
B returnItemsFromS3() 0 37 10
A returnItemsFromCache() 0 38 6
C handle() 0 35 12
B returnVersionedItemsFromS3() 0 36 8
A validateParams() 0 3 1
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 Exception;
16
use Matecat\SimpleS3\Commands\CommandHandler;
17
use Matecat\SimpleS3\Helpers\File;
18
19
class GetItemsInABucket extends CommandHandler
20
{
21
    /**
22
     * Get the list of keys in a bucket.
23
     * If 'hydrate' parameter is set to true, an array of hydrated Aws\Result is returned instead.
24
     *
25
     * @param array $params
26
     *
27
     * @return array
28
     * @throws Exception
29
     */
30 18
    public function handle(array $params = []): array
31
    {
32 18
        $bucketName = $params[ 'bucket' ];
33
34
        try {
35 18
            $config = [
36 18
                    'Bucket' => $bucketName,
37 18
            ];
38
39 18
            if (isset($params[ 'prefix' ])) {
40
                // add a final slash to prefix
41 10
                if (false === File::endsWith($params[ 'prefix' ], $this->client->getPrefixSeparator())) {
42 8
                    $params[ 'prefix' ] .= $this->client->getPrefixSeparator();
43
                }
44
45 10
                $config[ 'Delimiter' ] = (isset($params[ 'delimiter' ])) ? $params[ 'delimiter' ] : $this->client->getPrefixSeparator();
46 10
                $config[ 'Prefix' ]    = $params[ 'prefix' ];
47
            }
48
49
            // 1. If 'exclude-cache' is set, return records always from S3
50 18
            if (isset($params[ 'exclude-cache' ]) and true === $params[ 'exclude-cache' ]) {
51 2
                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 16
            if ($this->client->hasCache() and isset($config[ 'Prefix' ])) {
56 7
                return $this->returnItemsFromCache($bucketName, $config, (isset($params[ 'hydrate' ])) ? $params[ 'hydrate' ] : null);
57
            }
58
59
            // 3. Otherwise, return records from S3
60 9
            return $this->returnItemsFromS3($bucketName, $config, (isset($params[ 'hydrate' ])) ? $params[ 'hydrate' ] : null);
61
        } catch (S3Exception $e) {
62
            $this->commandHandlerLogger?->logExceptionAndReturnFalse($e);
63
64
            throw $e;
65
        }
66
    }
67
68
    /**
69
     * @param array $params
70
     *
71
     * @return bool
72
     */
73 18
    public function validateParams(array $params = []): bool
74
    {
75 18
        return (isset($params[ 'bucket' ]));
76
    }
77
78
    /**
79
     * @param string    $bucketName
80
     * @param array     $config
81
     * @param bool|null $hydrate
82
     *
83
     * @return array
84
     */
85 7
    protected function returnItemsFromCache(string $bucketName, array $config, ?bool $hydrate = null): array
86
    {
87 7
        $itemsFromCache = $this->client->getCache()->search($bucketName, $config[ 'Prefix' ]);
88
89
        // no data was found, try to retrieve data from S3
90 7
        if (count($itemsFromCache) == 0) {
91
            return $this->returnItemsFromS3($bucketName, $config, $hydrate);
92
        }
93
94
        // no hydrate, simply return the array of keys stored in redis
95 7
        if (null == $hydrate) {
96 5
            $this->commandHandlerLogger?->log($this, sprintf('Files of \'%s\' bucket were successfully obtained from CACHE', $bucketName));
97
98 5
            return $itemsFromCache;
99
        }
100
101
        // hydrate the key with the entire AWS\Result Object
102 2
        $items = [];
103 2
        foreach ($itemsFromCache as $key) {
104 2
            $version     = null;
105 2
            $originalKey = $key;
106
107 2
            if (str_contains($key, '<VERSION_ID:')) {
108 1
                $v       = explode('<VERSION_ID:', $key);
109 1
                $version = str_replace('>', '', $v[ 1 ]);
110 1
                $key     = $v[ 0 ];
111
            }
112
113 2
            if ($this->client->hasEncoder()) {
114 2
                $key = $this->client->getEncoder()->decode($key);
115
            }
116
117 2
            $items[ $originalKey ] = $this->client->getItem(['bucket' => $bucketName, 'key' => $key, 'version' => $version]);
118
        }
119
120 2
        $this->commandHandlerLogger?->log($this, sprintf('Files of \'%s\' bucket were successfully obtained from CACHE', $bucketName));
121
122 2
        return $items;
123
    }
124
125
    /**
126
     * @param string    $bucketName
127
     * @param array     $config
128
     * @param bool|null $hydrate
129
     *
130
     * @return array
131
     */
132 11
    protected function returnItemsFromS3(string $bucketName, array $config, ?bool $hydrate = null): array
133
    {
134 11
        if ($this->client->isBucketVersioned(['bucket' => $bucketName])) {
135 1
            return $this->returnVersionedItemsFromS3($bucketName, $config, $hydrate);
136
        }
137
138 11
        $resultPaginator = $this->client->getConn()->getPaginator('ListObjects', $config);
139 11
        $items           = [];
140
141 11
        foreach ($resultPaginator as $result) {
142 11
            if (is_array($contents = $result->get('Contents'))) {
143 9
                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...
144 9
                    $key = $contents[ $i ][ 'Key' ];
145
146 9
                    if (false === File::endsWith($key, $this->client->getPrefixSeparator())) {
147 9
                        if ($this->client->hasEncoder()) {
148 6
                            $key = $this->client->getEncoder()->decode($key);
149
                        }
150
151 9
                        if (null != $hydrate and true === $hydrate) {
152 2
                            $items[ $key ] = $this->client->getItem(['bucket' => $bucketName, 'key' => $key]);
153
                        } else {
154 7
                            $items[] = $key;
155
                        }
156
157
                        // send to cache, just to be sure that S3 is syncronized with cache
158 9
                        if ($this->client->hasCache()) {
159 6
                            $this->client->getCache()->set($bucketName, $contents[ $i ][ 'Key' ], $this->client->getItem(['bucket' => $bucketName, 'key' => $key]));
160
                        }
161
                    }
162
                }
163
            }
164
        }
165
166 11
        $this->commandHandlerLogger?->log($this, sprintf('Files were successfully obtained from \'%s\' bucket', $bucketName));
167
168 11
        return $items;
169
    }
170
171
    /**
172
     * @param string    $bucketName
173
     * @param array     $config
174
     * @param bool|null $hydrate
175
     *
176
     * @return array
177
     */
178 1
    protected function returnVersionedItemsFromS3(string $bucketName, array $config, ?bool $hydrate = null): array
179
    {
180 1
        $results = $this->client->getConn()->listObjectVersions($config);
181 1
        $items   = [];
182
183 1
        if (false === isset($results[ 'Versions' ])) {
184
            return $items;
185
        }
186
187 1
        foreach ($results[ 'Versions' ] as $result) {
188 1
            $key     = $result[ 'Key' ];
189 1
            $version = $result[ 'VersionId' ];
190
191 1
            if (false === File::endsWith($key, $this->client->getPrefixSeparator())) {
192 1
                if ($this->client->hasEncoder()) {
193 1
                    $key = $this->client->getEncoder()->decode($key);
194
                }
195
196 1
                $index = $key . '<VERSION_ID:' . $version . '>';
197
198 1
                if (null != $hydrate and true === $hydrate) {
199
                    $items[ $index ] = $this->client->getItem(['bucket' => $bucketName, 'key' => $key, 'version' => $version]);
200
                } else {
201 1
                    $items[] = $index;
202
                }
203
204
                // send to cache, just to be sure that S3 is syncronized with cache
205 1
                if ($this->client->hasCache()) {
206 1
                    $this->client->getCache()->set($bucketName, $result[ 'Key' ], $this->client->getItem(['bucket' => $bucketName, 'key' => $key, 'version' => $version]), $version);
207
                }
208
            }
209
        }
210
211 1
        $this->commandHandlerLogger?->log($this, sprintf('Files (versioned) were successfully obtained from \'%s\' bucket', $bucketName));
212
213 1
        return $items;
214
    }
215
}
216