Conversation.php 5.57 KB
Newer Older
MBoretto's avatar
MBoretto committed
1 2 3 4 5 6 7 8 9 10 11 12
<?php
/**
 * This file is part of the TelegramBot package.
 *
 * (c) Avtandil Kikabidze aka LONGMAN <akalongman@gmail.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Longman\TelegramBot;

13 14
use Longman\TelegramBot\Exception\TelegramException;

MBoretto's avatar
MBoretto committed
15
/**
16
 * Class Conversation
17 18 19
 *
 * Only one conversation can be active at any one time.
 * A conversation is directly linked to a user, chat and the command that is managing the conversation.
MBoretto's avatar
MBoretto committed
20
 */
21
class Conversation
MBoretto's avatar
MBoretto committed
22 23 24 25
{
    /**
     * All information fetched from the database
     *
26
     * @var array|null
MBoretto's avatar
MBoretto committed
27
     */
28
    protected $conversation;
MBoretto's avatar
MBoretto committed
29 30

    /**
31
     * Notes stored inside the conversation
MBoretto's avatar
MBoretto committed
32
     *
33
     * @var mixed
MBoretto's avatar
MBoretto committed
34
     */
35
    protected $protected_notes;
36 37 38 39

    /**
     * Notes to be stored
     *
40
     * @var mixed
41
     */
42
    public $notes;
MBoretto's avatar
MBoretto committed
43 44 45 46 47 48 49 50 51

    /**
     * Telegram user id
     *
     * @var int
     */
    protected $user_id;

    /**
52
     * Telegram chat id
MBoretto's avatar
MBoretto committed
53 54 55 56 57 58
     *
     * @var int
     */
    protected $chat_id;

    /**
59
     * Command to be executed if the conversation is active
MBoretto's avatar
MBoretto committed
60 61 62 63 64 65
     *
     * @var string
     */
    protected $command;

    /**
66
     * Conversation contructor to initialize a new conversation
MBoretto's avatar
MBoretto committed
67 68 69 70
     *
     * @param int    $user_id
     * @param int    $chat_id
     * @param string $command
71
     *
72
     * @throws TelegramException
MBoretto's avatar
MBoretto committed
73
     */
74
    public function __construct($user_id, $chat_id, $command = null)
MBoretto's avatar
MBoretto committed
75 76 77 78
    {
        $this->user_id = $user_id;
        $this->chat_id = $chat_id;
        $this->command = $command;
79 80

        //Try to load an existing conversation if possible
81
        if (!$this->load() && $command !== null) {
MBoretto's avatar
MBoretto committed
82 83 84 85 86
            //A new conversation start
            $this->start();
        }
    }

MBoretto's avatar
MBoretto committed
87
    /**
88
     * Clear all conversation variables.
MBoretto's avatar
MBoretto committed
89
     *
90
     * @return bool Always return true, to allow this method in an if statement.
MBoretto's avatar
MBoretto committed
91
     */
92
    protected function clear()
MBoretto's avatar
MBoretto committed
93
    {
94
        $this->conversation    = null;
95
        $this->protected_notes = null;
96
        $this->notes           = null;
97

98 99 100 101 102 103 104
        return true;
    }

    /**
     * Load the conversation from the database
     *
     * @return bool
105
     * @throws TelegramException
106 107 108
     */
    protected function load()
    {
109
        //Select an active conversation
110 111
        $conversation = ConversationDB::selectConversation($this->user_id, $this->chat_id, 1);
        if (isset($conversation[0])) {
MBoretto's avatar
MBoretto committed
112
            //Pick only the first element
113
            $this->conversation = $conversation[0];
MBoretto's avatar
MBoretto committed
114

115 116
            //Load the command from the conversation if it hasn't been passed
            $this->command = $this->command ?: $this->conversation['command'];
MBoretto's avatar
MBoretto committed
117

118 119 120
            if ($this->command !== $this->conversation['command']) {
                $this->cancel();
                return false;
MBoretto's avatar
MBoretto committed
121 122
            }

MBoretto's avatar
MBoretto committed
123
            //Load the conversation notes
MBoretto's avatar
MBoretto committed
124
            $this->protected_notes = json_decode($this->conversation['notes'], true);
125
            $this->notes           = $this->protected_notes;
MBoretto's avatar
MBoretto committed
126 127
        }

128
        return $this->exists();
MBoretto's avatar
MBoretto committed
129 130 131
    }

    /**
132
     * Check if the conversation already exists
MBoretto's avatar
MBoretto committed
133 134 135
     *
     * @return bool
     */
136
    public function exists()
MBoretto's avatar
MBoretto committed
137
    {
138 139 140 141 142 143 144
        return ($this->conversation !== null);
    }

    /**
     * Start a new conversation if the current command doesn't have one yet
     *
     * @return bool
145
     * @throws TelegramException
146 147 148
     */
    protected function start()
    {
Armando Lüscher's avatar
Armando Lüscher committed
149 150 151
        if ($this->command
            && !$this->exists()
            && ConversationDB::insertConversation(
152 153 154
                $this->user_id,
                $this->chat_id,
                $this->command
155
            )
156 157
        ) {
            return $this->load();
MBoretto's avatar
MBoretto committed
158
        }
159 160

        return false;
MBoretto's avatar
MBoretto committed
161 162 163
    }

    /**
164
     * Delete the current conversation
MBoretto's avatar
MBoretto committed
165
     *
MBoretto's avatar
MBoretto committed
166
     * Currently the Conversation is not deleted but just set to 'stopped'
167
     *
168
     * @return bool
169
     * @throws TelegramException
MBoretto's avatar
MBoretto committed
170
     */
MBoretto's avatar
MBoretto committed
171
    public function stop()
MBoretto's avatar
MBoretto committed
172
    {
173
        return ($this->updateStatus('stopped') && $this->clear());
MBoretto's avatar
MBoretto committed
174
    }
MBoretto's avatar
MBoretto committed
175

MBoretto's avatar
MBoretto committed
176
    /**
177
     * Cancel the current conversation
MBoretto's avatar
MBoretto committed
178
     *
179
     * @return bool
180
     * @throws TelegramException
MBoretto's avatar
MBoretto committed
181 182 183
     */
    public function cancel()
    {
184
        return ($this->updateStatus('cancelled') && $this->clear());
185 186 187 188 189 190 191 192
    }

    /**
     * Update the status of the current conversation
     *
     * @param string $status
     *
     * @return bool
193
     * @throws TelegramException
194 195 196 197 198 199
     */
    protected function updateStatus($status)
    {
        if ($this->exists()) {
            $fields = ['status' => $status];
            $where  = [
200
                'id'      => $this->conversation['id'],
201 202 203 204 205 206 207
                'status'  => 'active',
                'user_id' => $this->user_id,
                'chat_id' => $this->chat_id,
            ];
            if (ConversationDB::updateConversation($fields, $where)) {
                return true;
            }
MBoretto's avatar
MBoretto committed
208
        }
209 210

        return false;
MBoretto's avatar
MBoretto committed
211 212 213
    }

    /**
MBoretto's avatar
MBoretto committed
214
     * Store the array/variable in the database with json_encode() function
MBoretto's avatar
MBoretto committed
215
     *
216
     * @return bool
217
     * @throws TelegramException
MBoretto's avatar
MBoretto committed
218
     */
219
    public function update()
MBoretto's avatar
MBoretto committed
220
    {
221
        if ($this->exists()) {
MBoretto's avatar
MBoretto committed
222
            $fields = ['notes' => json_encode($this->notes)];
MBoretto's avatar
MBoretto committed
223
            //I can update a conversation whatever the state is
224
            $where = ['id' => $this->conversation['id']];
225 226 227
            if (ConversationDB::updateConversation($fields, $where)) {
                return true;
            }
MBoretto's avatar
MBoretto committed
228
        }
229 230

        return false;
MBoretto's avatar
MBoretto committed
231 232 233
    }

    /**
234
     * Retrieve the command to execute from the conversation
MBoretto's avatar
MBoretto committed
235
     *
236
     * @return string|null
MBoretto's avatar
MBoretto committed
237
     */
238
    public function getCommand()
MBoretto's avatar
MBoretto committed
239
    {
240
        return $this->command;
MBoretto's avatar
MBoretto committed
241 242
    }
}