Passed
Push — v9 ( 345353...555fde )
by Georges
04:49
created

Driver::decodeDocument()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 2
nc 1
nop 1
dl 0
loc 5
rs 10
c 1
b 0
f 0
1
<?php
2
3
/**
4
 *
5
 * This file is part of Phpfastcache.
6
 *
7
 * @license MIT License (MIT)
8
 *
9
 * For full copyright and license information, please see the docs/CREDITS.txt and LICENCE files.
10
 *
11
 * @author Georges.L (Geolim4)  <[email protected]>
12
 * @author Contributors  https://github.com/PHPSocialNetwork/phpfastcache/graphs/contributors
13
 */
14
declare(strict_types=1);
15
16
namespace Phpfastcache\Drivers\Dynamodb;
17
18
use Aws\Sdk as AwsSdk;
19
use Aws\DynamoDb\DynamoDbClient as AwsDynamoDbClient;
20
use Aws\DynamoDb\Marshaler as AwsMarshaler;
21
22
use Phpfastcache\Cluster\AggregatablePoolInterface;
23
use Phpfastcache\Config\ConfigurationOption;
24
use Phpfastcache\Core\Item\ExtendedCacheItemInterface;
25
use Phpfastcache\Core\Pool\ExtendedCacheItemPoolInterface;
26
use Phpfastcache\Core\Pool\TaggableCacheItemPoolTrait;
27
use Phpfastcache\Entities\DriverStatistic;
28
use Phpfastcache\Exceptions\PhpfastcacheLogicException;
29
use Psr\Http\Message\UriInterface;
30
31
/**
32
 * Class Driver
33
 * @property Config $config
34
 * @property AwsDynamoDbClient $instance
35
 * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
36
 */
37
class Driver implements ExtendedCacheItemPoolInterface, AggregatablePoolInterface
38
{
39
    use TaggableCacheItemPoolTrait;
40
41
    protected AwsSdk $awsSdk;
42
43
    protected AwsMarshaler $marshaler;
44
45
    /**
46
     * @return bool
47
     */
48
    public function driverCheck(): bool
49
    {
50
        return \class_exists(AwsSdk::class) && \class_exists(AwsDynamoDbClient::class);
51
    }
52
53
    /**
54
     * @return bool
55
     */
56
    protected function driverConnect(): bool
57
    {
58
        $this->awsSdk = new AwsSdk([
59
            'endpoint'   => $this->getConfig()->getEndpoint(),
60
            'region'   => $this->getConfig()->getRegion(),
61
            'version'  => $this->getConfig()->getVersion(),
62
            'debug'  => $this->getConfig()->isDebugEnabled(),
63
        ]);
64
        $this->instance = $this->awsSdk->createDynamoDb();
65
        $this->marshaler = new AwsMarshaler();
66
67
        if (!\count($this->instance->listTables(['TableNames' => [$this->getConfig()->getTable()]])->get('TableNames'))) {
0 ignored issues
show
Bug introduced by
It seems like $this->instance->listTab...))))->get('TableNames') can also be of type null; however, parameter $value of count() does only seem to accept Countable|array, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

67
        if (!\count(/** @scrutinizer ignore-type */ $this->instance->listTables(['TableNames' => [$this->getConfig()->getTable()]])->get('TableNames'))) {
Loading history...
68
            $this->createTable();
69
        }
70
71
        return true;
72
    }
73
74
    /**
75
     * @param ExtendedCacheItemInterface $item
76
     * @return bool
77
     * @throws PhpfastcacheLogicException
78
     */
79
    protected function driverWrite(ExtendedCacheItemInterface $item): bool
80
    {
81
        $awsItem = $this->marshaler->marshalItem(
82
            $this->encodeDocument($this->driverPreWrap($item, true))
83
        );
84
85
        $result = $this->instance->putItem([
86
            'TableName' => $this->getConfig()->getTable(),
87
            'Item' => $awsItem
88
        ]);
89
90
        return ($result->get('@metadata')['statusCode'] ?? null) === 200;
91
    }
92
93
    /**
94
     * @param ExtendedCacheItemInterface $item
95
     * @return null|array
96
     * @throws \Exception
97
     */
98
    protected function driverRead(ExtendedCacheItemInterface $item): ?array
