Skip to content

Commit b7f7a7b

Browse files
authored
Delete and restore multiple objects by IDs (#51)
* feat: delete and restore multiple * fix: test * fix: tests * test: skip some on be4 * ci: 96 coverage_min_percentage on unit-4 * refactor: retrocompatibility * tests: fix doc + tests * chore fix: make scrutinizer happy * chore feat: add scripts to composer.json
1 parent 5fb3173 commit b7f7a7b

File tree

5 files changed

+239
-9
lines changed

5 files changed

+239
-9
lines changed

README.md

+10
Original file line numberDiff line numberDiff line change
@@ -221,6 +221,10 @@ You can trash an object with `delete(string $path, mixed $body = null, ?array $h
221221

222222
// delete document by ID 99999 and type documents
223223
$response = $client->deleteObject(99999, 'documents'); // arguments passed are string|int $id, string $type
224+
225+
// delete multiple
226+
$response = $client->deleteObjects([999991, 999992, 999993], 'documents');
227+
224228
```
225229

226230
#### Restore data
@@ -230,6 +234,9 @@ Data in trashcan can be restored with `restoreObject(int|string $id, string $typ
230234
```php
231235
// restore document 99999
232236
$response = $client->restoreObject(99999, 'documents'); // arguments passed are string|int $id, string $type
237+
238+
// restore multiple
239+
$response = $client->restoreObjects([999991, 999992, 999993], 'documents');
233240
```
234241

235242
#### Hard delete
@@ -243,6 +250,9 @@ You can remove an object from trashcan with `remove(int|string $id)`.
243250

244251
// permanently remove documents 99999
245252
$response = $client->remove(99999); // argument passed is string|int $id
253+
254+
// permanently remove multiple
255+
$response = $client->removeObjects([999991, 999992, 999993]);
246256
```
247257

248258
### Working with relations

composer.json

+2
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,9 @@
5454
],
5555
"cs-check": "vendor/bin/phpcs --colors -p --standard=vendor/cakephp/cakephp-codesniffer/CakePHP ./src ./tests",
5656
"cs-fix": "vendor/bin/phpcbf --colors --standard=vendor/cakephp/cakephp-codesniffer/CakePHP ./src ./tests",
57+
"stan": "vendor/bin/phpstan analyse",
5758
"test": "vendor/bin/phpunit --colors=always",
59+
"coverage": "vendor/bin/phpunit --colors=always --coverage-html coverage",
5860
"update-dev": [
5961
"@composer update",
6062
"@cs-setup"

src/BEditaClient.php

+59-1
Original file line numberDiff line numberDiff line change
@@ -179,6 +179,27 @@ public function deleteObject($id, string $type): ?array
179179
return $this->delete(sprintf('/%s/%s', $type, $id));
180180
}
181181

182+
/**
183+
* Delete objects (DELETE) => move to trashcan.
184+
*
185+
* @param array $ids Object ids
186+
* @param string|null $type Object type name
187+
* @return array|null Response in array format
188+
*/
189+
public function deleteObjects(array $ids, string $type = 'objects'): ?array
190+
{
191+
try {
192+
$response = $this->delete(sprintf('/%s?ids=%s', $type, implode(',', $ids)));
193+
} catch (\Exception $e) {
194+
// fallback to delete one by one, to be retrocompatible
195+
foreach ($ids as $id) {
196+
$response = !empty($response) ? $response : $this->deleteObject($id, $type);
197+
}
198+
}
199+
200+
return $response;
201+
}
202+
182203
/**
183204
* Remove an object => permanently remove object from trashcan.
184205
*
@@ -190,6 +211,26 @@ public function remove($id): ?array
190211
return $this->delete(sprintf('/trash/%s', $id));
191212
}
192213

214+
/**
215+
* Remove objects => permanently remove objects from trashcan.
216+
*
217+
* @param array $ids Object ids
218+
* @return array|null Response in array format
219+
*/
220+
public function removeObjects(array $ids): ?array
221+
{
222+
try {
223+
$response = $this->delete(sprintf('/trash?ids=%s', implode(',', $ids)));
224+
} catch (\Exception $e) {
225+
// fallback to delete one by one, to be retrocompatible
226+
foreach ($ids as $id) {
227+
$response = !empty($response) ? $response : $this->remove($id);
228+
}
229+
}
230+
231+
return $response;
232+
}
233+
193234
/**
194235
* Upload file (POST)
195236
*
@@ -341,7 +382,7 @@ public function relationData(string $name): ?array
341382
public function restoreObject($id, string $type): ?array
342383
{
343384
return $this->patch(
344-
sprintf('/%s/%s', 'trash', $id),
385+
sprintf('/trash/%s', $id),
345386
json_encode([
346387
'data' => [
347388
'id' => $id,
@@ -350,4 +391,21 @@ public function restoreObject($id, string $type): ?array
350391
])
351392
);
352393
}
394+
395+
/**
396+
* Restore objects from trash
397+
*
398+
* @param array $ids Object ids
399+
* @param string|null $type Object type
400+
* @return array|null Response in array format
401+
*/
402+
public function restoreObjects(array $ids, string $type = 'objects'): ?array
403+
{
404+
$res = null;
405+
foreach ($ids as $id) {
406+
$res = !empty($res) ? $res : $this->restoreObject($id, $type);
407+
}
408+
409+
return $res;
410+
}
353411
}

tests/TestCase/BEditaClientTest.php

+166-6
Original file line numberDiff line numberDiff line change
@@ -704,13 +704,13 @@ public function deleteObjectProvider(): array
704704
/**
705705
* Test `deleteObject`.
706706
*
707-
* @param mixed $input Input data for delete
708-
* @param mixed $expected Expected result
707+
* @param array $input Input data for delete
708+
* @param array $expected Expected result
709709
* @return void
710710
* @dataProvider deleteObjectProvider
711711
* @covers ::deleteObject()
712712
*/
713-
public function testDeleteObject($input, $expected): void
713+
public function testDeleteObject(array $input, array $expected): void
714714
{
715715
$this->authenticate();
716716

@@ -720,6 +720,92 @@ public function testDeleteObject($input, $expected): void
720720
static::assertEmpty($response);
721721
}
722722

723+
/**
724+
* Test `deleteObjects`, `removeObjects` and `restoreObjects.
725+
* Skip on be4 (delete multiple available from BEdita v5.28.0).
726+
*
727+
* @return void
728+
* @covers ::deleteObjects()
729+
* @covers ::restoreObjects()
730+
* @covers ::getObject()
731+
*/
732+
public function testDeleteRemoveRestore(): void
733+
{
734+
$this->authenticate();
735+
$type = 'documents';
736+
$docId = $this->newObject([
737+
'type' => $type,
738+
'data' => [
739+
'title' => 'this is a test document',
740+
],
741+
]);
742+
$ids = [$docId];
743+
$response = $this->client->deleteObjects($ids, $type);
744+
static::assertEquals(204, $this->client->getStatusCode());
745+
static::assertEquals('No Content', $this->client->getStatusMessage());
746+
static::assertEmpty($response);
747+
$response = $this->client->getObjects($type, ['filter' => ['id' => $ids[0]]]);
748+
static::assertEmpty($response['data']);
749+
$response = $this->client->restoreObjects($ids, $type);
750+
static::assertEquals(204, $this->client->getStatusCode());
751+
static::assertEquals('No Content', $this->client->getStatusMessage());
752+
static::assertEmpty($response);
753+
$response = $this->client->getObjects($type, ['filter' => ['id' => $ids[0]]]);
754+
static::assertNotEmpty($response['data']);
755+
$response = $this->client->deleteObjects($ids, $type);
756+
static::assertEquals(204, $this->client->getStatusCode());
757+
static::assertEquals('No Content', $this->client->getStatusMessage());
758+
static::assertEmpty($response);
759+
$response = $this->client->removeObjects($ids, $type);
760+
static::assertEquals(204, $this->client->getStatusCode());
761+
static::assertEquals('No Content', $this->client->getStatusMessage());
762+
static::assertEmpty($response);
763+
}
764+
765+
/**
766+
* Test `deleteObjects` on exception.
767+
*
768+
* @return void
769+
* @covers ::deleteObjects()
770+
*/
771+
public function testDeleteObjects(): void
772+
{
773+
$client = new class ($this->apiBaseUrl, $this->apiKey) extends BEditaClient {
774+
public function deleteObject($id, string $type): ?array
775+
{
776+
return [];
777+
}
778+
};
779+
$response = $client->authenticate($this->adminUser, $this->adminPassword);
780+
$client->setupTokens($response['meta']);
781+
$type = 'documents';
782+
$response = $client->save($type, ['title' => 'this is a test document']);
783+
$docId = $response['data']['id'];
784+
$ids = [$docId, 'abc'];
785+
$actual = $client->deleteObjects($ids, $type);
786+
static::assertEmpty($actual);
787+
}
788+
789+
/**
790+
* Test `deleteObjects` on exception.
791+
*
792+
* @return void
793+
*/
794+
public function testDeleteObjectsOnException(): void
795+
{
796+
$this->authenticate();
797+
$type = 'documents';
798+
$docId = $this->newObject([
799+
'type' => $type,
800+
'data' => [
801+
'title' => 'this is a test document',
802+
],
803+
]);
804+
$ids = [$docId, 'abc'];
805+
$this->expectException(BEditaClientException::class);
806+
$this->client->deleteObjects($ids, $type);
807+
}
808+
723809
/**
724810
* Data provider for `testRestoreObject`
725811
*/
@@ -763,6 +849,31 @@ public function testRestoreObject($input, $expected): void
763849
static::assertEmpty($response);
764850
}
765851

852+
/**
853+
* Test `restoreObjects`.
854+
* Skip on be4 (delete multiple available from BEdita v5.28.0).
855+
*
856+
* @return void
857+
* @covers ::restoreObjects()
858+
*/
859+
public function testRestoreObjects(): void
860+
{
861+
$this->authenticate();
862+
$type = 'documents';
863+
$docId = $this->newObject([
864+
'type' => $type,
865+
'data' => [
866+
'title' => 'this is a test document',
867+
],
868+
]);
869+
$ids = [$docId];
870+
$this->client->deleteObjects($ids, $type);
871+
$response = $this->client->restoreObjects($ids, $type);
872+
static::assertEquals(204, $this->client->getStatusCode());
873+
static::assertEquals('No Content', $this->client->getStatusMessage());
874+
static::assertEmpty($response);
875+
}
876+
766877
/**
767878
* Data provider for `testRemove`
768879
*/
@@ -806,6 +917,55 @@ public function testRemove($input, $expected): void
806917
static::assertEmpty($response);
807918
}
808919

920+
/**
921+
* Test `removeObjects` on exception.
922+
*
923+
* @return void
924+
* @covers ::removeObjects()
925+
*/
926+
public function testRemoveObjects(): void
927+
{
928+
$client = new class ($this->apiBaseUrl, $this->apiKey) extends BEditaClient {
929+
public function remove($id): ?array
930+
{
931+
if ($id === 'abc') {
932+
return [];
933+
}
934+
935+
return $this->delete(sprintf('/trash/%s', $id));
936+
}
937+
};
938+
$response = $client->authenticate($this->adminUser, $this->adminPassword);
939+
$client->setupTokens($response['meta']);
940+
$type = 'documents';
941+
$response = $client->save($type, ['title' => 'this is a test document']);
942+
$docId = $response['data']['id'];
943+
$client->deleteObject($docId, $type);
944+
$ids = [$docId, 'abc'];
945+
$actual = $client->removeObjects($ids, $type);
946+
static::assertEmpty($actual);
947+
}
948+
949+
/**
950+
* Test `removeObjects` on exception.
951+
*
952+
* @return void
953+
*/
954+
public function testRemoveObjectsOnException(): void
955+
{
956+
$this->authenticate();
957+
$type = 'documents';
958+
$docId = $this->newObject([
959+
'type' => $type,
960+
'data' => [
961+
'title' => 'this is a test document',
962+
],
963+
]);
964+
$ids = [$docId, 'abc'];
965+
$this->expectException(BEditaClientException::class);
966+
$this->client->removeObjects($ids, $type);
967+
}
968+
809969
/**
810970
* Test `schema`.
811971
*
@@ -991,13 +1151,13 @@ public function testSendRequest($input, $expected): void
9911151
* Create new object for test purposes.
9921152
*
9931153
* @param array $input The input data.
994-
* @return int|string the Id.
1154+
* @return int the Id.
9951155
*/
996-
private function newObject($input)
1156+
private function newObject($input): int
9971157
{
9981158
$response = $this->client->save($input['type'], $input['data']);
9991159

1000-
return $response['data']['id'];
1160+
return (int)$response['data']['id'];
10011161
}
10021162

10031163
/**

tests/TestCase/BaseClientTest.php

+2-2
Original file line numberDiff line numberDiff line change
@@ -604,10 +604,10 @@ public function testRefreshTokens($input, $expected): void
604604
}
605605

606606
/**
607-
* Test `refreshToken` on Invalid response from server.
607+
* Test `refreshTokens` on Invalid response from server.
608608
*
609609
* @return void
610-
* @covers ::refreshToken()
610+
* @covers ::refreshTokens()
611611
*/
612612
public function testRefreshTokenInvalidResponseFromServer(): void
613613
{

0 commit comments

Comments
 (0)