Created
April 16, 2013 07:33
-
-
Save fagai/5394102 to your computer and use it in GitHub Desktop.
FuelPHPのormのModel_Softをだいたい日本語化。
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 | |
/** | |
* 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 <[email protected]> | |
*/ | |
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