Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 161
0.00% covered (danger)
0.00%
0 / 19
CRAP
0.00% covered (danger)
0.00%
0 / 1
MySqlSiteSettings
0.00% covered (danger)
0.00%
0 / 161
0.00% covered (danger)
0.00%
0 / 19
3660
0.00% covered (danger)
0.00%
0 / 1
 __construct
0.00% covered (danger)
0.00%
0 / 12
0.00% covered (danger)
0.00%
0 / 1
6
 isConsistent
0.00% covered (danger)
0.00%
0 / 13
0.00% covered (danger)
0.00%
0 / 1
42
 fetchSettings
0.00% covered (danger)
0.00%
0 / 17
0.00% covered (danger)
0.00%
0 / 1
12
 initEnvironment
0.00% covered (danger)
0.00%
0 / 3
0.00% covered (danger)
0.00%
0 / 1
2
 __isset
0.00% covered (danger)
0.00%
0 / 3
0.00% covered (danger)
0.00%
0 / 1
12
 __set
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 __get
0.00% covered (danger)
0.00%
0 / 5
0.00% covered (danger)
0.00%
0 / 1
12
 get
0.00% covered (danger)
0.00%
0 / 3
0.00% covered (danger)
0.00%
0 / 1
12
 getDescription
0.00% covered (danger)
0.00%
0 / 3
0.00% covered (danger)
0.00%
0 / 1
12
 getEnvironment
0.00% covered (danger)
0.00%
0 / 3
0.00% covered (danger)
0.00%
0 / 1
6
 set
0.00% covered (danger)
0.00%
0 / 11
0.00% covered (danger)
0.00%
0 / 1
42
 register
0.00% covered (danger)
0.00%
0 / 16
0.00% covered (danger)
0.00%
0 / 1
42
 getRegisteredSettings
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
12
 getLocales
0.00% covered (danger)
0.00%
0 / 7
0.00% covered (danger)
0.00%
0 / 1
6
 getThemes
0.00% covered (danger)
0.00%
0 / 7
0.00% covered (danger)
0.00%
0 / 1
6
 getPlugins
0.00% covered (danger)
0.00%
0 / 7
0.00% covered (danger)
0.00%
0 / 1
6
 getSystemInfo
0.00% covered (danger)
0.00%
0 / 12
0.00% covered (danger)
0.00%
0 / 1
2
 getLog
0.00% covered (danger)
0.00%
0 / 14
0.00% covered (danger)
0.00%
0 / 1
20
 store
