存储全局站点偏好设置 [PHP/MySQL]

4
有人能推荐一下存储网站通用偏好设置的最佳实践吗?例如,如果脚本没有设置默认页面标题、在内容框中显示的特色项目数量或系统上传图片时应生成的缩略图大小列表。将这些值集中管理可以方便地更改可能在多个页面上使用的偏好设置。
我的默认方法是将这些偏好设置作为属性/值对存储在一个 *gulp* EAV 表中。
这个表不太可能变得非常庞大,所以我不太担心性能问题。我的其余模式是关系型的。但这确实会导致一些非常难看的查询:
$sql = "SELECT name, value FROM preferences"
.    " WHERE name = 'picture_sizes'"
.    " OR name = 'num_picture_fields'"
.    " OR name = 'server_path_to_http'"
.    " OR name = 'picture_directory'";
$query = mysql_query($sql);
if(!$query) {
    echo "Oops! ".mysql_error();
}
while($results = mysql_fetch_assoc($query)) {
    $pref[$results['name']] = $results['value'];
}

有没有人能提出更好的方法?

7个回答

8
在我的应用程序中,我使用了这种结构:
CREATE TABLE `general_settings` (
  `setting_key` varchar(255) NOT NULL,
  `setting_group` varchar(255) NOT NULL DEFAULT 'general',
  `setting_label` varchar(255) DEFAULT NULL,
  `setting_type` enum('text','integer','float','textarea','select','radio','checkbox') NOT NULL DEFAULT 'text',
  `setting_value` text NOT NULL,
  `setting_options` varchar(255) DEFAULT NULL,
  `setting_weight` int(11) DEFAULT '0',
  PRIMARY KEY (`setting_key`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;

示例数据:

mysql> select * from general_settings;
+-----------------------------+---------------+------------------------------+--------------+-------------------------------+---------------------------------------+----------------+
| setting_key                 | setting_group | setting_label                | setting_type | setting_value                 | setting_options                       | setting_weight |
+-----------------------------+---------------+------------------------------+--------------+-------------------------------+---------------------------------------+----------------+
| website_name                | website       | Website Name                 | text         | s:6:"DeenTV";                 | NULL                                  |              1 | 

我在setting_value列中存储序列化的值。我从 WordPress 保存设置的方法中学到了这个技巧。

setting_options 列用于 selectradiocheckboxsetting_type。它将包含一个序列化的数组值。在管理员界面中,此值将显示为选项,因此管理员可以选择其中之一。

由于我使用 CodeIgniter,所以有一个模型可获取特定setting_key的单个值,因此很容易使用。


看起来是一个强大的解决方案。对于我的目的来说可能有点过于强大,但如果我想要扩展我的网站的可配置性,我一定会记住它的。谢谢! - cantlin
嗯,这是一条漫长的路。我从像你这样简单的开始,逐渐根据需要添加更多的列,完善改变值和获取当前值的方式。我建议你找到自己的方法,并尽可能使用它,这样你就知道它的弱点并使其更好。 - Donny Kurnia
setting_weight 只是用于在管理页面中显示设置的指南。我可以获取数据并使用 ORDER BY setting_weight,管理员可以按照所需顺序查看设置。 - Donny Kurnia
@DonnyKurnia,你能告诉我如何更新设置吗?你如何检查设置是否已经插入?我也使用Codeigniter。 - Spoody
@MehdiBounya,setting_key 是主键,因此您可以使用此键作为条件执行 UPDATE 查询。在表单中,您可以将此列值用作字段名称。 因此,如果表单发送了 $_POST['website_name'] = 'My new website',那么我可以使用它来更新数据库中的设置。 - Donny Kurnia

2
我认为这是一种完全可接受的结构,特别是对于像你这样的少量配置。您还可以将这些设置存储在.ini文件中,并调用parse_ini_file。如果INI不允许更多的灵活性(例如:嵌套数组等),那么您可以将它们全部放入.php文件中并包含该文件。如果您仍然想使用数据库中的配置,则(假设只有少数行)可能只需一次读取所有记录并缓存即可。
$config = array();
$result = mysql_query("SELECT * FROM config");
while ($row = mysql_fetch_assoc($result)) {
    $config[$row['name']] = $row['value'];
}

谢谢,Nick。我的唯一担忧是将值存储在文件中会使它们在通过某些未来的管理员界面进行更改时变得有点困难。 - cantlin
我还建议使用PHP会话,并将这些配置值存储在用户会话中的数组中。然后在此代码上方检查数组是否存在,如果存在,则使用它,如果不存在,则查询。这样,您就不需要每次用户查看页面时都查询数据库。唯一的缺点是更改的配置值直到登录用户的会话过期才会生效。 - TravisO

2

你目前的方法看起来很好。

如果你担心查询语句看起来不够优美,可以尝试稍微整理一下你的SQL。

以下是一个更加简洁的版本,基于你在问题中提供的查询语句:

SELECT name, value FROM preferences
WHERE name IN ('picture_sizes','num_picture_fields','server_path_to_http','picture_directory')";

或者创建一个存储函数来返回偏好值;例如,使用这样的存储函数:

DELIMITER $$

CREATE FUNCTION `getPreference` (p_name VARCHAR(50)) RETURNS VARCHAR(200)
BEGIN
  RETURN (SELECT `value` FROM preferences WHERE `name` = p_name);
END $$

DELIMITER ;

您可以使用以下查询获取您的首选项:
SELECT getPreference('server_path_to_http')

如果您不将偏好设置硬编码,那么速度会稍有降低(显然)。但是,如果您计划启用“站点管理员”更改默认偏好设置,则应将它们保存在数据库中。


1
许多应用程序,包括WordPress等,都使用序列化和反序列化。它允许您创建一个非常简单的表结构,甚至只有一个记录(例如,为您的项目(S)提供site_id)。
将数组中的所有变量序列化为字符串并存储。然后获取并反序列化回您的数组结构。
优点: 您不必事先计划完美的配置结构,做很多ALTER TABLE的工作。
缺点: 您无法通过SQL搜索序列化的数组结构。
命令:
string serialize  ( mixed $value  )
mixed unserialize  ( string $str  )

它也可以与您的对象一起使用。反序列化对象可以利用__wakeup()方法。


1

我认为使用包含文件会在以后节省一些麻烦 - 特别是如果您想将数组作为变量之一包含在内。如果您计划随时更改配置变量,则最好将其存储在数据库中,但如果它将保持相对静态,则建议使用“config.php”文件。


0
我的解决问题的方法是创建一个表格,其中每个配置变量都有一个单独的列,就像处理其他数据集一样,并设置主键,使得该表格无法包含多个条目。我通过将主键设置为只允许一个值的枚举来实现这一点,如下所示:
CREATE TABLE IF NOT EXISTS `global_config` (
  `row_limiter` enum('onlyOneRowAllowed') NOT NULL DEFAULT 'onlyOneRowAllowed',#only one possible value
  `someconfigvar` int(10) UNSIGNED NOT NULL DEFAULT 0,
  `someotherconfigvar` varchar(32) DEFAULT 'whatever',
  PRIMARY KEY(`row_limiter`)#primary key on a field which only allows one possible value
) ENGINE = InnoDB;

INSERT IGNORE INTO `global_config` () VALUES ();#to ensure our one row exists

完成此设置后,任何值都可以通过简单的UPDATE语句进行修改,通过简单的SELECT语句进行查找,连接到其他表中以在更复杂的查询中使用等。

这种方法的另一个好处是它允许使用正确的数据类型、外键和所有其他与正确数据库设计相关的内容来确保数据库完整性。(只需确保将您的外键设置为ON DELETE SET NULL或ON DELETE RESTRICT而不是ON DELETE CASCADE)。例如,假设您的配置变量之一是站点主要管理员的用户ID,则可以使用以下示例扩展:

CREATE TABLE IF NOT EXISTS `global_config` (
  `row_limiter` enum('onlyOneRowAllowed') NOT NULL DEFAULT 'onlyOneRowAllowed',
  `someconfigvar` int(10) UNSIGNED NOT NULL DEFAULT 0,
  `someotherconfigvar` varchar(32) DEFAULT 'whatever',
  `primary_admin_id` bigint(20) UNSIGNED NOT NULL,
  PRIMARY KEY(`row_limiter`),
  FOREIGN KEY(`primary_admin_id`) REFERENCES `users`(`user_id`) ON DELETE RESTRICT ON UPDATE CASCADE
) ENGINE = InnoDB;

INSERT IGNORE INTO `global_config` (`primary_admin_id`) VALUES (1);#assuming your DB is set up that the initial user created is also the admin

这可以确保您始终拥有有效的配置,即使配置变量需要引用数据库中的其他实体。


0
只需创建一个配置类并将您想要的每个值存储在该类的变量中。
在调用的所有文件中包含此类。
现在您可以在所有文件中访问此类,并通过在所有函数中声明全局来访问配置类。
希望这有所帮助。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接