Skip to content

Commit 10755e1

Browse files
committed
feat: add constant to force async attachment creation
1 parent 55acc7c commit 10755e1

4 files changed

Lines changed: 100 additions & 22 deletions

File tree

src/Configuration/AttachmentConfiguration.php

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,5 +30,14 @@ public function modify(Container $container)
3030
$container['file_manager'] = $container->service(function (Container $container) {
3131
return new AttachmentFileManager($container['uploads_basedir']);
3232
});
33+
$container['force_async_attachment_creation'] = $container->service(function () {
34+
if (false !== getenv('YMIR_FORCE_ASYNC_ATTACHMENT_CREATION')) {
35+
return (bool) getenv('YMIR_FORCE_ASYNC_ATTACHMENT_CREATION');
36+
} elseif (defined('YMIR_FORCE_ASYNC_ATTACHMENT_CREATION')) {
37+
return (bool) YMIR_FORCE_ASYNC_ATTACHMENT_CREATION;
38+
}
39+
40+
return false;
41+
});
3342
}
3443
}

src/Configuration/RestApiConfiguration.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ public function modify(Container $container)
3030
$container['rest_namespace'] = 'ymir/v1';
3131
$container['rest_endpoints'] = $container->service(function (Container $container) {
3232
return [
33-
new RestApi\CreateAttachmentEndpoint($container['cloud_storage_client'], $container['console_client'], $container['uploads_basedir'], $container['uploads_baseurl']),
33+
new RestApi\CreateAttachmentEndpoint($container['cloud_storage_client'], $container['console_client'], $container['uploads_basedir'], $container['uploads_baseurl'], $container['force_async_attachment_creation']),
3434
new RestApi\GetFileDetailsEndpoint($container['cloud_storage_client'], $container['uploads_path'], $container['uploads_subdir']),
3535
];
3636
});

src/RestApi/CreateAttachmentEndpoint.php

Lines changed: 23 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,13 @@ class CreateAttachmentEndpoint extends AbstractEndpoint
3535
*/
3636
private $consoleClient;
3737

38+
/**
39+
* Whether to force the creation of the attachment metadata asynchronously or not.
40+
*
41+
* @var bool
42+
*/
43+
private $forceAsync;
44+
3845
/**
3946
* The path to uploads directory.
4047
*
@@ -52,10 +59,11 @@ class CreateAttachmentEndpoint extends AbstractEndpoint
5259
/**
5360
* Constructor.
5461
*/
55-
public function __construct(CloudStorageClientInterface $cloudStorageClient, ConsoleClientInterface $consoleClient, string $uploadsDirectory, string $uploadsUrl)
62+
public function __construct(CloudStorageClientInterface $cloudStorageClient, ConsoleClientInterface $consoleClient, string $uploadsDirectory, string $uploadsUrl, bool $forceAsync = false)
5663
{
5764
$this->cloudStorageClient = $cloudStorageClient;
5865
$this->consoleClient = $consoleClient;
66+
$this->forceAsync = $forceAsync;
5967
$this->uploadsDirectory = $uploadsDirectory;
6068
$this->uploadsUrl = $uploadsUrl;
6169
}
@@ -122,13 +130,9 @@ public function respond(\WP_REST_Request $request)
122130
return $attachmentId;
123131
}
124132

125-
$async = false;
133+
$async = $this->needsAsync($details);
126134

127-
if (isset($details['size'], $details['type'])
128-
&& 0 === stripos($details['type'], 'image/')
129-
&& $details['size'] > wp_convert_hr_to_bytes('15MB')
130-
) {
131-
$async = true;
135+
if ($async) {
132136
wp_update_attachment_metadata($attachmentId, $this->createBaseImageMetadata($path));
133137
}
134138

@@ -162,4 +166,16 @@ private function createBaseImageMetadata(string $path): array
162166

163167
return $metadata;
164168
}
169+
170+
/**
171+
* Determine if we need to create the attachment metadata asynchronously or not.
172+
*/
173+
private function needsAsync(array $details): bool
174+
{
175+
if ($this->forceAsync) {
176+
return true;
177+
}
178+
179+
return isset($details['size'], $details['type']) && 0 === stripos($details['type'], 'image/') && $details['size'] > wp_convert_hr_to_bytes('15MB');
180+
}
165181
}

