Сохранение глобальных настроек сайта [PHP/MySQL]

Может ли кто-нибудь порекомендовать наилучшую практику для хранения общих настроек сайта? Например, заголовок страницы по умолчанию, если сценарий его не задает, или количество избранных элементов, отображаемых в поле содержимого, или список размеров эскизов, которые система должна создавать при загрузке изображения. Централизация этих значений имеет очевидное преимущество, поскольку позволяет легко изменять настройки, которые могут использоваться на многих страницах.

Мой подход по умолчанию заключался в том, чтобы поместить эти настройки в виде пар атрибут/значение в таблицу *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'];
}

Может ли кто-нибудь предложить лучший подход?


person cantlin    schedule 11.02.2010    source источник


Ответы (7)


Это выглядит прекрасно, как вы это делаете.

Если вы беспокоитесь, что ваши запросы выглядят уродливо, вы можете попробовать немного почистить свой 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')

Вы немного жертвуете скоростью, не запрограммировав свои предпочтения (очевидно). Но если вы планируете разрешить «администратору сайта» изменять настройки по умолчанию, вам следует сохранить их в базе данных.

person Mikuso    schedule 11.02.2010

В моем приложении я использую эту структуру:

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 используется для select, radio или checkbox setting_type. Он будет содержать сериализованное значение массива. В админке это значение будет отображаться как опция, так что админ может выбрать одну из них.

Поскольку я использую CodeIgniter, у меня есть модель для получения одного значения из конкретного setting_key, поэтому ее довольно легко использовать.

person Donny Kurnia    schedule 11.02.2010
comment
Выглядит как мощное решение. Вероятно, это слишком мощно для моих целей, но я обязательно буду иметь это в виду, если захочу расширить возможности настройки своего сайта. Спасибо! - person cantlin; 11.02.2010
comment
Что ж, это долгий путь. Я начинаю с простого, как у вас, и постепенно добавляю столбцы по мере необходимости, уточняю способ изменения значения и получаю текущее значение. Я предлагаю вам найти свой собственный и использовать его всякий раз, когда вы можете, чтобы вы знали его слабость и сделали его лучше. - person Donny Kurnia; 11.02.2010
comment
setting_weight просто как руководство по отображению настроек на странице администратора. Я могу получить данные, и ORDER BY setting_weight, и администратор могут видеть настройки в желаемом порядке. - person Donny Kurnia; 12.02.2010
comment
@DonnyKurnia, не могли бы вы рассказать, как вы обновляете настройки? Как проверить, что настройка уже вставлена? Я также использую Codeigniter - person Spoody; 25.02.2016
comment
@MehdiBounya setting_key является первичным ключом, поэтому вы можете выполнить запрос UPDATE, используя этот ключ в качестве условия. В форме вы можете использовать это значение столбца в качестве имени поля. Итак, если форма отправила $_POST['website_name'] = 'My new website', то я могу использовать это для обновления настроек в базе данных. - person Donny Kurnia; 26.02.2016

Я думаю, что это вполне приемлемая структура, особенно для небольшого количества конфигураций, как у вас.

Вы также можете сохранить эти настройки в файле .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'];
}
person nickf    schedule 11.02.2010
comment
Спасибо, Ник. Единственное, что меня беспокоило при хранении значений в файле, заключалось в том, что их было бы немного сложнее изменить через какой-то будущий интерфейс администратора. - person cantlin; 11.02.2010
comment
Я бы также рекомендовал использовать сеансы PHP и хранить эти значения конфигурации в массиве в сеансе пользователя. Затем над этим кодом проверьте, существует ли массив, если да, используйте его, если нет, то запросите. Таким образом, вам не нужно будет запрашивать базу данных для этого КАЖДЫЙ РАЗ, когда пользователь просматривает страницу. Единственный недостаток заключается в том, что измененное значение конфигурации не повлияет на вошедших в систему пользователей до истечения срока их сеанса. - person TravisO; 11.02.2010

Я думаю, что работа с включенным файлом избавит вас от некоторых хлопот в дальнейшем, особенно если вы когда-нибудь захотите включить массив в качестве одной из ваших переменных. Если вы планируете изменять переменные конфигурации на лету, то, возможно, лучше создать базу данных, но если она останется относительно статической, я бы порекомендовал файл «config.php».

person thetaiko    schedule 11.02.2010

Множество приложений, в т.ч. Wordpress, используйте сериализацию и десериализацию. Это позволяет вам создать очень простую структуру таблицы, возможно, даже с одной записью (например, с site_id для вашего проекта (ов)).

Все ваши (многие, многие) переменные в массиве сериализуются в строку и сохраняются. Затем извлекается и несериализуется обратно в структуру вашего массива.

Pro: вам не нужно заранее планировать идеальные структуры конфигурации, выполняя множество операций ALTER TABLE.

Минусы: вы не можете выполнять поиск в сериализованной структуре массива с помощью SQL.

Команды:

string serialize  ( mixed $value  )
mixed unserialize  ( string $str  )

Работает также с вашими объектами. Для десериализации объекта можно использовать метод __wakeup().

person initall    schedule 11.02.2010

Просто создайте класс configure и сохраните каждое значение, которое вы хотите, в переменной класса.

включить этот класс во все файлы, которые вызывает.

Теперь вы можете получить доступ к этому классу во всех файлах, и, объявив глобальную функцию во всех, вы можете получить доступ к классу конфигурации.

Надеюсь, это поможет.

person Avinash    schedule 11.02.2010

Мой подход к этой проблеме состоит в том, чтобы создать таблицу с отдельным столбцом для каждой переменной конфигурации, как и в случае с любым другим набором данных, и установить первичный ключ таким образом, чтобы таблица не могла содержать более одной записи. . Я делаю это, устанавливая первичный ключ как перечисление только с одним допустимым значением, например так:

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). Например, предположим, что одна из ваших переменных конфигурации является идентификатором пользователя основного администратора сайта, вы можете расширить пример следующим образом:

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

Это гарантирует, что у вас всегда будет действительная конфигурация, даже если переменная конфигурации должна ссылаться на какой-либо другой объект в базе данных.

person Dan    schedule 07.10.2015