Skip to content

Commit ccd5bce

Browse files
vitormattosjuliusknorr
authored andcommitted
Replace glob by EventDispatcher
Signed-off-by: Vitor Mattos <vitor@php.rio>
1 parent f2b6934 commit ccd5bce

File tree

9 files changed

+173
-28
lines changed

9 files changed

+173
-28
lines changed

docs/implement-import.md

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,32 @@
11
## Implement import
22

3-
* Create a new class `lib/Service/Importer/Systems/<ImportName>Service.php` where `<ImportName>` is the name of the source system.
3+
* Create a new importer class extending `ABoardImportService`
4+
* Create a listener for event `BoardImportGetAllowedEvent` to enable your importer.
5+
> You can read more about listeners on [Nextcloud](https://docs.nextcloud.com/server/latest/developer_manual/basics/events.html?highlight=event#writing-a-listener) doc.
6+
7+
Example:
8+
9+
```php
10+
class YourCustomImporterListener {
11+
public function handle(Event $event): void {
12+
if (!($event instanceof BoardImportGetAllowedEvent)) {
13+
return;
14+
}
15+
16+
$event->getService()->addAllowedImportSystem([
17+
'name' => YourCustomImporterService::$name,
18+
'class' => YourCustomImporterService::class,
19+
'internalName' => 'YourCustomImporter'
20+
]);
21+
}
22+
}
23+
```
24+
* Register your listener on your `Application` class like this:
25+
```php
26+
$dispatcher = $this->getContainer()->query(IEventDispatcher::class);
27+
$dispatcher->registerEventListener(
28+
BoardImportGetAllowedEvent::class,
29+
YourCustomImporterListener::class
30+
);
31+
```
432
* Use the `lib/Service/Importer/Systems/TrelloJsonService.php` class as inspiration
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
<?php
2+
/*
3+
* @copyright Copyright (c) 2021 Vitor Mattos <vitor@php.rio>
4+
*
5+
* @author Vitor Mattos <vitor@php.rio>
6+
*
7+
* @license GNU AGPL version 3 or any later version
8+
*
9+
* This program is free software: you can redistribute it and/or modify
10+
* it under the terms of the GNU Affero General Public License as
11+
* published by the Free Software Foundation, either version 3 of the
12+
* License, or (at your option) any later version.
13+
*
14+
* This program is distributed in the hope that it will be useful,
15+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
16+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17+
* GNU Affero General Public License for more details.
18+
*
19+
* You should have received a copy of the GNU Affero General Public License
20+
* along with this program. If not, see <http://www.gnu.org/licenses/>.
21+
*
22+
*/
23+
24+
declare(strict_types=1);
25+
26+
27+
namespace OCA\Deck\Event;
28+
29+
use OCA\Deck\Service\Importer\BoardImportService;
30+
use OCP\EventDispatcher\Event;
31+
32+
abstract class ABoardImportGetAllowedEvent extends Event {
33+
private $service;
34+
35+
public function __construct(BoardImportService $service) {
36+
parent::__construct();
37+
38+
$this->service = $service;
39+
}
40+
41+
public function getService(): BoardImportService {
42+
return $this->service;
43+
}
44+
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
<?php
2+
/*
3+
* @copyright Copyright (c) 2021 Vitor Mattos <vitor@php.rio>
4+
*
5+
* @author Vitor Mattos <vitor@php.rio>
6+
*
7+
* @license GNU AGPL version 3 or any later version
8+
*
9+
* This program is free software: you can redistribute it and/or modify
10+
* it under the terms of the GNU Affero General Public License as
11+
* published by the Free Software Foundation, either version 3 of the
12+
* License, or (at your option) any later version.
13+
*
14+
* This program is distributed in the hope that it will be useful,
15+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
16+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17+
* GNU Affero General Public License for more details.
18+
*
19+
* You should have received a copy of the GNU Affero General Public License
20+
* along with this program. If not, see <http://www.gnu.org/licenses/>.
21+
*
22+
*/
23+
24+
declare(strict_types=1);
25+
26+
namespace OCA\Deck\Event;
27+
28+
class BoardImportGetAllowedEvent extends ABoardImportGetAllowedEvent {
29+
}

lib/Service/Importer/ABoardImportService.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,8 @@ abstract public function getLabels(): array;
9292

9393
abstract public function validateUsers(): void;
9494

95+
abstract public function getJsonSchemaPath(): string;
96+
9597
public function updateStack(string $id, Stack $stack): void {
9698
$this->stacks[$id] = $stack;
9799
}

lib/Service/Importer/BoardImportCommandService.php

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -114,8 +114,7 @@ protected function validateConfig(): void {
114114
return $v['message'];
115115
}, $e->getData()));
116116
$this->getOutput()->writeln('Valid schema:');
117-
$schemaPath = __DIR__ . '/fixtures/config-' . $this->getSystem() . '-schema.json';
118-
$this->getOutput()->writeln(print_r(file_get_contents($schemaPath), true));
117+
$this->getOutput()->writeln(print_r(file_get_contents($this->getJsonSchemaPath()), true));
119118
$this->getInput()->setOption('config', '');
120119
}
121120
$this->validateConfig();