0.00% covered (danger)
0.00%
0 / 20
0.00% covered (danger)
0.00%
0 / 1
56
1<?php
2
3namespace UserFrosting;
4
5/**
6 * MySqlSiteSettings Class
7 *
8 * A site settings database object for MySQL databases.
9 *
10 */
11class MySqlSiteSettings extends MySqlDatabase implements SiteSettingsInterface {
12
13    /**
14     * @var array An array of UF environment variables.  Should be read-only.
15     */
16    protected $_environment;
17
18    /**
19     * @var array A list of plugin names => arrays of settings for that plugin.  The core plugin is "userfrosting".
20     */    
21    protected $_settings;
22    
23    /**
24     * @var array A list of plugin names => arrays of descriptions for that plugin.  The core plugin is "userfrosting".
25     */ 
26    protected $_descriptions;
27    
28    /**
29     * @var array A list of settings that have been registered to appear in the site settings interface.
30     */ 
31    protected $_settings_registered;
32    
33    /**
34     * @var string The name of the table, including prefix, that contains the persistent site settings.
35     */ 
36    protected $_table;
37
38    /** Construct the site settings object, loading values from the database */
39    public function __construct($settings = [], $descriptions = []) {
40        $this->_table = static::getTable('configuration');
41        
42        // Initialize UF environment
43        $this->initEnvironment();
44        
45        // Set default settings first
46        $this->_settings = $settings;
47        $this->_descriptions = $descriptions;
48        
49        // Now, try to load settings from database if possible
50        try {
51            $results = $this->fetchSettings();
52            // Merge, replacing default settings with DB settings as necessary.
53            $this->_settings = array_replace_recursive($this->_settings , $results['settings']);
54            $this->_descriptions = array_replace_recursive($this->_descriptions, $results['descriptions']);
55        } catch (\PDOException $e){
56            $connection = static::connection();
57            $table = static::getTable('configuration')->name;
58            
59            // If the database connection is fine, but the table doesn't exist, create it!
60            $connection->query("CREATE TABLE IF NOT EXISTS `$table` (
61                `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
62                `plugin` varchar(50) NOT NULL COMMENT 'The name of the plugin that manages this setting (set to ''userfrosting'' for core settings)',
63                `name` varchar(150) NOT NULL COMMENT 'The name of the setting.',
64                `value` longtext NOT NULL COMMENT 'The current value of the setting.',
65                `description` text NOT NULL COMMENT 'A brief description of this setting.',
66                PRIMARY KEY (`id`)
67            ) ENGINE=InnoDB  DEFAULT CHARSET=utf8 COMMENT='A configuration table, mapping global configuration options to their values.' AUTO_INCREMENT=1 ;");
68        }
69    }
70    
71    public function isConsistent(){
72        $connection = static::connection();
73        $prefix = static::$app->config('db')['db_prefix'];
74        
75        $table_exists = $connection->query("SHOW TABLES LIKE '$prefix" . "configuration'")->rowCount() > 0;
76        
77        if (!$table_exists){
78            return false;
79        }
80
81        $db_data = $this->fetchSettings()['settings'];
82        foreach ($this->_settings as $plugin => $setting){
83            if (!isset($db_data[$plugin])){
84                return false;
85            }
86            foreach ($setting as $name => $value){
87                if (!isset($db_data[$plugin][$name])){
88                    return false;
89                }
90            }
91        }
92        return true;
93    }
94    
95    public function fetchSettings(){
96        $db = static::connection();
97        
98        $table = $this->_table->name;
99        
100        $stmt = $db->query("SELECT * FROM `$table`");
101                  
102        $results = [];
103        $results['settings'] = [];
104        $results['descriptions'] = [];
105        while ($row = $stmt->fetch(\PDO::FETCH_ASSOC)) {
106            $name = $row['name'];
107            $value = $row['value'];
108            $plugin = $row['plugin'];
109            $description = $row['description'];
110            if (!isset($results['settings'][$plugin])) {
111                $results['settings'][$plugin] = [];
112                $results['descriptions'][$plugin] = [];
113            }
114                        
115            $results['settings'][$plugin][$name] = $value;
116            $results['descriptions'][$plugin][$name] = $description;          
117        }
118        return $results;
119    }
120    
121    /**
122     * Initialize the environment (non-persistent) variables for the app.  This includes things like the public root URL, css URLs, etc.
123     *
124     */    
125    private function initEnvironment(){
126        $this->_environment = [
127            'uri' => static::$app->config('uri')
128        ];
129    }
130    
131    public function __isset($name) {
132        if (isset($this->_environment[$name]) || isset($this->_settings['userfrosting'][$name]))
133            return true;
134        else
135            return false;
136    }
137    
138    public function __set($name, $value){
139        return $this->set('userfrosting', $name, $value);   
140    }
141
142    public function __get($name){
143        if (isset($this->_environment[$name])){
144            return $this->_environment[$name];
145        } else if (isset($this->_settings['userfrosting'][$name])){
146            return $this->_settings['userfrosting'][$name];
147        } else {
148            throw new \Exception("The value '$name' does not exist in the core userfrosting settings.");
149        }
150    }
151
152    public function get($name, $plugin = "userfrosting"){
153        if (isset($this->_settings[$plugin]) && isset($this->_settings[$plugin][$name])){
154            return $this->_settings[$plugin][$name];
155        } else {
156            throw new \Exception("The value '$name' does not exist in the settings for plugin '$plugin'.");
157        }
158    }
159    
160    public function getDescription($name, $plugin = "userfrosting"){
161        if (isset($this->_settings[$plugin]) && isset($this->_descriptions[$plugin][$name])){
162            return $this->_descriptions[$plugin][$name];
163        } else {
164            throw new \Exception("The value '$name' does not exist in the setting descriptions for plugin '$plugin'.");
165        }
166    }
167    
168    public function getEnvironment($name){
169        if (isset($this->_environment[$name])){
170            return $this->_environment[$name];
171        } else {
172            throw new \Exception("The value '$name' does not exist in the settings environment.");
173        }
174    }
175    
176    public function set($plugin, $name, $value = null, $description = null){
177        if (!isset($this->_settings[$plugin])){
178            $this->_settings[$plugin] = [];
179            $this->_descriptions[$plugin] = [];
180        }
181        if ($value !== null) {
182            $this->_settings[$plugin][$name] = $value; 
183        } else {
184            if (!isset($this->_settings[$plugin][$name]))
185                $this->_settings[$plugin][$name] = ""; 
186        }
187        if ($description !== null) {
188            $this->_descriptions[$plugin][$name] = $description; 
189        } else {
190            if (!isset($this->_descriptions[$plugin][$name]))
191                $this->_descriptions[$plugin][$name] = ""; 
192        }
193    }
194    
195    public function register($plugin, $name, $label, $type = "text", $options = []){
196        // Get the array of settings & descriptions
197        if (isset($this->_settings[$plugin])){
198            $settings = $this->_settings[$plugin];
199            $descriptions = $this->_descriptions[$plugin];      
200        } else {
201            throw new \Exception("The plugin '$plugin' does not have any site settings.  Be sure to add them first by calling set().");
202        }
203
204        if (!isset($settings[$name])){
205            throw new \Exception("The plugin '$plugin' does not have a value for '$name'.  Please add it first by calling set().");
206        }
207        
208        // Check type
209        if (!in_array($type, ["readonly", "text", "toggle", "select"]))
210            throw new \Exception("Type must be one of 'readonly', 'text', 'toggle', or 'select'.");
211            
212        if (!isset($this->_settings_registered[$plugin]))
213            $this->_settings_registered[$plugin] = [];
214        if (!isset($this->_settings_registered[$plugin][$name]))
215            $this->_settings_registered[$plugin][$name] = [];
216            
217        $this->_settings_registered[$plugin][$name]['label'] = $label;
218        $this->_settings_registered[$plugin][$name]['type'] = $type;
219        $this->_settings_registered[$plugin][$name]['options'] = $options;
220        $this->_settings_registered[$plugin][$name]['description'] = $descriptions[$name];
221    }
222    
223    public function getRegisteredSettings(){
224        foreach ($this->_settings_registered as $plugin => $setting){
225            foreach ($setting as $name => $params){
226                $this->_settings_registered[$plugin][$name]['value'] = $this->_settings[$plugin][$name];
227            }
228        }
229        return $this->_settings_registered;
230    }
231    
232    // Get a list of all supported locales
233    public function getLocales(){
234        $directory = static::$app->config('locales.path');
235        $languages = glob($directory . "/*.php");
236        $results = [];
237        foreach ($languages as $language){
238            $basename = basename($language, ".php");
239            $results[$basename] = $basename;
240        }
241        return $results;
242    }
243
244    // Get a list of all supported themes
245    public function getThemes(){
246        $directory = static::$app->config('themes.path');
247        $themes = glob($directory . "/*", GLOB_ONLYDIR);
248        $results = [];
249        foreach ($themes as $theme){
250            $basename = basename($theme);
251            $results[$basename] = $basename;
252        }
253        return $results;
254    }
255    
256    // Get a list of all plugins
257    public function getPlugins(){
258        $directory = static::$app->config('plugins.path');
259        $themes = glob($directory . "/*", GLOB_ONLYDIR);
260        $results = [];
261        foreach ($themes as $theme){
262            $basename = basename($theme);
263            $results[$basename] = $basename;
264        }
265        return $results;
266    }
267    // Return an array of system and server configuration info
268    public function getSystemInfo(){
269        $results = [];
270        $results['UserFrosting Version'] = $this->version;
271        $results['Web Server'] = $_SERVER['SERVER_SOFTWARE'];
272        $results['PHP Version'] = phpversion();
273        $dbinfo = static::getInfo();
274        $results['Database Version'] = $dbinfo['db_type'] . " " .  $dbinfo['db_version'];
275        $results['Database Name'] = $dbinfo['db_name'];
276        $results['Table Prefix'] = $dbinfo['table_prefix'];
277        $environment = static::$app->environment();
278        $results['Application Root'] = static::$app->config('base.path');
279        $results['Document Root'] = $this->uri['public'];
280        return $results;
281    }
282    
283    // Return the error log
284    public function getLog($lines = null){
285        // Check if error logging is enabled
286        if (!ini_get("error_log")){
287            $path = "Unavailable";
288            $messages = ["You do not seem to have an error log set up.  Please check your php.ini file."];
289        } else if (!ini_get("log_errors")){
290            $path = ini_get('error_log');
291            $messages = ["Error logging appears to be disabled.  Please check your php.ini file."];
292        } else {    
293            $path = ini_get('error_log');
294            if ($lines){
295                $messages = array_reverse(array_slice(file($path), -$lines));
296            } else {
297                $messages = array_reverse(file($path));
298            }
299        }
300        return [
301            "path"      => $path,
302            "messages"  => $messages
303        ];
304    }
305    
306    public function store(){
307        // Get current values as stored in DB
308        $db_settings = $this->fetchSettings();
309        
310        $db = static::connection();
311        $table = $this->_table->name;
312        
313        $stmt_insert = $db->prepare("INSERT INTO `$table`
314            (plugin, name, value, description)
315            VALUES (:plugin, :name, :value, :description);");
316        
317        $stmt_update = $db->prepare("UPDATE `$table` SET
318            value = :value,
319            description = :description 
320            WHERE plugin = :plugin and name = :name;");
321        
322        // For each setting in this object, check if it exists in DB.  If it does not exist, add.  If it exists and is different from the current value, update.
323        foreach ($this->_settings as $plugin => $setting){
324            foreach ($setting as $name => $value){
325                $sqlVars = [
326                    ":plugin" => $plugin,
327                    ":name" => $name,
328                    ":value" => $value,
329                    ":description" => $this->_descriptions[$plugin][$name]
330                ];
331                if (!isset($db_settings['settings'][$plugin]) || !isset($db_settings['settings'][$plugin][$name])){
332                    $stmt_insert->execute($sqlVars);
333                } else if (($db_settings['settings'][$plugin][$name] !== $this->_settings[$plugin][$name]) || ($db_settings['descriptions'][$plugin][$name] !== $this->_descriptions[$plugin][$name])){
334                    $stmt_update->execute($sqlVars);
335                }
336            }
337        }
338        
339        return true;   
340    }
341}