tests/Unit/RestApi/CreateAttachmentEndpointTest.php

Lines changed: 67 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -50,13 +50,13 @@ public function testGetPath()
5050
$this->assertSame('/attachments', CreateAttachmentEndpoint::getPath());
5151
}
5252

53-
public function testRespondReturnsAsyncResponseForLargeImage()
53+
public function testRespondPerformsAsyncCommandIfForced()
5454
{
5555
$cloudStorageClient = $this->getCloudStorageClientInterfaceMock();
5656
$cloudStorageClient->expects($this->once())
5757
->method('getObjectDetails')
5858
->with('uploads/2020/08/filename.jpg')
59-
->willReturn(['size' => 16, 'type' => 'image/jpeg']);
59+
->willReturn(['size' => 1, 'type' => 'image/jpeg']);
6060

6161
$consoleClient = $this->getConsoleClientInterfaceMock();
6262
$consoleClient->expects($this->once())
@@ -79,9 +79,7 @@ public function testRespondReturnsAsyncResponseForLargeImage()
7979
->willReturn('filename');
8080

8181
$wp_convert_hr_to_bytes = $this->getFunctionMock($this->getNamespace(CreateAttachmentEndpoint::class), 'wp_convert_hr_to_bytes');
82-
$wp_convert_hr_to_bytes->expects($this->once())
83-
->with($this->identicalTo('15MB'))
84-
->willReturn(15);
82+
$wp_convert_hr_to_bytes->expects($this->never());
8583

8684
$wp_insert_attachment = $this->getFunctionMock($this->getNamespace(CreateAttachmentEndpoint::class), 'wp_insert_attachment');
8785
$wp_insert_attachment->expects($this->once())
@@ -97,7 +95,7 @@ public function testRespondReturnsAsyncResponseForLargeImage()
9795
$wp_update_attachment_metadata->expects($this->once())
9896
->with($this->identicalTo('attachment_id'), $this->identicalTo(['file' => '2020/08/filename.jpg']));
9997

100-
$this->assertSame([], (new CreateAttachmentEndpoint($cloudStorageClient, $consoleClient, 'cloudstorage:///uploads', 'https://d1mbwobeuvop7i.cloudfront.net/uploads'))->respond($request));
98+
$this->assertSame([], (new CreateAttachmentEndpoint($cloudStorageClient, $consoleClient, 'cloudstorage:///uploads', 'https://d1mbwobeuvop7i.cloudfront.net/uploads', true))->respond($request));
10199
}
102100

103101
public function testRespondReturnsError()
@@ -133,12 +131,12 @@ public function testRespondReturnsError()
133131
$this->assertSame($error, (new CreateAttachmentEndpoint($cloudStorageClient, $this->getConsoleClientInterfaceMock(), 'uploads_dir', 'uploads_url'))->respond($request));
134132
}
135133