99
    {
100
        $key = $this->marshaler->marshalItem([
101
            $this->getConfig()->getPartitionKey() => $item->getKey()
102
        ]);
103
104
        $result = $this->instance->getItem([
105
            'TableName' => $this->getConfig()->getTable(),
106
            'Key' => $key
107
        ]);
108
109
        $awsItem = $result->get('Item');
110
111
        if ($awsItem !== null) {
112
            return $this->decodeDocument(
113
                $this->marshaler->unmarshalItem($awsItem)
0 ignored issues
show
Bug introduced by
It seems like $this->marshaler->unmarshalItem($awsItem) can also be of type stdClass; however, parameter $data of Phpfastcache\Drivers\Dyn...river::decodeDocument() does only seem to accept array, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

113
                /** @scrutinizer ignore-type */ $this->marshaler->unmarshalItem($awsItem)
Loading history...
114
            );
115
        }
116
117
        return null;
118
    }
119
120
    /**
121
     * @param ExtendedCacheItemInterface $item
122
     * @return bool
123
     */
124
    protected function driverDelete(ExtendedCacheItemInterface $item): bool
125
    {
126
        $key = $this->marshaler->marshalItem([
127
            $this->getConfig()->getPartitionKey() => $item->getKey()
128
        ]);
129
130
        $result = $this->instance->deleteItem([
131
            'TableName' => $this->getConfig()->getTable(),
132
            'Key' => $key
133
        ]);
134
135
        return ($result->get('@metadata')['statusCode'] ?? null) === 200;
136
    }
137
138
    /**
139
     * @return bool
140
     */
141
    protected function driverClear(): bool
142
    {
143
        $params = [
144
            'TableName' => $this->getConfig()->getTable(),
145
        ];
146
147
        $result = $this->instance->deleteTable($params);
148
149
        $this->instance->waitUntil('TableNotExists', $params);
150
151
        $this->createTable();
152
153
        return ($result->get('@metadata')['statusCode'] ?? null) === 200;
154
    }
155
156
    protected function createTable() :void
157
    {
158
        $params = [
159
            'TableName' => $this->getConfig()->getTable(),
160
            'KeySchema' => [
161
                [
162
                    'AttributeName' => $this->getConfig()->getPartitionKey(),
163
                    'KeyType' => 'HASH'
164
                ]
165
            ],
166
            'AttributeDefinitions' => [
167
                [
168
                    'AttributeName' => $this->getConfig()->getPartitionKey(),
169
                    'AttributeType' => 'S'
170
                ],
171
            ],
172
            'ProvisionedThroughput' => [
173
                'ReadCapacityUnits' => 10,
174
                'WriteCapacityUnits' => 10
175
            ]
176
        ];
177
178
        $this->instance->createTable($params);
179
        $this->instance->waitUntil('TableExists', $params);
180
    }
181
182
    public function getStats(): DriverStatistic
183
    {
184
        /** @var UriInterface $endpoint */
185
        $endpoint = $this->instance->getEndpoint();
186
        $table = $this->instance->describeTable(['TableName' => $this->getConfig()->getTable()])->get('Table');
187
188
        $info = \sprintf(
189
            'Dynamo server "%s" | Table "%s" with %d item(s) stored',
190
            $endpoint->getHost(),
191
            $table['TableName'] ?? 'Unknown table name',
192
            $table['ItemCount'] ?? 'Unknown item count',
193
        );
194
195
        $data = [
196
            'dynamoEndpoint' => $endpoint,
197
            'dynamoTable' => $table,
198
            'dynamoConfig' => $this->instance->getConfig(),
199
            'dynamoApi' => $this->instance->getApi()->toArray(),
200
        ];
201
202
        return (new DriverStatistic())
203
            ->setData(implode(', ', array_keys($this->itemInstances)))
204
            ->setInfo($info)
205
            ->setRawData($data)
206
            ->setSize($data['dynamoTable']['TableSizeBytes'] ?? 0);
207
    }
208
209
    protected function encodeDocument(array $data): array
210
    {
211
        $data[self::DRIVER_DATA_WRAPPER_INDEX] = $this->encode($data[self::DRIVER_DATA_WRAPPER_INDEX]);
212
213
        return $data;
214
    }
215
216
    protected function decodeDocument(array $data): array
217
    {
218
        $data[self::DRIVER_DATA_WRAPPER_INDEX] = $this->decode($data[self::DRIVER_DATA_WRAPPER_INDEX]);
219
220
        return $data;
221
    }
222
223
    public function getConfig() : Config
224
    {
225
        return $this->config;
226
    }
227
}
228