Создание админки. ч1. Создание модуля для работы с настройками(данными) из БД.

Вступление


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

Хранилище данных настроек


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


CREATE TABLE `prefix_core` (
  `pref_name` varchar(100) NOT NULL,
  `pref_value` text NOT NULL,
  UNIQUE KEY `pref_name` (`pref_name`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_bin;


Т.е. хранимое значение будет, например

pref_name = 'site', pref_value ='array (
  'SITE_NAME' => 'livestreet',
  'SITE_KEYWORDS' => 'livestreet, cms, open source',
  'SITE_DESCRIPTION' => 'livestreet - open source cms',
)'


Модуль работы с настройками


Далее создаем модуль работы с настройками сайта.
По пути «classes\modules\» название «prefs», в каталоге создаем 3 файла.
Prefs.class.php — класс для работы с настройками (функции модуля)
mapper\Prefs.mapper.class.php — класс доступа к данным (запись/чтение данных из базы данных)
entity\Site.entity.class.php — сущность данных (описание полей к которым сможем обращаться)

Описание сущности. \entity\Site.entity.class.php

Как ни странно, начну с описания сущности, в ней представлены 3 поля (настройки) Имя сайта, Ключевые слова и Описание сайта и соответственно методы работы с данными: get получают значение, а set записывают данные в сущность.
Причем, в реализации данного модуля сделано так, что если не установлены настройки через админку, то они будут возвращаться как были описаны файле настроек.


class PrefsEntity_Site extends Entity {
	
    public function getSiteName() {
		if (isset($this->_aData['SITE_NAME'])){
			return $this->_aData['SITE_NAME'];
		}
		return SITE_NAME;
    }
    public function getSiteKeyWords() {
    	if (isset($this->_aData['SITE_KEYWORDS'])){
			return $this->_aData['SITE_KEYWORDS'];
    	}
    	return SITE_KEYWORDS;
    }    
    
    public function getSiteDescription() {
    	if (isset($this->_aData['SITE_DESCRIPTION'])){
        	return $this->_aData['SITE_DESCRIPTION'];
    	}
    	return SITE_DESCRIPTION;
    } 
    
    public function getArray(){
    	return $this->_aData;
    }
    
    
    public function setSiteName($data) {
    	$this->_aData['SITE_NAME']=$data;
    }
    
    public function setSiteKeyWords($data) {
    	$this->_aData['SITE_KEYWORDS']=$data;
    }
   
    public function setSiteDescription($data) {
    	$this->_aData['SITE_DESCRIPTION']=$data;
    }
}


Соответственно если будите создать свой модуль достаточно будет написать так:

class <ИмяКлассаМодуля>Entity_<ИмяСущности> extends Entity {
public function getЛогичноеИмя() {
    return $this->_aData['Имя_поля_в_базе'];
}
public function setЛогичноеИмя($data) {
    	$this->_aData['Имя_поля_в_базе']=$data;
    }
}


Описание доступа к данным \mapper\Prefs.mapper.class.php

Тут все просто, данные настроек получаются из базы, причем по умолчанию всех групп, а далее методом get получаются настройки конкретной группы настроек, за сохранение настроек отвечает метод set.


class Mapper_Prefs extends Mapper {	
	private $prefVals;
	private $prefArrays;

	/**
	 * Проверяем есть ли уже такой раздел с настройками
	 * @param name - имя настройки
	 */
	public function сheckPrefs($name = "")
	{
		$sql = "SELECT pref_name, pref_value from ".DB_TABLE_CORE." where pref_name = '$name'";
		if (!$aRow=$this->oDb->selectRow($sql)) {
			return false;
		}
		return true;
	}
	
	/**
	 * Устанавливаем настройки
	 * @param name - имя настройки
	 * @param val - значение настройки
	 */
	public function set($name = "", $val) {
		
		$val = addslashes($val);
		// Скрипт обновления
		$sql = "UPDATE ".DB_TABLE_CORE." 
			SET 
				pref_value='$val'
			WHERE
				pref_name = '$name'
			";
		// Скрипт вставки		
		$sql_ins = "INSERT INTO ".DB_TABLE_CORE." (pref_name,pref_value) VALUES('$name','$val')";	
		
		if($this->сheckPrefs($name))
			{
				$this->oDb->query($sql);
			} else{
				$this->oDb->query($sql_ins);
			}	
	}
	
	/**
	 * Получение настроек по имени
	 * @param name - имя настройки
	 */
	public function get($Name) {
		if(isset($this->prefVals[$Name])){
			return $this->prefVals[$Name];
		} else {
			return false;
		}
	}
	
	/**
	 * Получаем данные настроек, по умолчанию выбираются данные всех настроек
	 * @param Preflist - массив с перечислением нужных настроек
	 */
	public function ExtractPrefs($Preflist = "") {
		$lim = "";
		if(is_array($Preflist))
		{
			foreach($Preflist as $v)
			{
				$lim .= ($lim ? " OR pref_name='{$v}'" : "pref_name='{$v}'");
			}
		}
		if (strlen($lim)){
			$lim = "where $lim";
		}
		$sql = "SELECT pref_name, pref_value from ".DB_TABLE_CORE." $lim";
		
		if ($row =$this->oDb->select($sql)){	
			foreach($row as $key => $value){
				$this->prefVals[$value['pref_name']] = $value['pref_value'];
			}
		}
		return $this->prefVals;
	}
}


Для создания собстевенного модуля для работы с данным достаточно будет написать 3 функции

class Mapper_<ИмяКлассаМодуля> extends Mapper {
   public function ФункцияВыборкиДанных() {
	}	
   public function ФункцияВставкиДанных() {
	}
   public function ФункцияОбновленияДанных() {
	}
}

Кто хочет узнать синтаксис и возможности работы с данными, то вам сюда

Описание основного модуля Prefs.class.php

Функции модуля позволяют «на высоком уровне» работать с данными. Например, getPrefs возвращает уже наполненную сущность данными, setPrefs сохраняет данные, readArray преобразует данные из строки-массива в «нормальный» ассоциативный массив, writeArray делает обратную операцию.

set_include_path(get_include_path().PATH_SEPARATOR.dirname(__FILE__));
require_once('mapper/Prefs.mapper.class.php');

class Prefs extends Module{
	protected $oMapperPrefs;
		
	/**
	 * Инициализация
	 */
	public function Init() {		
		$this->oMapperPrefs=new Mapper_Prefs($this->Database_GetConnect());
	}
	
	/**
	 * Функция которая возвращает сущность со значениями
	 * @param $name - имя настройки
	 */
	public function getPrefs($name = '') {		
		$this->oMapperPrefs->ExtractPrefs(); //array('site','plugins')
		$PrefData = $this->oMapperPrefs->get($name);
		return new PrefsEntity_Site($this->readArray($PrefData));
	}
	
	/**
	 * Сохранение значений
	 * @param name - имя настройки
	 * @param oPrefs - объект настроек 
 	 */
	public function setPrefs($name, PrefsEntity_Site $oPrefs) {	
		$PrefData = $oPrefs->getArray($oPrefs);	
		$this->oMapperPrefs->set($name,$this->writeArray($PrefData, false));
	}
	
	/**
	 * Записываем строку-массив
	 * @param ArrayData - массив 
	 * @param AddSlashes - экранировать слешем кавычки? 
	 */
	private function writeArray($ArrayData, $AddSlashes = true) {
		if (!is_array($ArrayData)) {
			return false;
		}
		$Array = var_export($ArrayData, true);
		if ($AddSlashes == true) {
			$Array = addslashes($Array);
		}
		return $Array;
	}
	
	/**
	 * Читаем массив из строки-массива
	 * @param ArrayData - строка-массив
	 */
	private function readArray($ArrayData) {
		if ($ArrayData == ""){
			return false;
		}
		$data = "";
		$ArrayData = '$data = '.trim($ArrayData).';';
		@eval($ArrayData);
		if (!isset($data) || !is_array($data)) {
			trigger_error("Кривые данные на входе - <br />".htmlentities($ArrayData), E_USER_ERROR);
			return false;
		}
		return $data;
	}	
}


Для создании собственного класса модуля прочитайте ранее приведенную статью. Некоторые добавления которые потребуются для создания модуля работающего с БД: в Init() нужно добавить создание объекта доступа к данным и добавить поле класса, как в приведенном ниже коде.


protected $oMapper<ИмяКлассаМодуля>;
public function Init() {
   $this->oMapper<ИмяКлассаМодуля>=new Mapper_<ИмяКлассаМодуля>($this->Database_GetConnect());
}

далее функции доступа к данным можно вызывать, например так: $this->oMapper<ИмяКлассаМодуля>->ФункцияВыборкиДанных();

P.S> Наверняка многое можно оптимизировать.
P.S.S> постарался по компактнее описать и информативнее комментировать код, надеюсь все понятно, если нет, пишите, отвечу на вопросы.

В следующей статье будет описано как создаются меню и будут использованы функции ранее описанного модуля.

5 комментариев

avatar
кстати, забыл написать, надо в файл config.table.php,
добавить строчку еще define('DB_TABLE_CORE',DB_PREFIX_TABLE.'core');
  • gran
  • 0
avatar

Всем привет, пишу свой первый комментарий.

Преодолел установку LS на денвер ) было не совсем уж сложно, но проблемно.

Я только начинаю изучать все эти при мудрости, но скажите куда писать вот это

CREATE TABLE `prefix_core` (
  `pref_name` varchar(100) NOT NULL,
  `pref_value` text NOT NULL,
  UNIQUE KEY `pref_name` (`pref_name`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
 
avatar
Сам спросил, сам нашел :)
avatar
А можно поподробнее про использование базы на примере
livestreet.ru/blog/dev_documentation/254.html?

в файл modules/Mytest.class.php надо добавить

protected $oMapper summ;
public function Init() {
   $this->oMapper summ=new Mapper_summ($this->Database_GetConnect());
}


И тогда я смогу делать запросы к базе как из файла модуля так и из экшна?
avatar
У меня вопрос, откуда берется (в каком классе Module? Object )
функция:

$this -> Database_GetConnect()?..
Только зарегистрированные и авторизованные пользователи могут оставлять комментарии.