Skip to content

Instantly share code, notes, and snippets.

@fagai
Created April 16, 2013 07:33
Show Gist options
  • Save fagai/5394102 to your computer and use it in GitHub Desktop.
Save fagai/5394102 to your computer and use it in GitHub Desktop.
FuelPHPのormのModel_Softをだいたい日本語化。
<?php
/**
* Model_Soft 日本語化
* @author fagai
*/
namespace Orm;
class RelationNotSoft extends \Exception
{
}
/**
* Defines a model that can be "soft" deleted. A timestamp is used to indicate
* that the data has been deleted but the data itself is not removed from the
* database.
*
* @author Steve "Uru" West <uruwolf@gmail.com>
*/
class Model_Soft extends Model
{
/**
* 削除されたタイムスタンプが入るデフォルトのカラム名
* @var string
*/
protected static $_default_field_name = 'deleted_at';
/**
* timestampを使用しているかどうか
* @var boolean
*/
protected static $_default_mysql_timestamp = true;
/**
* Contains cached soft delete properties.
* @var array
*/
protected static $_soft_delete_cached = array();
// key => value形式で記述。keyがクラス名。フィルタから除外するにはfalseを指定する。
protected static $_disable_filter = array();
/**
* soft deleteのプロパティを取得する
* Mostly stolen from the parent class properties() function
*
* @return array
*/
public static function soft_delete_properties()
{
$class = get_called_class();
// キャッシュが残っていればキャッシュを返す
if (array_key_exists($class, static::$_soft_delete_cached))
{
return static::$_soft_delete_cached[$class];
}
$properties = array();
// クラスにプロパティが存在するか調べる
if (property_exists($class, '_soft_delete'))
{
//無かったら親を適用
$properties = static::$_soft_delete;
}
// 次回のためにキャッシュをとる
static::$_soft_delete_cached[$class] = $properties;
return static::$_soft_delete_cached[$class];
}
/**
* 削除のフィルタから除外する
*/
public static function disable_filter()
{
$class = get_called_class();
static::$_disable_filter[$class] = false;
}
/**
* 削除のフィルタを適用する
*/
public static function enable_filter()
{
$class = get_called_class();
static::$_disable_filter[$class] = true;
}
/**
* @return boolean delete_fieldを適用する場合はtrue。適用しない場合はfalse
*/
public static function get_filter_status()
{
$class = get_called_class(); // コール元のクラス名を取得
return \Arr::get(static::$_disable_filter, $class, true);
}
/**
* Fetches a soft delete property description array, or specific data from it.
* Stolen from parent class.
*
* @param string property or property.key
* @param mixed return value when key not present
* @return mixed
*/
public static function soft_delete_property($key, $default = null)
{
$class = get_called_class();
// キャッシュの確認
if ( ! array_key_exists($class, static::$_soft_delete_cached))
{
static::soft_delete_properties();
}
//キャッシュされたクラスにあるプロパティ名、$keyを取得して返す
return \Arr::get(static::$_soft_delete_cached[$class], $key, $default);
}
/**
* Do some php magic to allow static::find_deleted() to work
*
* @param type $method
* @param type $args
*/
public static function __callStatic($method, $args)
{
// 互換のために用意されている?
if (strpos($method, 'find_deleted') === 0)
{
$temp_args = $args;
$find_type = count($temp_args) > 0 ? array_pop($temp_args) : 'all';
$options = count($temp_args) > 0 ? array_pop($temp_args) : array();
return static::deleted($find_type, $options);
}
parent::__callStatic($method, $args);
}
/**
* 論理削除を行う。
*
* @return this
*/
public function delete($cascade = null, $use_transaction = false)
{
// プロパティの取得
$deleted_column = static::soft_delete_property('deleted_field', static::$_default_field_name);
$mysql_timestamp = static::soft_delete_property('mysql_timestamp', static::$_default_mysql_timestamp);
//トランザクションを使用している場合は接続を確認
if ($use_transaction)
{
$db = \Database_Connection::instance(static::connection(true));
$db->start_transaction();
}
//オブザーバーを読む
$this->observe('before_delete');
//delete fieldに入れるタイムスタンプを保存
$this->{$deleted_column} = $mysql_timestamp ? \Date::forge()->format('mysql') : \Date::forge()->get_timestamp();
//ループで関係のあるレコードのカスケード削除を行う
$this->freeze();
foreach ($this->relations() as $rel_name => $rel)
{
//get the cascade delete status
$relCascade = is_null($cascade) ? $rel->cascade_delete : (bool) $cascade;
//Make sure that the other model is soft delete too
if ($relCascade)
{
if ( ! is_subclass_of($rel->model_to, 'Orm\Model_Soft'))
{
//Throw if other is not soft
throw new RelationNotSoft('Both sides of the relation must be subclasses of Model_Soft if cascade delete is true');
}
if(get_class($rel) != 'Orm\ManyMany')
{
//Loop through and call delete on all the models
foreach($rel->get($this) as $model)
{
$model->delete($cascade);
}
}
}
}
$this->unfreeze();
$this->save();
$this->observe('after_delete');
//Make sure the transaction is commited if needed
$use_transaction and $db->commit_transaction();
return $this;
}
/**
* 論理削除したものを戻す
*/
public function restore($cascade_restore = null)
{
$deleted_column = static::soft_delete_property('deleted_field', static::$_default_field_name);
$this->{$deleted_column} = null; //削除していないことにするためにnullを入れる
//カスケード削除したものもループで戻す
$this->freeze();
foreach ($this->relations() as $rel_name => $rel)
{
//get the cascade delete status
$rel_cascade = is_null($cascade_restore) ? $rel->cascade_delete : (bool) $cascade_restore;
//Make sure that the other model is soft delete too
if ($rel_cascade)
{
if ( ! is_subclass_of($rel->model_to, 'Orm\Model_Soft'))
{
//Throw if other is not soft
throw new RelationNotSoft('Both sides of the relation must be subclasses of Model_Soft if cascade delete is true');
}
if (get_class($rel) != 'Orm\ManyMany')
{
$model_to = $rel->model_to;
$model_to::disable_filter();
//Loop through and call restore on all the models
foreach($rel->get($this) as $model)
{
$model->restore($cascade_restore);
}
$model_to::enable_filter();
}
}
}
$this->unfreeze();
$this->save();
return $this;
}
/**
* Alias of restore()
*/
public function undelete()
{
return $this->restore();
}
/**
* findメソッドをオーバーライド。削除された行は除外するようにする。
*/
public static function find($id = null, array $options = array())
{
if (static::get_filter_status())
{
//Make sure we are filtering out soft deleted items
$deleted_column = static::soft_delete_property('deleted_field', static::$_default_field_name);
$options['where'][] = array($deleted_column, null);
}
return parent::find($id, $options);
}
/**
* queryメソッドをオーバーライド。削除された行は除外するようにする。
*/
public static function query($options=array())
{
if (static::get_filter_status())
{
//Make sure we are filtering out soft deleted items
$deleted_column = static::soft_delete_property('deleted_field', static::$_default_field_name);
$options['where'][] = array($deleted_column, null);
}
return parent::query($options);
}
/**
* findメソッドをオーバーライドしている。論理削除済みのレコードを取得する
*/
public static function deleted($id = null, array $options = array())
{
//Make sure we are not filtering out soft deleted items
$deleted_column = static::soft_delete_property('deleted_field', static::$_default_field_name);
$options['where'][] = array($deleted_column, 'IS NOT', null);
static::disable_filter();
$result = parent::find($id, $options);
static::enable_filter();
return $result;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment