Last active
August 29, 2015 14:02
-
-
Save zhouyl/ae0e9ceccd135f3c72b6 to your computer and use it in GitHub Desktop.
Fixed Phalcon\Mvc\Model empty string
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
use | |
Phalcon\Mvc\Model, | |
Phalcon\Mvc\Model\Message, | |
Phalcon\Db\RawValue; | |
/** | |
* 基础 Model 实现 | |
* | |
* @link http://docs.phalconphp.com/zh/latest/reference/models.html | |
* @link http://docs.phalconphp.com/zh/latest/api/Phalcon_Mvc_Model.html | |
*/ | |
class ModelBase extends Model | |
{ | |
/** | |
* 被禁用的事件 | |
* | |
* @var array | |
*/ | |
public $_disableEvents = array(); | |
/** | |
* 初始化方法 | |
*/ | |
public function initialize() | |
{ | |
Model::setup(array( | |
'notNullValidations' => false, // 禁止非空验证 | |
)); | |
$defineDatabase = get_called_class() . '::DATABASE'; | |
$defineTable = get_called_class() . '::TABLE'; | |
$definePrefix = get_called_class() . '::PREFIX'; | |
// 设置数据库名 | |
if (defined($defineDatabase)) { | |
$this->setSchema(constant($defineDatabase)); | |
} | |
// 设置表名 | |
if (defined($defineTable)) { | |
$this->setSource(constant($defineTable)); | |
} | |
// 设置表名前缀 | |
if ($prefix = defined($definePrefix) ? constant($definePrefix) : config('database.prefix')) { | |
$this->setSource($prefix . (defined($defineTable) ? constant($defineTable) : $this->getSource())); | |
} | |
/** | |
* 动态更新 | |
* | |
* 此功能允许ORM在创建SQL UPDATE语句时,只改变有改变的字段,而不是整个表的所有字段。 | |
* 在某些情况下,这可以提高性能,减少应用程序与数据库服务器之间的传输数据量 | |
*/ | |
$this->useDynamicUpdate(true); | |
/** | |
* 记录快照 | |
* | |
* 这项新功能,指定的Models可以设定为查询时保持记录的快照。 | |
* 你可以使用此功能来实现审计或只是为了知道哪些字段被更改过: | |
* | |
* $robot = new Robots(); | |
* $robot->name = 'Other name'; | |
* var_dump($robot->getChangedFields()); // ['name'] | |
* var_dump($robot->hasChanged('name')); // true | |
*/ | |
$this->keepSnapshots(true); | |
} | |
/** | |
* 在执行 create 方法前触发该事件 | |
* 返回 false 时停止执行 create | |
* | |
* @return boolean | |
*/ | |
public function beforeSave() | |
{ | |
if (isset($this->ctime) && ! $this->ctime) { | |
$this->ctime = time(); | |
} | |
if (isset($this->mtime) && ! $this->mtime) { | |
$this->mtime = time(); | |
} | |
return true; | |
} | |
/** | |
* 获得第一条错误消息 | |
* | |
* @return string | |
*/ | |
public function getMessage() | |
{ | |
return $this->getFirstMessage(); | |
} | |
/** | |
* 获得第一条错误消息 | |
* | |
* @return string | |
*/ | |
public function getFirstMessage() | |
{ | |
if (count($this->getMessages())) { | |
return (string) current($this->getMessages()); | |
} | |
return false; | |
} | |
/** | |
* 获取最后一条错误消息 | |
* | |
* @return string | |
*/ | |
public function getLastMessage() | |
{ | |
if (count($this->getMessages())) { | |
return (string) end($this->getMessages()); | |
} | |
return false; | |
} | |
/** | |
* 创建一个查询 builder | |
* | |
* @link http://docs.phalconphp.com/zh/latest/api/Phalcon_Mvc_Model_Query_Builder.html | |
* @return \Phalcon\Mvc\Model\Query\Builder | |
*/ | |
public function createBuilder() | |
{ | |
return $this->getModelsManager()->createBuilder()->from(get_called_class()); | |
} | |
/** | |
* 获取单例实例 | |
* | |
* @return \Formax\Model | |
*/ | |
public static function getInstance() | |
{ | |
static $instance = null; | |
if ($instance === null) { | |
$class = get_called_class(); | |
$instance = new $class; | |
} | |
return $instance; | |
} | |
/** | |
* 是否启用 validation 方法 | |
* | |
* @param boolean useValidation | |
* @return \Formax\Model | |
*/ | |
public function useValidation($useValidation = true) | |
{ | |
$events = array( | |
'beforeValidation', | |
'beforeValidationOnCreate', | |
'beforeValidationOnUpdate', | |
'validation', | |
'afterValidationOnCreate', | |
'afterValidationOnUpdate', | |
'afterValidation', | |
); | |
$useValidation ? $this->enableEvents($events) : $this->disableEvents($events); | |
return $this; | |
} | |
/** | |
* 禁用事件 | |
* | |
* @param array|string $events | |
* @return \Formax\Model | |
*/ | |
public function disableEvents($events) | |
{ | |
is_array($events) or $events = array($events); | |
$this->_disableEvents += array_map('strtolower', $events); | |
return $this; | |
} | |
/** | |
* 启用事件 | |
* | |
* @param array|string $events | |
* @return \Formax\Model | |
*/ | |
public function enableEvents($events) | |
{ | |
is_array($events) or $events = array($events); | |
$events = array_map('strtolower', $events);; | |
foreach ($this->_disableEvents as $index => $eventName) { | |
if (in_array($eventName, $events)) { | |
unset($this->_disableEvents[$index]); | |
} | |
} | |
return $this; | |
} | |
// -------------------------------------- | |
// 以下方法重载框架原生的方法 | |
// -------------------------------------- | |
/** | |
* Fires an event, implicitly calls behaviors and listeners in the events manager are notified | |
* | |
* @param string $eventName | |
* @return boolean | |
*/ | |
public function fireEvent($eventName) | |
{ | |
$eventName = strtolower($eventName); | |
$this->_beforeFireEvent($eventName); | |
$result = in_array($eventName, $this->_disableEvents) ? true : parent::fireEventCancel($eventName); | |
$this->_afterFireEvent($eventName); | |
return $result; | |
} | |
/** | |
* Fires an event, implicitly calls behaviors and listeners in the events manager are notified | |
* This method stops if one of the callbacks/listeners returns boolean false | |
* | |
* @param string $eventName | |
* @return boolean | |
*/ | |
public function fireEventCancel($eventName) | |
{ | |
$eventName = strtolower($eventName); | |
$this->_beforeFireEvent($eventName); | |
$result = in_array($eventName, $this->_disableEvents) ? true : parent::fireEventCancel($eventName); | |
$this->_afterFireEvent($eventName); | |
return $result; | |
} | |
/** | |
* 在事件执行前调用 | |
* | |
* @param string $eventName | |
*/ | |
protected function _beforeFireEvent($eventName) | |
{ | |
/** | |
* validation 事件在整个 model 中,只会被 _preSave() 方法调用 | |
* not null 的验证将在 validation 事件前执行,因此可以在 validation 执行前将空值还原 | |
* | |
* @link https://github.com/phalcon/cphalcon/blob/master/ext/mvc/model.c#L3252 | |
*/ | |
if ($eventName === 'validation') { | |
foreach ($this->toArray() as $key => $val) { | |
// 修正空值转换后数据为 Phalcon\Db\RawValue 实例的问题 | |
if ($val instanceof RawValue) { | |
$this->$key = $val->__toString() === "''" ? '' : $val->__toString(); | |
} | |
} | |
} | |
} | |
/** | |
* 在事件被执行后调用 | |
* | |
* @param string $eventName | |
*/ | |
protected function _afterFireEvent($eventName) | |
{ | |
/** | |
* beforeValidationOnCreate / beforeValidationOnUpdate 事件在整个 model 中,只会被 _preSave() 方法调用 | |
* 执行该事件后,即会执行 not null 验证,在此之前对空值做转换 | |
* | |
* @link https://github.com/phalcon/cphalcon/blob/master/ext/mvc/model.c#L3085 | |
*/ | |
if ($eventName === 'beforevalidationoncreate' || $eventName === 'beforevalidationonupdate') { | |
foreach ($this->toArray() as $key => $value) { | |
if ($this->{$key} === '') { | |
// 将为空的值,转换为空值 | |
$this->{$key} = new RawValue("''"); | |
} | |
} | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment