Completed
Push — master ( 8470e3...ad08f4 )
by Danilo
03:56
created

Language::setLanguageDatabase()   B

Complexity

Conditions 3
Paths 3

Size

Total Lines 24
Code Lines 14

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 12

Importance

Changes 0
Metric Value
dl 0
loc 24
ccs 0
cts 13
cp 0
rs 8.9713
c 0
b 0
f 0
cc 3
eloc 14
nc 3
nop 1
crap 12
1
<?php
2
3
/*
4
 * This file is part of the PhpBotFramework.
5
 *
6
 * PhpBotFramework is free software: you can redistribute it and/or modify
7
 * it under the terms of the GNU Lesser General Public License as
8
 * published by the Free Software Foundation, version 3.
9
 *
10
 * PhpBotFramework is distributed in the hope that it will be useful, but
11
 * WITHOUT ANY WARRANTY; without even the implied warranty of
12
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GN
13
 * Lesser General Public License for more details.
14
 *
15
 * You should have received a copy of the GNU Lesser General Public License
16
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17
 */
18
19
namespace PhpBotFramework\Localization;
20
21
use PhpBotFramework\Exceptions\BotException;
22
23
trait Language
24
{
25
26
    /**
27
     * \addtogroup Localization Localization
28
     * \brief Create a localized bot.
29
     * \details Using both a sql database and a redis database you can develop a localized bot with just a small impact on the performance.
30
     * By default the sql database will store the language permanently in a table which name is defined in $user_table.
31
     * The redis database will cache the language for the chat_id for a variable time.
32
     * You can use only the sql database if a redis database is not accessible.
33
     * These methods will treat groups as User so they will be stored in the table as normal user does.
34
     * @{
35
     */
36
37
    /** \brief Stores the language for a multi-language bot */
38
    public $language;
39
40
    /** PDO connection to the database. */
41
    public $pdo;
42
43
    /** \brief Table containing bot users data into database. */
44
    public $user_table = '"User"';
45
46
    /** \brief Name of the column that represents the user ID into database */
47
    public $id_column = 'chat_id';
48
49
    /**
50
     * \brief Get current user's language from the database, and set it in $language.
51
     * @param string $default_language <i>Optional</i>. Default language to return in case of errors.
52
     * @return string Language set for the current user, $default_language on errors.
53
     */
54
    public function getLanguageDatabase(string $default_language = 'en')
55
    {
56
        // If we have no database
57
        if (!isset($this->_database)) {
58
            $this->language = $default_language;
59
            return $default_language;
60
        }
61
62
        // Get the language from the bot
63
        $sth = $this->pdo->prepare('SELECT language FROM ' . $this->user_table . ' WHERE '
64
                                                           . $this->id_column . ' = :chat_id');
65
        $sth->bindParam(':chat_id', $this->_chat_id);
0 ignored issues
show
Bug introduced by
The property _chat_id does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
66
67
        try {
68
            $sth->execute();
69
        } catch (PDOException $e) {
0 ignored issues
show
Bug introduced by
The class PhpBotFramework\Localization\PDOException does not exist. Did you forget a USE statement, or did you not list all dependencies?

Scrutinizer analyzes your composer.json/composer.lock file if available to determine the classes, and functions that are defined by your dependencies.

It seems like the listed class was neither found in your dependencies, nor was it found in the analyzed files in your repository. If you are using some other form of dependency management, you might want to disable this analysis.

Loading history...
70
            echo $e->getMessage();
71
        }
72
73
        $row = $sth->fetch();
74
        $sth = null;
0 ignored issues
show
Unused Code introduced by
$sth is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
75
76
        if (isset($row['language'])) {
77
            $this->language = $row['language'];
78
            return $row['language'];
79
        }
80
81
        // If we couldn't get it, set the language to the default one
82
        $this->language = $default_language;
83
        return $this->language;
84
    }
85
86
    /**
87
     * \brief Set the current user language in database and internally.
88
     * \details Save it into database first.
89
     * @param string $language The language to set.
90
     * @return bool On sucess, return true, throws exception otherwise.
91
     */
92
    public function setLanguageDatabase(string $language) : bool
93
    {
94
        if (!isset($this->_database)) {
95
            throw new BotException('Database connection not set');
96
        }
97
98
        // Update the language in the database
99
        $sth = $this->pdo->prepare('UPDATE ' . $this->user_table . ' SET language = :language WHERE '
100
                                             . $this->id_column . ' = :id');
101
        $sth->bindParam(':language', $language);
102
        $sth->bindParam(':id', $this->_chat_id);
103
104
        try {
105
            $sth->execute();
106
        } catch (PDOException $e) {
0 ignored issues
show
Bug introduced by
The class PhpBotFramework\Localization\PDOException does not exist. Did you forget a USE statement, or did you not list all dependencies?

Scrutinizer analyzes your composer.json/composer.lock file if available to determine the classes, and functions that are defined by your dependencies.

It seems like the listed class was neither found in your dependencies, nor was it found in the analyzed files in your repository. If you are using some other form of dependency management, you might want to disable this analysis.

Loading history...
107
            throw new BotException($e->getMessage());
108
        }
109
        $sth = null;
0 ignored issues
show
Unused Code introduced by
$sth is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
110
111
        // Set language internally
112
        $this->language = $language;
113
114
        return true;
115
    }
116
117
    /**
118
     * \brief Get current user language from Redis (as a cache) and set it in language.
119
     * \details Using Redis as cache, check for the language. On failure, get the language
120
     * from the database and store it (with default expiring time of one day) in Redis.
121
     *
122
     * It also change $language parameter of the bot to the language returned.
123
     * @param string $default_language <i>Optional</i>. Default language to return in case of errors.
124
     * @param int $expiring_time <i>Optional</i>. Set the expiring time for the language on
125
     * redis each time it is took from the sql database.
126
     * @return string Language for the current user, $default_language on errors.
127
     */
128
    public function getLanguageRedis(string $default_language = 'en', int $expiring_time = 86400) : string
129
    {
130
        if (!isset($this->redis) || !isset($this->pdo)) {
131
            return $default_language;
132
        }
133
134
        // Check if the language exists on Redis
135 View Code Duplication
        if ($this->redis->exists($this->_chat_id . ':language')) {
136
            $this->language = $this->redis->get($this->_chat_id . ':language');
0 ignored issues
show
Bug introduced by
The property redis does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
137
            return $this->language;
138
        }
139
140
        // Set the value from the database
141
        $this->redis->setEx(
142
            $this->_chat_id . ':language',
143
            $expiring_time,
144
            $this->getLanguageDatabase($default_language)
145
        );
146
        return $this->language;
147
    }
148
149
    /**
150
     * \brief Set the current user language in both Redis, database and internally.
151
     * \details Save it into database first, then create the expiring key on Redis.
152
     * @param string $language The language to set.
153
     * @param int $expiring_time <i>Optional</i>. Time for the language key in redis to expire.
154
     * @return bool On sucess, return true, throws exception otherwise.
155
     */
156
    public function setLanguageRedis(string $language, int $expiring_time = 86400) : bool
157
    {
158
        if (!isset($this->redis)) {
159
            throw new BotException('Database connection not set');
160
        }
161
162
        // If we could successfully set the language in the database
163
        if ($this->setLanguageDatabase($language)) {
164
165
            // Set the language in Redis
166
            $this->redis->setEx($this->_chat_id . ':language', $expiring_time, $language);
167
            return true;
168
        }
169
170
        return false;
171
    }
172
173
    /** @} */
174
}
175