Completed
Push — master ( 7978ee...492a8c )
by
unknown
22:12
created
lib/private/Preview/Storage/ObjectStorePreviewStorage.php 1 patch
Indentation   +157 added lines, -157 removed lines patch added patch discarded remove patch
@@ -26,161 +26,161 @@
 block discarded – undo
26 26
  */
27 27
 class ObjectStorePreviewStorage implements IPreviewStorage {
28 28
 
29
-	/**
30
-	 * @var array<string, array<string, IObjectStore>>
31
-	 */
32
-	private array $objectStoreCache = [];
33
-
34
-	private bool $isMultibucketPreviewDistributionEnabled;
35
-
36
-	public function __construct(
37
-		private readonly PrimaryObjectStoreConfig $objectStoreConfig,
38
-		IConfig $config,
39
-		readonly private PreviewMapper $previewMapper,
40
-	) {
41
-		$this->isMultibucketPreviewDistributionEnabled = $config->getSystemValueBool('objectstore.multibucket.preview-distribution');
42
-	}
43
-
44
-	#[Override]
45
-	public function writePreview(Preview $preview, mixed $stream): int {
46
-		$size = 0;
47
-		$countStream = CountWrapper::wrap($stream, function (int $writtenSize) use (&$size): void {
48
-			$size = $writtenSize;
49
-		});
50
-
51
-		[
52
-			'urn' => $urn,
53
-			'store' => $store,
54
-		] = $this->getObjectStoreInfoForNewPreview($preview);
55
-
56
-		try {
57
-			$store->writeObject($urn, $countStream);
58
-		} catch (\Exception $exception) {
59
-			throw new NotPermittedException('Unable to save preview to object store', previous: $exception);
60
-		}
61
-		return $size;
62
-	}
63
-
64
-	#[Override]
65
-	public function readPreview(Preview $preview): mixed {
66
-		[
67
-			'urn' => $urn,
68
-			'store' => $store,
69
-		] = $this->getObjectStoreInfoForExistingPreview($preview);
70
-
71
-		try {
72
-			return $store->readObject($urn);
73
-		} catch (\Exception $exception) {
74
-			throw new NotPermittedException('Unable to read preview from object store with urn:' . $urn, previous: $exception);
75
-		}
76
-	}
77
-
78
-	#[Override]
79
-	public function deletePreview(Preview $preview): void {
80
-		if (defined('PHPUNIT_RUN') && $preview->getLocationId() === null) {
81
-			// Should only be the case in unit tests when adding dummy previews in the database.
82
-			return;
83
-		}
84
-
85
-		[
86
-			'urn' => $urn,
87
-			'store' => $store,
88
-		] = $this->getObjectStoreInfoForExistingPreview($preview);
89
-
90
-		try {
91
-			$store->deleteObject($urn);
92
-		} catch (\Exception $exception) {
93
-			throw new NotPermittedException('Unable to delete preview from object store', previous: $exception);
94
-		}
95
-	}
96
-
97
-	#[Override]
98
-	public function migratePreview(Preview $preview, SimpleFile $file): void {
99
-		// Just set the Preview::bucket and Preview::objectStore
100
-		$this->getObjectStoreInfoForNewPreview($preview, migration: true);
101
-		$this->previewMapper->update($preview);
102
-	}
103
-
104
-	/**
105
-	 * @return ObjectStoreDefinition
106
-	 */
107
-	private function getObjectStoreInfoForExistingPreview(Preview $preview): array {
108
-		$objectStoreName = $preview->getObjectStoreName();
109
-		$bucketName = $preview->getBucketName();
110
-		assert(!empty($objectStoreName));
111
-		assert(!empty($bucketName));
112
-
113
-		$config = $this->objectStoreConfig->getObjectStoreConfiguration($objectStoreName);
114
-		$config['arguments']['bucket'] = $preview->getBucketName();
115
-		$objectStoreName = $preview->getObjectStoreName();
116
-
117
-		return [
118
-			'urn' => $this->getUrn($preview, $config),
119
-			'store' => $this->getObjectStore($objectStoreName, $config),
120
-		];
121
-	}
122
-
123
-	/**
124
-	 * @return ObjectStoreDefinition
125
-	 */
126
-	private function getObjectStoreInfoForNewPreview(Preview $preview, bool $migration = false): array {
127
-		// When migrating old previews, use the 'root' object store configuration
128
-		$config = $this->objectStoreConfig->getObjectStoreConfiguration($migration ? 'root' : 'preview');
129
-		$objectStoreName = $this->objectStoreConfig->resolveAlias($migration ? 'root' : 'preview');
130
-
131
-		$bucketName = $config['arguments']['bucket'];
132
-		if ($config['arguments']['multibucket']) {
133
-			if ($this->isMultibucketPreviewDistributionEnabled) {
134
-				// Spread the previews on different buckets depending on their corresponding fileId
135
-				$oldLocationArray = str_split(substr(md5((string)$preview->getFileId()), 0, 2));
136
-				$bucketNumber = hexdec('0x' . $oldLocationArray[0]) * 16 + hexdec('0x' . $oldLocationArray[0]);
137
-				$bucketName .= '-preview-' . $bucketNumber;
138
-			} else {
139
-				// Put all previews in the root (0) bucket
140
-				$bucketName .= '0';
141
-			}
142
-		}
143
-		$config['arguments']['bucket'] = $bucketName;
144
-
145
-		// Get the locationId corresponding to the bucketName and objectStoreName, this will create
146
-		// a new one, if no matching location is found in the DB.
147
-		$locationId = $this->previewMapper->getLocationId($bucketName, $objectStoreName);
148
-		$preview->setLocationId($locationId);
149
-		$preview->setObjectStoreName($objectStoreName);
150
-		$preview->setBucketName($bucketName);
151
-
152
-		return [
153
-			'urn' => $this->getUrn($preview, $config),
154
-			'store' => $this->getObjectStore($objectStoreName, $config),
155
-		];
156
-	}
157
-
158
-	private function getObjectStore(string $objectStoreName, array $config): IObjectStore {
159
-		$bucketName = $config['arguments']['bucket'];
160
-
161
-		if (!isset($this->objectStoreCache[$objectStoreName])) {
162
-			$this->objectStoreCache[$objectStoreName] = [];
163
-			$this->objectStoreCache[$objectStoreName][$bucketName] = $this->objectStoreConfig->buildObjectStore($config);
164
-		} elseif (!isset($this->objectStoreCache[$objectStoreName][$bucketName])) {
165
-			$this->objectStoreCache[$objectStoreName][$bucketName] = $this->objectStoreConfig->buildObjectStore($config);
166
-		}
167
-
168
-		return $this->objectStoreCache[$objectStoreName][$bucketName];
169
-	}
170
-
171
-	public function getUrn(Preview $preview, array $config): string {
172
-		if ($preview->getOldFileId()) {
173
-			return ($config['arguments']['objectPrefix'] ?? 'urn:oid:') . $preview->getOldFileId();
174
-		}
175
-		if (isset($config['arguments']['objectPrefix'])) {
176
-			return ($config['arguments']['objectPrefix'] . 'preview:') . $preview->getId();
177
-		} else {
178
-			return 'uri:oid:preview:' . $preview->getId();
179
-		}
180
-	}
181
-
182
-	#[Override]
183
-	public function scan(): int {
184
-		return 0;
185
-	}
29
+    /**
30
+     * @var array<string, array<string, IObjectStore>>
31
+     */
32
+    private array $objectStoreCache = [];
33
+
34
+    private bool $isMultibucketPreviewDistributionEnabled;
35
+
36
+    public function __construct(
37
+        private readonly PrimaryObjectStoreConfig $objectStoreConfig,
38
+        IConfig $config,
39
+        readonly private PreviewMapper $previewMapper,
40
+    ) {
41
+        $this->isMultibucketPreviewDistributionEnabled = $config->getSystemValueBool('objectstore.multibucket.preview-distribution');
42
+    }
43
+
44
+    #[Override]
45
+    public function writePreview(Preview $preview, mixed $stream): int {
46
+        $size = 0;
47
+        $countStream = CountWrapper::wrap($stream, function (int $writtenSize) use (&$size): void {
48
+            $size = $writtenSize;
49
+        });
50
+
51
+        [
52
+            'urn' => $urn,
53
+            'store' => $store,
54
+        ] = $this->getObjectStoreInfoForNewPreview($preview);
55
+
56
+        try {
57
+            $store->writeObject($urn, $countStream);
58
+        } catch (\Exception $exception) {
59
+            throw new NotPermittedException('Unable to save preview to object store', previous: $exception);
60
+        }
61
+        return $size;
62
+    }
63
+
64
+    #[Override]
65
+    public function readPreview(Preview $preview): mixed {
66
+        [
67
+            'urn' => $urn,
68
+            'store' => $store,
69
+        ] = $this->getObjectStoreInfoForExistingPreview($preview);
70
+
71
+        try {
72
+            return $store->readObject($urn);
73
+        } catch (\Exception $exception) {
74
+            throw new NotPermittedException('Unable to read preview from object store with urn:' . $urn, previous: $exception);
75
+        }
76
+    }
77
+
78
+    #[Override]
79
+    public function deletePreview(Preview $preview): void {
80
+        if (defined('PHPUNIT_RUN') && $preview->getLocationId() === null) {
81
+            // Should only be the case in unit tests when adding dummy previews in the database.
82
+            return;
83
+        }
84
+
85
+        [
86
+            'urn' => $urn,
87
+            'store' => $store,
88
+        ] = $this->getObjectStoreInfoForExistingPreview($preview);
89
+
90
+        try {
91
+            $store->deleteObject($urn);
92
+        } catch (\Exception $exception) {
93
+            throw new NotPermittedException('Unable to delete preview from object store', previous: $exception);
94
+        }
95
+    }
96
+
97
+    #[Override]
98
+    public function migratePreview(Preview $preview, SimpleFile $file): void {
99
+        // Just set the Preview::bucket and Preview::objectStore
100
+        $this->getObjectStoreInfoForNewPreview($preview, migration: true);
101
+        $this->previewMapper->update($preview);
102
+    }
103
+
104
+    /**
105
+     * @return ObjectStoreDefinition
106
+     */
107
+    private function getObjectStoreInfoForExistingPreview(Preview $preview): array {
108
+        $objectStoreName = $preview->getObjectStoreName();
109
+        $bucketName = $preview->getBucketName();
110
+        assert(!empty($objectStoreName));
111
+        assert(!empty($bucketName));
112
+
113
+        $config = $this->objectStoreConfig->getObjectStoreConfiguration($objectStoreName);
114
+        $config['arguments']['bucket'] = $preview->getBucketName();
115
+        $objectStoreName = $preview->getObjectStoreName();
116
+
117
+        return [
118
+            'urn' => $this->getUrn($preview, $config),
119
+            'store' => $this->getObjectStore($objectStoreName, $config),
120
+        ];
121
+    }
122
+
123
+    /**
124
+     * @return ObjectStoreDefinition
125
+     */
126
+    private function getObjectStoreInfoForNewPreview(Preview $preview, bool $migration = false): array {
127
+        // When migrating old previews, use the 'root' object store configuration
128
+        $config = $this->objectStoreConfig->getObjectStoreConfiguration($migration ? 'root' : 'preview');
129
+        $objectStoreName = $this->objectStoreConfig->resolveAlias($migration ? 'root' : 'preview');
130
+
131
+        $bucketName = $config['arguments']['bucket'];
132
+        if ($config['arguments']['multibucket']) {
133
+            if ($this->isMultibucketPreviewDistributionEnabled) {
134
+                // Spread the previews on different buckets depending on their corresponding fileId
135
+                $oldLocationArray = str_split(substr(md5((string)$preview->getFileId()), 0, 2));
136
+                $bucketNumber = hexdec('0x' . $oldLocationArray[0]) * 16 + hexdec('0x' . $oldLocationArray[0]);
137
+                $bucketName .= '-preview-' . $bucketNumber;
138
+            } else {
139
+                // Put all previews in the root (0) bucket
140
+                $bucketName .= '0';
141
+            }
142
+        }
143
+        $config['arguments']['bucket'] = $bucketName;
144
+
145
+        // Get the locationId corresponding to the bucketName and objectStoreName, this will create
146
+        // a new one, if no matching location is found in the DB.
147
+        $locationId = $this->previewMapper->getLocationId($bucketName, $objectStoreName);
148
+        $preview->setLocationId($locationId);
149
+        $preview->setObjectStoreName($objectStoreName);
150
+        $preview->setBucketName($bucketName);
151
+
152
+        return [
153
+            'urn' => $this->getUrn($preview, $config),
154
+            'store' => $this->getObjectStore($objectStoreName, $config),
155
+        ];
156
+    }
157
+
158
+    private function getObjectStore(string $objectStoreName, array $config): IObjectStore {
159
+        $bucketName = $config['arguments']['bucket'];
160
+
161
+        if (!isset($this->objectStoreCache[$objectStoreName])) {
162
+            $this->objectStoreCache[$objectStoreName] = [];
163
+            $this->objectStoreCache[$objectStoreName][$bucketName] = $this->objectStoreConfig->buildObjectStore($config);
164
+        } elseif (!isset($this->objectStoreCache[$objectStoreName][$bucketName])) {
165
+            $this->objectStoreCache[$objectStoreName][$bucketName] = $this->objectStoreConfig->buildObjectStore($config);
166
+        }
167
+
168
+        return $this->objectStoreCache[$objectStoreName][$bucketName];
169
+    }
170
+
171
+    public function getUrn(Preview $preview, array $config): string {
172
+        if ($preview->getOldFileId()) {
173
+            return ($config['arguments']['objectPrefix'] ?? 'urn:oid:') . $preview->getOldFileId();
174
+        }
175
+        if (isset($config['arguments']['objectPrefix'])) {
176
+            return ($config['arguments']['objectPrefix'] . 'preview:') . $preview->getId();
177
+        } else {
178
+            return 'uri:oid:preview:' . $preview->getId();
179
+        }
180
+    }
181
+
182
+    #[Override]
183
+    public function scan(): int {
184
+        return 0;
185
+    }
186 186
 }
Please login to merge, or discard this patch.