Skip to content

Instantly share code, notes, and snippets.

@zhouyl
Last active August 29, 2015 14:02
Show Gist options
  • Save zhouyl/ae0e9ceccd135f3c72b6 to your computer and use it in GitHub Desktop.
Save zhouyl/ae0e9ceccd135f3c72b6 to your computer and use it in GitHub Desktop.
Fixed Phalcon\Mvc\Model empty string
<?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