Skip to content

Commit b126ad1

Browse files
author
Erick Ruiz de Chavez
authored
Add greeter functionality (#28)
* Add Greeter functionality * Add tests * Add some spaces and clarify the use of `count+1` * Delete old tests file
1 parent e7a15ed commit b126ad1

File tree

8 files changed

+278
-38
lines changed

8 files changed

+278
-38
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,3 +8,4 @@
88
vendor
99
db/phpmxbot.db
1010
.env
11+
/.phpunit.cache

db/sql/V2__Greeter.sql

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
DROP TABLE IF EXISTS "greeter";
2+
CREATE TABLE "greeter" (
3+
"channel" text NOT NULL,
4+
"message" text NOT NULL,
5+
"order" text NOT NULL,
6+
"method" text NOT NULL
7+
);

src/Conversation/Greeter.php

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
<?php
2+
3+
namespace PhpMx\Conversation;
4+
5+
use BotMan\BotMan\BotMan;
6+
use PhpMx\Conversation\ConversationInterface;
7+
use PhpMx\Services\Greeter as GreeterService;
8+
use Symfony\Component\HttpFoundation\ParameterBag;
9+
10+
class Greeter implements ConversationInterface
11+
{
12+
private $greeterService;
13+
14+
public function __construct(GreeterService $greeterService)
15+
{
16+
$this->greeterService = $greeterService;
17+
}
18+
19+
public function handleEvent(ParameterBag $payload, BotMan $bot)
20+
{
21+
$event = $payload->get('event');
22+
$channel = $event['channel'];
23+
$user = $event['user'];
24+
25+
$messages = $this->greeterService->getMessagesFor($channel);
26+
27+
$additionalParameters = [
28+
'link_names' => true,
29+
'unfurl_links' => true,
30+
'unfurl_media' => true,
31+
];
32+
33+
foreach ($messages as $message) {
34+
$text = $this->renderMessage($message['message'], $event);
35+
$to = $message['method'] === 'channel' ? $channel : $user;
36+
$bot->say($text, $to, null, $additionalParameters);
37+
}
38+
}
39+
40+
public static function renderMessage($message, $event)
41+
{
42+
$channel = $event['channel'];
43+
$user = $event['user'];
44+
45+
return str_replace(['{user}', '{channel}'], ["<@{$user}>", "<#{$channel}>"], $message);
46+
}
47+
48+
public function subscribe(BotMan $botman)
49+
{
50+
$botman->on('member_joined_channel', [$this, 'handleEvent']);
51+
}
52+
}

src/Drivers/CustomDriver.php

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,13 @@ public function hasMatchingEvent()
2121
return $event;
2222
}
2323

24+
if ($payload->get('type') === 'event_callback' && $payload->get('event')['type'] === 'member_joined_channel') {
25+
$event = new GenericEvent($payload);
26+
$event->setName($payload->get('event')['type']);
27+
28+
return $event;
29+
}
30+
2431
parent::hasMatchingEvent();
2532
}
2633
}

src/Services/Greeter.php

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
<?php
2+
3+
namespace PhpMx\Services;
4+
5+
use SQLite3;
6+
7+
class Greeter
8+
{
9+
private $db;
10+
11+
public function __construct(SQLite3 $db)
12+
{
13+
$this->db = $db;
14+
}
15+
16+
public function getMessagesFor(string $channel)
17+
{
18+
$sql = <<<SQL
19+
SELECT *
20+
FROM greeter
21+
WHERE channel = :channel
22+
ORDER BY `order` ASC
23+
SQL;
24+
25+
$query = $this->db->prepare($sql);
26+
$query->bindValue(':channel', $channel);
27+
28+
$result = $query->execute();
29+
$messages = [];
30+
while ($row = $result->fetchArray(SQLITE3_ASSOC)) {
31+
$messages[] = $row;
32+
}
33+
34+
return $messages;
35+
}
36+
}

test.php

