Completed
Pull Request — master (#2282)
by ྅༻ Ǭɀħ
01:44
created

Options::add()   B

Complexity

Conditions 5
Paths 7

Size

Total Lines 36
Code Lines 18

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 5
eloc 18
nc 7
nop 2
dl 0
loc 36
rs 8.439
c 0
b 0
f 0
1
<?php
2
3
/**
4
 * YOURLS Options
5
 *
6
 * Note to plugin authors: you most likely SHOULD NOT use directly methods and properties of this class. Use instead
7
 * function wrappers (eg don't use $ydb->option, or $ydb->get(), use yourls_*_options() functions instead).
8
 *
9
 * Note to devs: this class internally uses function wrappers eg yourls_*_options() instead of direct methods, to
10
 * comply to any filter set in the function wrappers (eg $this->update() uses yourls_get_option()).
11
 * Maybe in the future this will look as a dumb idea?
12
 * The alternative would be to move return filters from function wrappers to here, but I think this will make things
13
 * less readable for users.
14
 *
15
 * @since 1.7.3
16
 */
17
18
namespace YOURLS\Database;
19
20
use YOURLS\Database\YDB;
21
22
23
class Options {
24
25
    /**
26
     * Hold a copy of the all mighty $ydb global
27
     *
28
     * @var \YOURLS\Database\YDB
29
     */
30
    protected $ydb;
31
32
    public function __construct(YDB $ydb) {
33
        $this->ydb = $ydb;
34
    }
35
36
    /**
37
     * Read all options from DB at once
38
     *
39
     * @since  1.7.3
40
     * @return bool
41
     */
42
    public function get_all_options() {
43
        // Get option values from DB
44
        $table = YOURLS_DB_TABLE_OPTIONS;
45
        $sql = "SELECT option_name, option_value FROM $table WHERE 1=1";
46
        $options = (array) $this->ydb->fetchPairs($sql);
47
48
        if(empty($options)) {
49
            return false;
50
        }
51
52
        foreach($options as $name => $value) {
53
            $this->ydb->set_option($name, yourls_maybe_unserialize($value));
54
        }
55
56
        yourls_apply_filter('get_all_options', 'deprecated');
57
58
        return true;
59
    }
60
61
    /**
62
     * Get option value from DB (or from cache if available). Return value or $default if not found
63
     *
64
     * @since  1.7.3
65
     * @param  string $name     Option name
66
     * @param  string $default  Optional value to return if option doesn't exist
67
     * @return mixed            Value set for the option
68
     */
69
    public function get($name, $default) {
70
        $name = trim((string)$name);
71
        if (empty($name)) {
72
            return $default;
73
        }
74
75
        // Check if option value is cached already
76
        if($this->ydb->has_option($name)) {
77
            return $this->ydb->get_option($name);
78
        }
79
80
        // Get option value from DB
81
        $table = YOURLS_DB_TABLE_OPTIONS;
82
        $sql = "SELECT option_value FROM $table WHERE option_name = :option_name LIMIT 1";
83
        $bind = array('option_name' => $name);
84
85
        // Use fechOne() to get array('option_value'=>$value), or false if not found.
86
        // This way, we can effectively store false as an option value, and not confuse with false as the default return value
87
        $value = $this->ydb->fetchOne($sql, $bind);
88
        if($value !== false) {
89
            $value = yourls_maybe_unserialize( $value['option_value'] );
90
            // Cache option value to save a DB query if needed later
91
            $this->ydb->set_option($name, $value);
92
        } else {
93
            $value = $default;
94
        }
95
96
        /**
97
         * We don't cache value if option is not set, to make a difference between "not found: returning false"
98
         * and "found, and value is false".
99
         * This way, we can:
100
         * $check = yourls_get_option('doesnt_exist'); // false
101
         * yourls_add_option('doesnt_exist', 'value'); // will work, because check on has_option() will return false
102
         */
103
104
        return $value;
105
    }
106
107
    /**
108
     * Update (add if doesn't exist) an option to DB
109
     *
110
     * @since  1.7.3
111
     * @param  string $name      Option name. Expected to not be SQL-escaped.
112
     * @param  mixed  $newvalue  Option value.
113
     * @return bool              False if value was not updated, true otherwise.
114
     */
115
    public function update($name, $newvalue) {
116
        $name = trim((string)$name);
117
        if (empty($name)) {
118
            return false;
119
        }
120
121
        // Use clone to break object refs -- see commit 09b989d375bac65e692277f61a84fede2fb04ae3
122
        if (is_object($newvalue)) {
123
            $newvalue = clone $newvalue;
124
        }
125
126
        $oldvalue = yourls_get_option($name);
127
128
        // If the new and old values are the same, no need to update.
129
        if ($newvalue === $oldvalue) {
130
            return false;
131
        }
132
133
        // If this is a new option, just add it
134
        if (false === $oldvalue) {
135
            return $this->add($name, $newvalue);
136
        }
137
138
        $_newvalue = yourls_maybe_serialize($newvalue);
139
        $table = YOURLS_DB_TABLE_OPTIONS;
140
        $sql  = "UPDATE $table SET option_value = :value WHERE option_name = :name";
141
        $bind = array('name' => $name, 'value' => $_newvalue);
142
        $do   = $this->ydb->fetchAffected($sql, $bind);
143
144
        if($do !== 1) {
145
            // Something went wrong :(
146
            return false;
147
        }
148
149
        // Cache option value to save a DB query if needed later
150
        $this->ydb->set_option($name, $newvalue);
151
    	yourls_do_action( 'update_option', $name, $oldvalue, $newvalue );
152
        return true;
153
    }
154
155
    /**
156
     * Add an option to the DB
157
     *
158
     * @since  1.7.3
159
     * @param  string $name   Name of option to add. Expected to not be SQL-escaped.
160
     * @param  mixed  $value  Optional option value. Must be serializable if non-scalar. Expected to not be SQL-escaped.
161
     * @return bool           False if option was not added (eg already exists), true otherwise.
162
     */
163
    public function add($name, $value) {
164
        $name = trim((string)$name);
165
        if (empty($name)) {
166
            return false;
167
        }
168
169
        // Use clone to break object refs -- see commit 09b989d375bac65e692277f61a84fede2fb04ae3
170
        if (is_object($value)) {
171
            $value = clone $value;
172
        }
173
174
        // Make sure the option doesn't already exist
175
        if ($this->ydb->has_option($name)) {
176
            return false;
177
        }
178
        // if (false !== yourls_get_option($name)) {
179
            // return false;
180
        // }
181
182
        $table = YOURLS_DB_TABLE_OPTIONS;
183
        $_value = yourls_maybe_serialize($value);
184
        $sql  = "INSERT INTO $table (option_name, option_value) VALUES (:name, :value)";
185
        $bind = array('name' => $name, 'value' => $_value);
186
        $do   = $this->ydb->fetchAffected($sql, $bind);
187
188
        if($do !== 1) {
189
            // Something went wrong :(
190
            return false;
191
        }
192
193
        // Cache option value to save a DB query if needed later
194
        $this->ydb->set_option($name, $value);
195
        yourls_do_action('add_option', $name, $_value);
196
197
        return true;
198
    }
199
200
    /**
201
     * Delete option from DB
202
     *
203
     * @since  1.7.3
204
     * @param  string $name  Option name to delete. Expected to not be SQL-escaped.
205
     * @return bool          False if option was not deleted (eg not found), true otherwise.
206
     */
207
    public function delete($name) {
208
        $name = trim((string)$name);
209
        if (empty($name)) {
210
            return false;
211
        }
212
213
        $table = YOURLS_DB_TABLE_OPTIONS;
214
        $sql = "DELETE FROM $table WHERE option_name = :name";
215
        $bind = array('name' => $name);
216
        $do   = $this->ydb->fetchAffected($sql, $bind);
217
218
        if($do !== 1) {
219
            // Something went wrong :(
220
            return false;
221
        }
222
223
        yourls_do_action('delete_option', $name);
224
        $this->ydb->delete_option($name);
225
        return true;
226
    }
227
228
}
229