lib/Service/Importer/BoardImportService.php

Lines changed: 28 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -36,11 +36,16 @@
3636
use OCA\Deck\Db\CardMapper;
3737
use OCA\Deck\Db\LabelMapper;
3838
use OCA\Deck\Db\StackMapper;
39+
use OCA\Deck\Event\BoardImportGetAllowedEvent;
3940
use OCA\Deck\Exceptions\ConflictException;
4041
use OCA\Deck\NotFoundException;
42+
use OCA\Deck\Service\FileService;
43+
use OCA\Deck\Service\Importer\Systems\TrelloApiService;
44+
use OCA\Deck\Service\Importer\Systems\TrelloJsonService;
4145
use OCP\Comments\IComment;
4246
use OCP\Comments\ICommentsManager;
4347
use OCP\Comments\NotFoundException as CommentNotFoundException;
48+
use OCP\EventDispatcher\IEventDispatcher;
4449
use OCP\IUserManager;
4550

4651
class BoardImportService {
@@ -62,6 +67,8 @@ class BoardImportService {
6267
private $attachmentMapper;
6368
/** @var ICommentsManager */
6469
private $commentsManager;
70+
/** @var IEventDispatcher */
71+
private $eventDispatcher;
6572
/** @var string */
6673
private $system = '';
6774
/** @var null|ABoardImportService */
@@ -96,7 +103,8 @@ public function __construct(
96103
AssignmentMapper $assignmentMapper,
97104
AttachmentMapper $attachmentMapper,
98105
CardMapper $cardMapper,
99-
ICommentsManager $commentsManager
106+
ICommentsManager $commentsManager,
107+
IEventDispatcher $eventDispatcher
100108
) {
101109
$this->userManager = $userManager;
102110
$this->boardMapper = $boardMapper;
@@ -107,6 +115,7 @@ public function __construct(
107115
$this->assignmentMapper = $assignmentMapper;
108116
$this->attachmentMapper = $attachmentMapper;
109117
$this->commentsManager = $commentsManager;
118+
$this->eventDispatcher = $eventDispatcher;
110119
$this->board = new Board();
111120
$this->disableCommentsEvents();
112121
}
@@ -161,29 +170,25 @@ public function getSystem(): string {
161170
return $this->system;
162171
}
163172

173+
public function addAllowedImportSystem($system): self {
174+
$this->allowedSystems[] = $system;
175+
return $this;
176+
}
177+
164178
public function getAllowedImportSystems(): array {
165179
if (!$this->allowedSystems) {
166-
$allowedSystems = glob(__DIR__ . '/Systems/*Service.php');
167-
$allowedSystems = array_map(function ($filename) {
168-
preg_match('/\/(?<class>(?<system>\w+)Service)\.php$/', $filename, $matches);
169-
$className = 'OCA\Deck\Service\Importer\Systems\\'.$matches['class'];
170-
if (!class_exists($className)) {
171-
/** @psalm-suppress UnresolvableInclude */
172-
require_once $className;
173-
}
174-
/** @psalm-suppress InvalidPropertyFetch */
175-
$name = $className::$name;
176-
if (empty($name)) {
177-
$name = lcfirst($matches['system']);
178-
}
179-
return [
180-
'name' => $name,
181-
'class' => $className,
182-
'internalName' => lcfirst($matches['system'])
183-
];
184-
}, $allowedSystems);
185-
$this->allowedSystems = array_values($allowedSystems);
180+
$this->addAllowedImportSystem([
181+
'name' => TrelloApiService::$name,
182+
'class' => TrelloApiService::class,
183+
'internalName' => 'TrelloApi'
184+
]);
185+
$this->addAllowedImportSystem([
186+
'name' => TrelloJsonService::$name,
187+
'class' => TrelloJsonService::class,
188+
'internalName' => 'TrelloJson'
189+
]);
186190
}
191+
$this->eventDispatcher->dispatchTyped(new BoardImportGetAllowedEvent($this));
187192
return $this->allowedSystems;
188193
}
189194

@@ -192,7 +197,7 @@ public function getImportSystem(): ABoardImportService {
192197
throw new NotFoundException('System to import not found');
193198
}
194199
if (!is_object($this->systemInstance)) {
195-
$systemClass = 'OCA\\Deck\\Service\\BoardImport' . ucfirst($this->getSystem()) . 'Service';
200+
$systemClass = 'OCA\\Deck\\Service\\Importer\\Systems\\' . ucfirst($this->getSystem()) . 'Service';
196201
$this->systemInstance = \OC::$server->get($systemClass);
197202
$this->systemInstance->setImportService($this);
198203
}
@@ -421,7 +426,7 @@ protected function validateConfig(): void {
421426
}
422427

423428
public function getJsonSchemaPath(): string {
424-
return __DIR__ . '/fixtures/config-' . $this->getSystem() . '-schema.json';
429+
return $this->getImportSystem()->getJsonSchemaPath();
425430
}
426431

427432
public function validateOwner(): void {

lib/Service/Importer/Systems/TrelloApiService.php

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,15 @@ public function bootstrap(): void {
6666
parent::bootstrap();
6767
}
6868

69+
public function getJsonSchemaPath(): string {
70+
return implode(DIRECTORY_SEPARATOR, [
71+
__DIR__,
72+
'..',
73+
'fixtures',
74+
'config-trelloApi-schema.json',
75+
]);
76+
}
77+
6978
private function populateActions(): void {
7079
$data = $this->getImportService()->getData();
7180
$data->actions = $this->doRequest(

lib/Service/Importer/Systems/TrelloJsonService.php

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,15 @@ public function bootstrap(): void {
6565
$this->validateUsers();
6666
}
6767

68+
public function getJsonSchemaPath(): string {
69+
return implode(DIRECTORY_SEPARATOR, [
70+
__DIR__,
71+
'..',
72+
'fixtures',
73+
'config-trelloJson-schema.json',
74+
]);
75+
}
76+
6877
public function validateUsers(): void {
6978
if (empty($this->getImportService()->getConfig('uidRelation'))) {
7079
return;

tests/unit/Service/Importer/BoardImportServiceTest.php

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,8 +35,10 @@
3535
use OCA\Deck\Db\LabelMapper;
3636
use OCA\Deck\Db\Stack;
3737
use OCA\Deck\Db\StackMapper;
38+
use OCA\Deck\Event\BoardImportGetAllowedEvent;
3839
use OCA\Deck\Service\Importer\Systems\TrelloJsonService;
3940
use OCP\Comments\ICommentsManager;
41+
use OCP\EventDispatcher\IEventDispatcher;
4042
use OCP\IDBConnection;
4143
use OCP\IUser;
4244
use OCP\IUserManager;
@@ -63,6 +65,8 @@ class BoardImportServiceTest extends \Test\TestCase {
6365
private $attachmentMapper;
6466
/** @var ICommentsManager|MockObject */
6567
private $commentsManager;
68+
/** @var IEventDispatcher|MockObject */
69+
private $eventDispatcher;
6670
/** @var TrelloJsonService|MockObject */
6771
private $trelloJsonService;
6872
/** @var BoardImportService|MockObject */
@@ -77,6 +81,7 @@ public function setUp(): void {
7781
$this->assignmentMapper = $this->createMock(AssignmentMapper::class);
7882
$this->attachmentMapper = $this->createMock(AttachmentMapper::class);
7983
$this->commentsManager = $this->createMock(ICommentsManager::class);
84+
$this->eventDispatcher = $this->createMock(IEventDispatcher::class);
8085
$this->boardImportService = new BoardImportService(
8186
$this->userManager,
8287
$this->boardMapper,
@@ -86,18 +91,33 @@ public function setUp(): void {
8691
$this->assignmentMapper,
8792
$this->attachmentMapper,
8893
$this->cardMapper,
89-
$this->commentsManager
94+
$this->commentsManager,
95+
$this->eventDispatcher
9096
);
9197

9298
$this->boardImportService->setSystem('trelloJson');
9399

100+
$this->eventDispatcher
101+
->method('dispatchTyped')
102+
->willReturnCallback(function (BoardImportGetAllowedEvent $event) {
103+
$event->getService()->addAllowedImportSystem([
104+
'name' => TrelloJsonService::$name,
105+
'class' => TrelloJsonService::class,
106+
'internalName' => 'trelloJson'
107+
]);
108+
});
109+
94110
$data = json_decode(file_get_contents(__DIR__ . '/../../../data/data-trelloJson.json'));
95111
$this->boardImportService->setData($data);
96112

97-
$configInstance = json_decode(file_get_contents(__DIR__ . '/../../../data/config-trelloJson.json'));
113+
$configFile = __DIR__ . '/../../../data/config-trelloJson.json';
114+
$configInstance = json_decode(file_get_contents($configFile));
98115
$this->boardImportService->setConfigInstance($configInstance);
99116

100117
$this->trelloJsonService = $this->createMock(TrelloJsonService::class);
118+
$this->trelloJsonService
119+
->method('getJsonSchemaPath')
120+
->willReturn($configFile);
101121
$this->boardImportService->setImportSystem($this->trelloJsonService);
102122

103123
$owner = $this->createMock(IUser::class);

0 commit comments

Comments
 (0)