136-
public function testRespondReturnsResponse()
134+
public function testRespondReturnsResponseForMultisite()
137135
{
138136
$cloudStorageClient = $this->getCloudStorageClientInterfaceMock();
139137
$cloudStorageClient->expects($this->once())
140138
->method('getObjectDetails')
141-
->with('uploads/2020/08/filename.jpg')
139+
->with('uploads/sites/2/2020/08/filename.jpg')
142140
->willReturn(['type' => 'text/plain']);
143141

144142
$consoleClient = $this->getConsoleClientInterfaceMock();
@@ -163,24 +161,74 @@ public function testRespondReturnsResponse()
163161

164162
$wp_insert_attachment = $this->getFunctionMock($this->getNamespace(CreateAttachmentEndpoint::class), 'wp_insert_attachment');
165163
$wp_insert_attachment->expects($this->once())
166-
->with($this->identicalTo(['guid' => 'https://d1mbwobeuvop7i.cloudfront.net/uploads/2020/08/filename.jpg', 'post_author' => 'user_id', 'post_mime_type' => 'text/plain', 'post_title' => 'filename']), $this->identicalTo('2020/08/filename.jpg'), $this->identicalTo(0), $this->identicalTo(true))
164+
->with($this->identicalTo(['guid' => 'https://d1mbwobeuvop7i.cloudfront.net/uploads/sites/2/2020/08/filename.jpg', 'post_author' => 'user_id', 'post_mime_type' => 'text/plain', 'post_title' => 'filename']), $this->identicalTo('2020/08/filename.jpg'), $this->identicalTo(0), $this->identicalTo(true))
167165
->willReturn('attachment_id');
168166

169167
$wp_prepare_attachment_for_js = $this->getFunctionMock($this->getNamespace(CreateAttachmentEndpoint::class), 'wp_prepare_attachment_for_js');
170168
$wp_prepare_attachment_for_js->expects($this->once())
171169
->with($this->identicalTo('attachment_id'))
172170
->willReturn([]);
173171

172+
$this->assertSame([], (new CreateAttachmentEndpoint($cloudStorageClient, $consoleClient, 'cloudstorage:///uploads/sites/2', 'https://d1mbwobeuvop7i.cloudfront.net/uploads/sites/2'))->respond($request));
173+
}
174+
175+
public function testRespondWithLargeImage()
176+
{
177+
$cloudStorageClient = $this->getCloudStorageClientInterfaceMock();
178+
$cloudStorageClient->expects($this->once())
179+
->method('getObjectDetails')
180+
->with('uploads/2020/08/filename.jpg')
181+
->willReturn(['size' => 16, 'type' => 'image/jpeg']);
182+
183+
$consoleClient = $this->getConsoleClientInterfaceMock();
184+
$consoleClient->expects($this->once())
185+
->method('createAttachmentMetadata')
186+
->with($this->identicalTo('attachment_id'), $this->identicalTo(true));
187+
188+
$get_current_user_id = $this->getFunctionMock($this->getNamespace(CreateAttachmentEndpoint::class), 'get_current_user_id');
189+
$get_current_user_id->expects($this->once())
190+
->willReturn('user_id');
191+
192+
$request = $this->getWPRESTRequestMock();
193+
$request->expects($this->once())
194+
->method('get_param')
195+
->with($this->identicalTo('path'))
196+
->willReturn('2020/08/filename.jpg');
197+
198+
$sanitize_text_field = $this->getFunctionMock($this->getNamespace(CreateAttachmentEndpoint::class), 'sanitize_text_field');
199+
$sanitize_text_field->expects($this->once())
200+
->with($this->identicalTo('filename'))
201+
->willReturn('filename');
202+
203+
$wp_convert_hr_to_bytes = $this->getFunctionMock($this->getNamespace(CreateAttachmentEndpoint::class), 'wp_convert_hr_to_bytes');
204+
$wp_convert_hr_to_bytes->expects($this->once())
205+
->with($this->identicalTo('15MB'))
206+
->willReturn(15);
207+
208+
$wp_insert_attachment = $this->getFunctionMock($this->getNamespace(CreateAttachmentEndpoint::class), 'wp_insert_attachment');
209+
$wp_insert_attachment->expects($this->once())
210+
->with($this->identicalTo(['guid' => 'https://d1mbwobeuvop7i.cloudfront.net/uploads/2020/08/filename.jpg', 'post_author' => 'user_id', 'post_mime_type' => 'image/jpeg', 'post_title' => 'filename']), $this->identicalTo('2020/08/filename.jpg'), $this->identicalTo(0), $this->identicalTo(true))
211+
->willReturn('attachment_id');
212+
213+
$wp_prepare_attachment_for_js = $this->getFunctionMock($this->getNamespace(CreateAttachmentEndpoint::class), 'wp_prepare_attachment_for_js');
214+
$wp_prepare_attachment_for_js->expects($this->once())
215+
->with($this->identicalTo('attachment_id'))
216+
->willReturn([]);
217+
218+
$wp_update_attachment_metadata = $this->getFunctionMock($this->getNamespace(CreateAttachmentEndpoint::class), 'wp_update_attachment_metadata');
219+
$wp_update_attachment_metadata->expects($this->once())
220+
->with($this->identicalTo('attachment_id'), $this->identicalTo(['file' => '2020/08/filename.jpg']));
221+
174222
$this->assertSame([], (new CreateAttachmentEndpoint($cloudStorageClient, $consoleClient, 'cloudstorage:///uploads', 'https://d1mbwobeuvop7i.cloudfront.net/uploads'))->respond($request));
175223
}
176224

