2009-05-10 10:50:39 +03:00
|
|
|
|
<?php
|
2008-09-21 09:36:57 +03:00
|
|
|
|
/*-------------------------------------------------------
|
|
|
|
|
*
|
|
|
|
|
* LiveStreet Engine Social Networking
|
|
|
|
|
* Copyright © 2008 Mzhelskiy Maxim
|
|
|
|
|
*
|
|
|
|
|
*--------------------------------------------------------
|
|
|
|
|
*
|
|
|
|
|
* Official site: www.livestreet.ru
|
|
|
|
|
* Contact e-mail: rus.engine@gmail.com
|
|
|
|
|
*
|
|
|
|
|
* GNU General Public License, version 2:
|
|
|
|
|
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
|
|
|
|
*
|
|
|
|
|
---------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
/**
|
2012-04-17 20:58:32 +03:00
|
|
|
|
* Абстрактный класс сущности.
|
|
|
|
|
* При запросе к базе данных удобно возвращать не просто массив данных, а данные в виде специального объекта - Entity.
|
|
|
|
|
* Основные методы такого объекта делятся на два вида: get-методы и set-методы.
|
|
|
|
|
* Первые получают свойство объекта по его имени, а вторые устанавливают.
|
|
|
|
|
* Сущности поддерживает "магические" методы set* и get* , например
|
|
|
|
|
* <pre>
|
|
|
|
|
* $oEntity->getMyProperty()
|
|
|
|
|
* </pre> вернет данные по ключу/полю my_property
|
2008-09-21 09:36:57 +03:00
|
|
|
|
*
|
2012-04-17 20:58:32 +03:00
|
|
|
|
* @package engine
|
|
|
|
|
* @since 1.0
|
2008-09-21 09:36:57 +03:00
|
|
|
|
*/
|
2012-04-07 09:41:52 +03:00
|
|
|
|
abstract class Entity extends LsObject {
|
2012-04-17 20:58:32 +03:00
|
|
|
|
/**
|
|
|
|
|
* Данные сущности, на этот массив мапятся методы set* и get*
|
|
|
|
|
*
|
|
|
|
|
* @var array
|
|
|
|
|
*/
|
2008-09-21 09:36:57 +03:00
|
|
|
|
protected $_aData=array();
|
2012-04-17 20:58:32 +03:00
|
|
|
|
/**
|
|
|
|
|
* Имя поля с первичным ключом в БД
|
|
|
|
|
*
|
|
|
|
|
* @var null|string
|
|
|
|
|
*/
|
2012-03-02 19:27:16 +02:00
|
|
|
|
protected $sPrimaryKey = null;
|
2012-04-17 20:58:32 +03:00
|
|
|
|
/**
|
|
|
|
|
* Список правил валидации полей
|
|
|
|
|
* @see ModuleValidate
|
|
|
|
|
*
|
|
|
|
|
* @var array
|
|
|
|
|
*/
|
2012-03-02 19:27:16 +02:00
|
|
|
|
protected $aValidateRules=array();
|
2012-04-17 20:58:32 +03:00
|
|
|
|
/**
|
|
|
|
|
* Список ошибок валидации в разрезе полей, например
|
|
|
|
|
* <pre>
|
|
|
|
|
* array(
|
|
|
|
|
* 'title' => array('error one','error two'),
|
|
|
|
|
* 'name' => array('error one','error two'),
|
|
|
|
|
* )
|
|
|
|
|
* </pre>
|
|
|
|
|
*
|
|
|
|
|
* @var array
|
|
|
|
|
*/
|
2012-03-02 19:27:16 +02:00
|
|
|
|
protected $aValidateErrors=array();
|
2012-04-17 20:58:32 +03:00
|
|
|
|
/**
|
|
|
|
|
* Сценарий валиадции полей
|
|
|
|
|
* @see _setValidateScenario
|
|
|
|
|
*
|
|
|
|
|
* @var string
|
|
|
|
|
*/
|
2012-03-02 19:27:16 +02:00
|
|
|
|
protected $sValidateScenario='';
|
|
|
|
|
|
2008-09-21 09:36:57 +03:00
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Если передать в конструктор ассоциативный массив свойств и их значений, то они автоматом загрузятся в сущность
|
|
|
|
|
*
|
2012-04-17 20:58:32 +03:00
|
|
|
|
* @param array|false $aParam Ассоциативный массив данных сущности
|
2008-09-21 09:36:57 +03:00
|
|
|
|
*/
|
2010-02-07 20:50:45 +02:00
|
|
|
|
public function __construct($aParam = false) {
|
|
|
|
|
$this->_setData($aParam);
|
2012-03-12 13:40:26 +02:00
|
|
|
|
$this->Init();
|
|
|
|
|
}
|
|
|
|
|
/**
|
|
|
|
|
* Метод инициализации сущности, вызывается при её создании
|
|
|
|
|
*/
|
|
|
|
|
public function Init() {
|
|
|
|
|
|
2010-02-07 20:50:45 +02:00
|
|
|
|
}
|
2012-04-17 20:58:32 +03:00
|
|
|
|
/**
|
|
|
|
|
* Устанавливает данные сущности
|
|
|
|
|
*
|
|
|
|
|
* @param array $aData Ассоциативный массив данных сущности
|
|
|
|
|
*/
|
2010-02-07 20:50:45 +02:00
|
|
|
|
public function _setData($aData) {
|
|
|
|
|
if(is_array($aData)) {
|
|
|
|
|
foreach ($aData as $sKey => $val) {
|
2008-09-21 09:36:57 +03:00
|
|
|
|
$this->_aData[$sKey] = $val;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2012-04-17 20:58:32 +03:00
|
|
|
|
/**
|
|
|
|
|
* Получает массив данных сущности
|
|
|
|
|
*
|
|
|
|
|
* @param array|null $aKeys Список полей, данные по которым необходимо вернуть, если не передан, то возвращаются все данные
|
|
|
|
|
* @return array
|
|
|
|
|
*/
|
2010-02-07 20:50:45 +02:00
|
|
|
|
public function _getData($aKeys=array()) {
|
|
|
|
|
if(!is_array($aKeys) or !count($aKeys)) return $this->_aData;
|
2012-03-02 19:27:16 +02:00
|
|
|
|
|
2010-02-07 20:50:45 +02:00
|
|
|
|
$aReturn=array();
|
|
|
|
|
foreach ($aKeys as $key) {
|
2010-08-13 09:12:19 +03:00
|
|
|
|
if(array_key_exists($key,$this->_aData)) {
|
2010-02-07 20:50:45 +02:00
|
|
|
|
$aReturn[$key] = $this->_aData[$key];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return $aReturn;
|
|
|
|
|
}
|
2012-04-17 20:58:32 +03:00
|
|
|
|
/**
|
|
|
|
|
* Возвращает данные по конкретному полю
|
|
|
|
|
*
|
|
|
|
|
* @param string $sKey Название поля, например <pre>'my_property'</pre>
|
|
|
|
|
* @return null|mixed
|
|
|
|
|
*/
|
2010-08-13 09:12:19 +03:00
|
|
|
|
public function _getDataOne($sKey) {
|
|
|
|
|
if(array_key_exists($sKey,$this->_aData)) {
|
|
|
|
|
return $this->_aData[$sKey];
|
|
|
|
|
}
|
|
|
|
|
return null;
|
|
|
|
|
}
|
2011-08-19 11:24:36 +03:00
|
|
|
|
/**
|
|
|
|
|
* Рекурсивное преобразование объекта и вложенных объектов в массив
|
2012-04-17 20:58:32 +03:00
|
|
|
|
*
|
|
|
|
|
* @return array
|
2011-08-19 11:24:36 +03:00
|
|
|
|
*/
|
2012-04-17 20:58:32 +03:00
|
|
|
|
public function _getDataArray() {
|
2011-08-19 11:24:36 +03:00
|
|
|
|
$aResult = array();
|
|
|
|
|
foreach ($this->_aData as $sKey => $sValue) {
|
|
|
|
|
if (is_object($sValue) && $sValue instanceOf Entity) {
|
|
|
|
|
$aResult[$sKey] = $sValue->_getDataArray();
|
|
|
|
|
} else {
|
|
|
|
|
$aResult[$sKey] = $sValue;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return $aResult;
|
|
|
|
|
}
|
2009-04-23 10:40:25 +03:00
|
|
|
|
/**
|
|
|
|
|
* Ставим хук на вызов неизвестного метода и считаем что хотели вызвать метод какого либо модуля
|
2012-04-17 20:58:32 +03:00
|
|
|
|
* Также производит обработку методов set* и get*
|
|
|
|
|
* @see Engine::_CallModule
|
2009-04-23 10:40:25 +03:00
|
|
|
|
*
|
2012-04-17 20:58:32 +03:00
|
|
|
|
* @param string $sName Имя метода
|
|
|
|
|
* @param array $aArgs Аргументы
|
|
|
|
|
* @return mixed
|
2009-04-23 10:40:25 +03:00
|
|
|
|
*/
|
|
|
|
|
public function __call($sName,$aArgs) {
|
2010-02-07 17:01:27 +02:00
|
|
|
|
$sType=strtolower(substr($sName,0,3));
|
2010-08-03 23:13:44 +03:00
|
|
|
|
if (!strpos($sName,'_') and in_array($sType,array('get','set'))) {
|
2010-08-13 18:40:21 +03:00
|
|
|
|
$sKey=func_underscore(substr($sName,3));
|
2010-02-07 17:01:27 +02:00
|
|
|
|
if ($sType=='get') {
|
2010-08-03 23:13:44 +03:00
|
|
|
|
if (isset($this->_aData[$sKey])) {
|
2010-02-07 17:01:27 +02:00
|
|
|
|
return $this->_aData[$sKey];
|
2010-08-03 23:13:44 +03:00
|
|
|
|
} else {
|
|
|
|
|
if (preg_match('/Entity([^_]+)/',get_class($this),$sModulePrefix)) {
|
2010-08-13 18:40:21 +03:00
|
|
|
|
$sModulePrefix=func_underscore($sModulePrefix[1]).'_';
|
2010-08-03 23:13:44 +03:00
|
|
|
|
if (isset($this->_aData[$sModulePrefix.$sKey])) {
|
|
|
|
|
return $this->_aData[$sModulePrefix.$sKey];
|
|
|
|
|
}
|
|
|
|
|
}
|
2010-02-07 17:01:27 +02:00
|
|
|
|
}
|
|
|
|
|
return null;
|
2010-08-13 09:12:19 +03:00
|
|
|
|
} elseif ($sType=='set' and array_key_exists(0,$aArgs)) {
|
2010-02-07 17:01:27 +02:00
|
|
|
|
$this->_aData[$sKey]=$aArgs[0];
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
return Engine::getInstance()->_CallModule($sName,$aArgs);
|
|
|
|
|
}
|
2009-04-23 10:40:25 +03:00
|
|
|
|
}
|
2012-03-02 19:27:16 +02:00
|
|
|
|
/**
|
|
|
|
|
* Получение первичного ключа сущности (ключ, а не значение!)
|
2012-04-17 20:58:32 +03:00
|
|
|
|
* @see _getPrimaryKeyValue
|
|
|
|
|
*
|
|
|
|
|
* @return null|string
|
2012-03-02 19:27:16 +02:00
|
|
|
|
*/
|
2012-04-17 20:58:32 +03:00
|
|
|
|
public function _getPrimaryKey() {
|
2012-03-02 19:27:16 +02:00
|
|
|
|
if (!$this->sPrimaryKey) {
|
|
|
|
|
if (isset($this->_aData['id'])) {
|
|
|
|
|
$this->sPrimaryKey = 'id';
|
|
|
|
|
} else {
|
|
|
|
|
// Получение primary_key из схемы бд (пока отсутствует)
|
|
|
|
|
$this->sPrimaryKey = 'id';
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return $this->sPrimaryKey;
|
|
|
|
|
}
|
2012-04-17 20:58:32 +03:00
|
|
|
|
/**
|
|
|
|
|
* Возвращает значение первичного ключа/поля
|
|
|
|
|
*
|
|
|
|
|
* @return mixed|null
|
|
|
|
|
*/
|
2012-03-02 19:27:16 +02:00
|
|
|
|
public function _getPrimaryKeyValue() {
|
|
|
|
|
return $this->_getDataOne($this->_getPrimaryKey());
|
|
|
|
|
}
|
|
|
|
|
/**
|
|
|
|
|
* Выполняет валидацию данных сущности
|
|
|
|
|
* Если $aFields=null, то выполняется валидация по всем полям из $this->aValidateRules, иначе по пересечению
|
|
|
|
|
*
|
2012-04-17 20:58:32 +03:00
|
|
|
|
* @param null|array $aFields Список полей для валидации, если null то по всем полям
|
|
|
|
|
* @param bool $bClearErrors Очищать или нет стек ошибок перед валидацией
|
2012-03-02 19:27:16 +02:00
|
|
|
|
*
|
|
|
|
|
* @return bool
|
|
|
|
|
*/
|
2012-04-17 20:58:32 +03:00
|
|
|
|
public function _Validate($aFields=null, $bClearErrors=true) {
|
|
|
|
|
if($bClearErrors) {
|
2012-03-02 19:27:16 +02:00
|
|
|
|
$this->_clearValidateErrors();
|
|
|
|
|
}
|
|
|
|
|
foreach($this->_getValidators() as $validator) {
|
|
|
|
|
$validator->validateEntity($this,$aFields);
|
|
|
|
|
}
|
|
|
|
|
return !$this->_hasValidateErrors();
|
|
|
|
|
}
|
|
|
|
|
/**
|
|
|
|
|
* Возвращает список валидаторов с учетом текущего сценария
|
|
|
|
|
*
|
|
|
|
|
* @param null|string $sField Поле сущности для которого необходимо вернуть валидаторы, если нет, то возвращается для всех полей
|
|
|
|
|
*
|
|
|
|
|
* @return array
|
|
|
|
|
*/
|
|
|
|
|
public function _getValidators($sField=null) {
|
2012-03-12 13:40:26 +02:00
|
|
|
|
$aValidators=$this->_createValidators();
|
2012-03-02 19:27:16 +02:00
|
|
|
|
|
|
|
|
|
$aValidatorsReturn=array();
|
|
|
|
|
$sScenario=$this->_getValidateScenario();
|
|
|
|
|
foreach($aValidators as $oValidator) {
|
|
|
|
|
/**
|
|
|
|
|
* Проверка на текущий сценарий
|
|
|
|
|
*/
|
|
|
|
|
if($oValidator->applyTo($sScenario)) {
|
|
|
|
|
if($sField===null || in_array($sField,$oValidator->fields,true)) {
|
|
|
|
|
$aValidatorsReturn[]=$oValidator;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return $aValidatorsReturn;
|
|
|
|
|
}
|
|
|
|
|
/**
|
|
|
|
|
* Создает и возвращает список валидаторов для сущности
|
2012-04-17 20:58:32 +03:00
|
|
|
|
* @see ModuleValidate::CreateValidator
|
2012-03-02 19:27:16 +02:00
|
|
|
|
*
|
|
|
|
|
* @return array
|
|
|
|
|
* @throws Exception
|
|
|
|
|
*/
|
2012-03-12 13:40:26 +02:00
|
|
|
|
public function _createValidators() {
|
2012-03-02 19:27:16 +02:00
|
|
|
|
$aValidators=array();
|
|
|
|
|
foreach($this->aValidateRules as $aRule) {
|
|
|
|
|
if(isset($aRule[0],$aRule[1])) {
|
|
|
|
|
$aValidators[]=$this->Validate_CreateValidator($aRule[1],$this,$aRule[0],array_slice($aRule,2));
|
|
|
|
|
} else {
|
|
|
|
|
throw new Exception(get_class($this).' has an invalid validation rule');
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return $aValidators;
|
|
|
|
|
}
|
|
|
|
|
/**
|
|
|
|
|
* Проверяет есть ли ошибки валидации
|
|
|
|
|
*
|
|
|
|
|
* @param null|string $sField Поле сущности, если нет, то проверяется для всех полей
|
|
|
|
|
*
|
|
|
|
|
* @return bool
|
|
|
|
|
*/
|
|
|
|
|
public function _hasValidateErrors($sField=null) {
|
|
|
|
|
if($sField===null) {
|
|
|
|
|
return $this->aValidateErrors!==array();
|
|
|
|
|
} else {
|
|
|
|
|
return isset($this->aValidateErrors[$sField]);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
/**
|
|
|
|
|
* Возвращает список ошибок для всех полей или одного поля
|
|
|
|
|
*
|
|
|
|
|
* @param null|string $sField Поле сущности, если нет, то возвращается для всех полей
|
|
|
|
|
*
|
|
|
|
|
* @return array
|
|
|
|
|
*/
|
|
|
|
|
public function _getValidateErrors($sField=null) {
|
|
|
|
|
if($sField===null) {
|
|
|
|
|
return $this->aValidateErrors;
|
|
|
|
|
} else {
|
|
|
|
|
return isset($this->aValidateErrors[$sField]) ? $this->aValidateErrors[$sField] : array();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
/**
|
2012-03-24 07:11:48 +02:00
|
|
|
|
* Возвращает первую ошибку для поля или среди всех полей
|
2012-03-02 19:27:16 +02:00
|
|
|
|
*
|
2012-03-24 07:11:48 +02:00
|
|
|
|
* @param null|string $sField Поле сущности
|
2012-03-02 19:27:16 +02:00
|
|
|
|
*
|
|
|
|
|
* @return string|null
|
|
|
|
|
*/
|
2012-03-24 07:11:48 +02:00
|
|
|
|
public function _getValidateError($sField=null) {
|
|
|
|
|
if ($sField===null) {
|
|
|
|
|
foreach($this->_getValidateErrors() as $sFieldKey=>$aErros) {
|
|
|
|
|
return reset($aErros);
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
return isset($this->aValidateErrors[$sField]) ? reset($this->aValidateErrors[$sField]) : null;
|
|
|
|
|
}
|
2012-03-02 19:27:16 +02:00
|
|
|
|
}
|
|
|
|
|
/**
|
|
|
|
|
* Добавляет для поля ошибку в список ошибок
|
|
|
|
|
*
|
|
|
|
|
* @param string $sField Поле сущности
|
2012-04-17 20:58:32 +03:00
|
|
|
|
* @param string $sError Сообщение об ошибке
|
2012-03-02 19:27:16 +02:00
|
|
|
|
*/
|
2012-04-17 20:58:32 +03:00
|
|
|
|
public function _addValidateError($sField,$sError) {
|
|
|
|
|
$this->aValidateErrors[$sField][]=$sError;
|
2012-03-02 19:27:16 +02:00
|
|
|
|
}
|
|
|
|
|
/**
|
|
|
|
|
* Очищает список всех ошибок или для конкретного поля
|
|
|
|
|
*
|
|
|
|
|
* @param null|string $sField Поле сущности
|
|
|
|
|
*/
|
|
|
|
|
public function _clearValidateErrors($sField=null) {
|
|
|
|
|
if($sField===null) {
|
|
|
|
|
$this->aValidateErrors=array();
|
|
|
|
|
} else {
|
|
|
|
|
unset($this->aValidateErrors[$sField]);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
/**
|
|
|
|
|
* Возвращает текущий сценарий валидации
|
|
|
|
|
*
|
|
|
|
|
* @return string
|
|
|
|
|
*/
|
|
|
|
|
public function _getValidateScenario() {
|
|
|
|
|
return $this->sValidateScenario;
|
|
|
|
|
}
|
|
|
|
|
/**
|
|
|
|
|
* Устанавливает сценарий валидации
|
2012-04-17 20:58:32 +03:00
|
|
|
|
* Если использовать валидацию без сценария, то будут использоваться только те правила, где нет никаких сценариев, либо указан пустой сценарий ''
|
|
|
|
|
* Если указать сценарий, то проверка будет только по правилом, где в списке сценарией есть указанный
|
2012-03-02 19:27:16 +02:00
|
|
|
|
*
|
|
|
|
|
* @param string $sValue
|
|
|
|
|
*/
|
|
|
|
|
public function _setValidateScenario($sValue) {
|
|
|
|
|
$this->sValidateScenario=$sValue;
|
|
|
|
|
}
|
2008-09-21 09:36:57 +03:00
|
|
|
|
}
|
|
|
|
|
?>
|