Lines changed: 0 additions & 38 deletions
This file was deleted.
Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace PhpMx\Tests\Unit\Conversation;
6+
7+
use BotMan\BotMan\BotMan;
8+
use PhpMx\Conversation\Greeter;
9+
use PhpMx\Services\Greeter as ServicesGreeter;
10+
use PHPUnit\Framework\TestCase;
11+
use Symfony\Component\HttpFoundation\ParameterBag;
12+
13+
final class GreeterTest extends TestCase
14+
{
15+
public function testSubscribe()
16+
{
17+
$botmanMock = $this->createMock(BotMan::class);
18+
$serviceMock = $this->createMock(ServicesGreeter::class);
19+
20+
$greeter = new Greeter($serviceMock);
21+
22+
$botmanMock->expects($this->once())
23+
->method('on')
24+
->with('member_joined_channel', [$greeter, 'handleEvent']);
25+
26+
$greeter->subscribe($botmanMock);
27+
}
28+
29+
public function provideRenderMessages()
30+
{
31+
$event = [
32+
'user' => 'foo',
33+
'channel' => 'bar',
34+
];
35+
36+
return [
37+
'plain text' => [
38+
'Lorem ipsum dolor sit amet, consectetur adipiscing elit.',
39+
'Lorem ipsum dolor sit amet, consectetur adipiscing elit.',
40+
$event,
41+
],
42+
'only user' => [
43+
'Lorem ipsum <@foo> dolor sit amet, consectetur adipiscing elit.',
44+
'Lorem ipsum {user} dolor sit amet, consectetur adipiscing elit.',
45+
$event,
46+
],
47+
'only channel' => [
48+
'Lorem ipsum dolor sit amet, <#bar> consectetur adipiscing elit.',
49+
'Lorem ipsum dolor sit amet, {channel} consectetur adipiscing elit.',
50+
$event,
51+
],
52+
'user and channel' => [
53+
'Lorem <@foo> ipsum dolor sit amet, <#bar> consectetur adipiscing elit.',
54+
'Lorem {user} ipsum dolor sit amet, {channel} consectetur adipiscing elit.',
55+
$event,
56+
],
57+
];
58+
}
59+
60+
/**
61+
* @dataProvider provideRenderMessages
62+
*/
63+
public function testRenderMessage($expected, $message, $event)
64+
{
65+
$this->assertEquals($expected, Greeter::renderMessage($message, $event));
66+
}
67+
68+
public function provideGreeterMessages(): array
69+
{
70+
$user = 'UFOO';
71+
$channel = 'CBAR';
72+
$parameterBag = new ParameterBag([
73+
'event' => [
74+
'user' => $user,
75+
'channel' => $channel,
76+
]
77+
]);
78+
79+
return [
80+
'no messages' => [
81+
$parameterBag,
82+
[]
83+
],
84+
'plain text message' => [
85+
$parameterBag,
86+
[
87+
[
88+
'message' => 'This is a test',
89+
'method' => ''
90+
]
91+
]
92+
],
93+
];
94+
}
95+
96+
/**
97+
* @dataProvider provideGreeterMessages
98+
*/
99+
public function testHandleEvent(ParameterBag $payload, $messages)
100+
{
101+
$serviceMock = $this->createMock(ServicesGreeter::class);
102+
$serviceMock->expects($this->once())
103+
->method('getMessagesFor')
104+
->with($payload->get('event')['channel'])
105+
->willReturn($messages);
106+
107+
$botmanMock = $this->createMock(BotMan::class);
108+
$botmanMock->expects($this->exactly(count($messages)))->method('say');
109+
110+
$greeter = new Greeter($serviceMock);
111+
$greeter->handleEvent($payload, $botmanMock);
112+
}
113+
}

tests/Unit/Services/GreeterTest.php

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace PhpMx\Tests\Unit\Services;
6+
7+
use PhpMx\Services\Greeter;
8+
use PHPUnit\Framework\TestCase;
9+
use SQLite3;
10+
use SQLite3Result;
11+
use SQLite3Stmt;
12+
13+
final class GreeterTest extends TestCase
14+
{
15+
public function provideGreeterMessages(): array
16+
{
17+
return [
18+
'no messages' => ['foo', []],
19+
'one message' => ['bar', ['one message']],
20+
'multiple messages' => ['baz', ['one message', 'two messages']],
21+
];
22+
}
23+
24+
/**
25+
* @param string $channel
26+
* @param array $messages
27+
* @dataProvider provideGreeterMessages
28+
*/
29+
public function testGetMessagesFor(string $channel, array $messages): void
30+
{
31+
$resultMock = $this->createMock(SQLite3Result::class);
32+
33+
// `fetchArray` is called inside a while loop, therefore it is
34+
// count($messages) + 1 times, that is
35+
// at least once even if the array is empty.
36+
$resultMock->expects($this->exactly(count($messages) + 1))
37+
->method('fetchArray')
38+
->with(SQLITE3_ASSOC)
39+
->willReturnOnConsecutiveCalls(...$messages);
40+
41+
$queryMock = $this->createMock(SQLite3Stmt::class);
42+
43+
$queryMock->expects($this->once())
44+
->method('bindValue')
45+
->with(':channel', $channel);
46+
47+
$queryMock->expects($this->once())
48+
->method('execute')
49+
->willReturn($resultMock);
50+
51+
$sqlMock = $this->createMock(SQLite3::class);
52+
53+
$sqlMock->expects($this->once())
54+
->method('prepare')
55+
->willReturn($queryMock);
56+
57+
$greeter = new Greeter($sqlMock);
58+
$result = $greeter->getMessagesFor($channel);
59+
60+
$this->assertEquals($messages, $result);
61+
}
62+
}

0 commit comments

Comments
 (0)