-
Notifications
You must be signed in to change notification settings - Fork 7
Conversations
When it comes to chatbots, you probably don't want to react to single keywords, but instead, you might need to gather information from the user, using a conversation. Let's say that you want your chatbot to provide a rich user onboarding experience for your application users. In the onboarding process, we are going to ask the user for their first name and email address - that's a perfect fit for conversations! (from botman)
Important!: By default, Botter uses File System Json Cache. This driver uses Hard Drive for storing data. We recommend you using a better and optimized driver like Redis. Check the Botter Object Instance wiki section for more information about migrating to Redis.
You can start a conversation with startConversation()
On::text("/signup", function() use($botter){
$botter->startConversation(new SignupConversation);
});And take a look at SignupConversation class (a class extended from ffb255\Botter\Conversations\Conversation class):
use ffb255\Botter\Conversations\Conversation;
class SignupConversation extends Conversation {
public function start()
{
$this->say("Welcome, Whats your name?");
$this->next("askEmail");
}
public function askEmail()
{
$this->name = $this->getAnswer()->getText();
$this->say("Whats your email?");
$this->next("finishSignup");
}
public function finishSignup()
{
// Insert user data do DB
// ..
$name = $this->name;
$this->say("Thanks {$name}! Your account has been created.");
$this->finish();
}
}looks easy!
When you start a conversation with startConversation(), Botter automatiaclly call start() method on your Conversation Class, and a conversation begin start with user.
Then you determine the next step in your conversation by $this->next(). Each method in you class can be a step in your conversation.
A conversation class extends from ffb255\Botter\Conversations\Conversation parent class. This class determines a logic for your bot conversation. Each method is a step of conversation.
All conversation starts with the start() method in your class.
use ffb255\Botter\Conversations\Conversation;
// Simple conversation logic class
class SignupConversation extends Conversation {
public function start(){
// First step in your conversation
}
}You can access to Botter instance via $this->botter and access to all Botter methods.
class SignupConversation extends Conversation {
public function start(){
$this->botter->say("Hello");
}
}For convenience, the two methods say() and reply() are directly applicable. But for other Botther methods you should call Botter instance in $this->botter.
You can set the next step in your conversation with $this->next() method, accept a string parameter from your next step method name.
class SignupConversation extends Conversation {
public function start(){
$this->botter->say("Hello, you are in start method. Your next request will be sent to secondStep()");
$this->next("secondStep");
}
public function secondStep() {
$this->botter->say("You are in second step. Your next request will be sent to thirdStep()");
$this->next("thirdStep");
}
public function thirdStep() {
$this->botter->say("You are third step. your conversation will be end after this message.");
$this->finish();
}
}

In your conversation logic class, when you set a property, it automatically saves into user conversation storage, and you can access this data during the next requests.
public function start()
{
$this->say("Welcome, Whats your name?");
$this->next("askEmail");
}
public function askEmail()
{
$this->name = $this->botter->getUpdate()->getMessage()->getText();
$this->say("Whats your email?");
$this->next("finishSignup");
}
public function finishSignup()
{
// Insert user data do DB
// ..
$name = $this->name;
$this->say("Thanks {$name}! Your account has been created.");
$this->finish();
}
}

When you use $this->next(), You are setting your next request step. But you can jump into another step in current request with $this->jumpTo().
Check this example:
class SignupConversation extends Conversation {
public function start()
{
$this->say("How old are you?");
$this->next("checkAge");
}
public function checkAge()
{
$age = $this->botter->getUpdate()->getMessage()->getText();
if ( $age > 18 ) {
$this->jumpTo("finishSignup");
} else {
$this->say("You are under 18! Enter your age again");
return;
}
}
public function finishSignup()
{
$this->say("You are signed up successfully!");
$this->finish();
}
}

As you saw previously, You can stop conversation with $this->finish(). This method will finish the current conversation with the user.
class SignupConversation extends Conversation {
public function start(){
$this->say("Hello and Bye");
$this->finish()
}
}$this->ask() and $this->then() are two useful methods in Botter conversations. These methods allow you to validate user input and decide which method should handle the request in next step.
Let's re-write our previous example about asking age conversation:
class SignupConversation extends Conversation {
public function start()
{
$this->ask("How old are you?")->then(function(){
$age = $this->getAnswer()->getText();
if ($age > 18){
$this->jumpTo("finishSignup");
} else{
$this->say("You are under 18! Enter your age again");
}
});
}
public function finishSignup()
{
$this->say("You are signed up successfully!");
$this->finish();
}
}

Note: If you pass string to $this->ask(), Botter will send message to your user with this string, But you can pass an anonymous function:
$this->ask(function(){
// Do something
// ..
$this->say("How old are you?");
})->then(function(){
$age = $this->getAnswer()->getText();
if ($age > 18){
$this->jumpTo("finishSignup");
} else{
$this->say("You are under 18! Enter your age again");
}
});As botter 1.2.0, you can add a boot() method to your conversation logic class. Botter automatically calls this method before each step and you can have more control over your conversation flow.
Let's consider you need to add a /cancel command to stop conversation in any step:
class BookingFlightConversation extends Conversation {
// This method will call in any request on this conversation
public function boot(){
$userText = $this->botter->getUpdate()->getMessage()->getText();
if ($userText == '/cancel') {
$this->reply("No Problem! Enter /start to open main menu");
$this->finish();
}
}
public function start(){
$this->say("Where do you want to travel?");
$this->next('askTripTime');
}
public function askTripTime(){
$this->destination = $this->botter->getUpdate()->getMessage()->getText();
$this->say("Cool, When do you want to travel to {$this->destination}?");
$this->next('askFellowTraveler');
}
public function askFellowTraveler(){
$this->tripTime = $this->botter->getUpdate()->getMessage()->getText();
$this->say("How many companions do you have in this trip?");
$this->next('bookTravel');
}
public function bookTravel(){
$this->numberOfFellowTraveler = $this->botter->getUpdate()->getMessage()->getText();
$this->say("All done! Your trip to {$this->destination} booked for {$this->tripTime} with {$this->numberOfFellowTraveler} passangers");
$this->finish();
}
}

As you saw previously, When you call $botter->startConversation() it automatically call your conversation start() method. You can change this behavior by pass your custom method name:
class SignupConversation extends Conversation {
public function myStarterMethod(){
$this->say("Hello and Bye");
$this->finish()
}
}
On::text("/signup", function() use($botter){
$botter->startConversation(new SignupConversation, 'myStarterMethod');
});It may help you to make resumable conversations.
- Let's play with Botter
- Core Concepts
- Conversations
-
Advanced Topics
- Botter Object Instance
- Cache and Storage
- MISCELLANEOUS