177-
public function testRespondReturnsResponseForMultisite()
225+
public function testRespondWithSmallImage()
178226
{
179227
$cloudStorageClient = $this->getCloudStorageClientInterfaceMock();
180228
$cloudStorageClient->expects($this->once())
181229
->method('getObjectDetails')
182-
->with('uploads/sites/2/2020/08/filename.jpg')
183-
->willReturn(['type' => 'text/plain']);
230+
->with('uploads/2020/08/filename.jpg')
231+
->willReturn(['size' => 1, 'type' => 'image/jpeg']);
184232

185233
$consoleClient = $this->getConsoleClientInterfaceMock();
186234
$consoleClient->expects($this->once())
@@ -202,16 +250,21 @@ public function testRespondReturnsResponseForMultisite()
202250
->with($this->identicalTo('filename'))
203251
->willReturn('filename');
204252

253+
$wp_convert_hr_to_bytes = $this->getFunctionMock($this->getNamespace(CreateAttachmentEndpoint::class), 'wp_convert_hr_to_bytes');
254+
$wp_convert_hr_to_bytes->expects($this->once())
255+
->with($this->identicalTo('15MB'))
256+
->willReturn(15);
257+
205258
$wp_insert_attachment = $this->getFunctionMock($this->getNamespace(CreateAttachmentEndpoint::class), 'wp_insert_attachment');
206259
$wp_insert_attachment->expects($this->once())
207-
->with($this->identicalTo(['guid' => 'https://d1mbwobeuvop7i.cloudfront.net/uploads/sites/2/2020/08/filename.jpg', 'post_author' => 'user_id', 'post_mime_type' => 'text/plain', 'post_title' => 'filename']), $this->identicalTo('2020/08/filename.jpg'), $this->identicalTo(0), $this->identicalTo(true))
260+
->with($this->identicalTo(['guid' => 'https://d1mbwobeuvop7i.cloudfront.net/uploads/2020/08/filename.jpg', 'post_author' => 'user_id', 'post_mime_type' => 'image/jpeg', 'post_title' => 'filename']), $this->identicalTo('2020/08/filename.jpg'), $this->identicalTo(0), $this->identicalTo(true))
208261
->willReturn('attachment_id');
209262

210263
$wp_prepare_attachment_for_js = $this->getFunctionMock($this->getNamespace(CreateAttachmentEndpoint::class), 'wp_prepare_attachment_for_js');
211264
$wp_prepare_attachment_for_js->expects($this->once())
212265
->with($this->identicalTo('attachment_id'))
213266
->willReturn([]);
214267

215-
$this->assertSame([], (new CreateAttachmentEndpoint($cloudStorageClient, $consoleClient, 'cloudstorage:///uploads/sites/2', 'https://d1mbwobeuvop7i.cloudfront.net/uploads/sites/2'))->respond($request));
268+
$this->assertSame([], (new CreateAttachmentEndpoint($cloudStorageClient, $consoleClient, 'cloudstorage:///uploads', 'https://d1mbwobeuvop7i.cloudfront.net/uploads'))->respond($request));
216269
}
217270
}

0 commit comments

Comments
 (0)