CopyInBatch   A
last analyzed

Complexity

Total Complexity 15

Size/Duplication

Total Lines 128
Duplicated Lines 0 %

Test Coverage

Coverage 81.67%

Importance

Changes 0
Metric Value
wmc 15
eloc 55
dl 0
loc 128
ccs 49
cts 60
cp 0.8167
rs 10
c 0
b 0
f 0

2 Methods

Rating   Name   Duplication   Size   Complexity  
C handle() 0 87 13
A validateParams() 0 5 2
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\CommandInterface;
15
use Aws\CommandPool;
16
use Aws\Exception\AwsException;
17
use Aws\ResultInterface;
18
use Exception;
19
use InvalidArgumentException;
20
21
class CopyInBatch extends CopyItem
22
{
23
    /**
24
     * Copy in batch items from a bucket to another one.
25
     * For a complete reference:
26
     * https://docs.aws.amazon.com/cli/latest/reference/s3api/copy-object.html?highlight=copy
27
     *
28
     * @param array $params
29
     *
30
     * Example:
31
     * $input = [
32
     *      'source_bucket' => 'ORIGINAL-BUCKET',
33
     *      'target_bucket' => 'TARGET-BUCKET', (OPTIONAL)
34
     *      'files' => [
35
     *          'source' => [
36
     *              'keyname-1',
37
     *              'keyname-2',
38
     *          ],
39
     *          'target' => [ (OPTIONAL)
40
     *              'keyname-3',
41
     *              'keyname-4',
42
     *          ],
43
     *      ],
44
     * ];
45
     *
46
     * @return bool
47
     * @throws Exception
48
     */
49 4
    public function handle(array $params = []): bool
50
    {
51 4
        if (isset($params[ 'target_bucket' ])) {
52 3
            $this->client->createBucketIfItDoesNotExist(['bucket' => $params[ 'target_bucket' ]]);
53
        }
54
55 4
        if (empty($params[ 'files' ][ 'source' ])) {
56
            throw new InvalidArgumentException('source files array cannot be empty.');
57
        }
58
59 4
        $commands     = [];
60 4
        $errors       = [];
61 4
        $targetKeys   = [];
62 4
        $targetBucket = (isset($params[ 'target_bucket' ])) ? $params[ 'target_bucket' ] : $params[ 'source_bucket' ];
63
64 4
        foreach ($params[ 'files' ][ 'source' ] as $key => $file) {
65 4
            $targetKey    = (isset($params[ 'files' ][ 'target' ][ $key ])) ? $params[ 'files' ][ 'target' ][ $key ] : $file;
66 4
            $sourceBucket = $params[ 'source_bucket' ];
67
68 4
            if ($this->client->hasEncoder()) {
69 2
                $targetKey = $this->client->getEncoder()->encode($targetKey);
70 2
                $file      = $this->client->getEncoder()->encode($file);
71
            }
72
73 4
            $copySource   = $this->getCopySource($sourceBucket, $file);
74 4
            $targetKeys[] = $targetKey;
75
76 4
            $config = [
77 4
                    'Bucket'     => $targetBucket,
78 4
                    'Key'        => $targetKey,
79 4
                    'CopySource' => $copySource,
80 4
            ];
81
82 4
            if ($this->client->isBucketVersioned(['bucket' => $sourceBucket])) {
83
                $version                = $this->client->getCurrentItemVersion(['bucket' => $sourceBucket, 'key' => $params[ 'source' ]]);
84
                $config[ 'CopySource' ] = $copySource . '?versionId=' . $version;
85
            }
86
87 4
            $commands[] = $this->client->getConn()->getCommand('CopyObject', $config);
88
        }
89
90
        try {
91
            // Create a pool and provide an optional array of configuration
92 4
            $pool = new CommandPool($this->client->getConn(), $commands, [
93 4
                    'concurrency' => (isset($params[ 'concurrency' ])) ? $params[ 'concurrency' ] : 25,
94 4
                    'before'      => function (CommandInterface $cmd, $iterKey) {
95 4
                        $this->commandHandlerLogger?->log($this, sprintf('About to send \'%s\'', $iterKey));
96 4
                    },
97
                // Invoke this function for each successful transfer
98 4
                    'fulfilled'   => function (
99 4
                            ResultInterface $result,
100 4
                            $iterKey
101 4
                    ) use ($targetBucket, $targetKeys) {
102 4
                        $this->commandHandlerLogger?->log($this, sprintf('Completed copy of \'%s\'', $targetKeys[ $iterKey ]));
103
104 4
                        if ($this->client->hasCache()) {
105 2
                            $this->client->getCache()->set($targetBucket, $targetKeys[ $iterKey ], '');
106
                        }
107 4
                    },
108
                // Invoke this function for each failed transfer
109 4
                    'rejected'    => function (
110 4
                            AwsException $reason
111 4
                    ) use (&$errors) {
112
                        $errors[] = $reason;
113
114
                        $this->commandHandlerLogger?->logExceptionAndReturnFalse($reason);
115
116
                        throw $reason;
117 4
                    },
118 4
            ]);
119
120
            // Initiate the pool transfers and waits it ends
121 4
            $pool->promise()->wait();
122
123 4
            if (count($errors) === 0) {
124 4
                $this->commandHandlerLogger?->log($this, sprintf('Copy in batch from \'%s\' to \'%s\' was succeded without errors', $params[ 'source_bucket' ], $targetBucket));
125
126 4
                return true;
127
            }
128
129
            $this->commandHandlerLogger?->log($this, sprintf('Something went wrong during copying in batch from \'%s\' to \'%s\'', $params[ 'source_bucket' ], (isset($params[ 'target_bucket' ])) ? $params[ 'target_bucket' ] : $params[ 'source_bucket' ]), 'warning');
130
131
            return false;
132
        } catch (Exception $e) {
133
            $this->commandHandlerLogger?->logExceptionAndReturnFalse($e);
134
135
            throw $e;
136
        }
137
    }
138
139
    /**
140
     * @param array $params
141
     *
142
     * @return bool
143
     */
144 4
    public function validateParams(array $params = []): bool
145
    {
146 4
        return (
147 4
                isset($params[ 'source_bucket' ]) and
148 4
                isset($params[ 'files' ][ 'source' ])
149 4
        );
150
    }
151
}
152