-
-
Save sj-i/db9e9c72a5fff1bf28a0 to your computer and use it in GitHub Desktop.
FuelPHPのOrmをselectを考慮したものにする
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 | |
class Model_Test extends \Orm\Model | |
{ | |
public static function implode_pk($data) | |
{ | |
$result = parent::implode_pk($data); | |
if (static::$cache_context) | |
{ | |
$result .= '['.static::$cache_context.']'; | |
} | |
return $result; | |
} | |
public static function cached_object($obj, $class = null) | |
{ | |
$class = $class ?: get_called_class(); | |
$id = (is_int($obj) or is_string($obj)) ? ((string) $obj).'['.static::$cache_context.']' : $class::implode_pk($obj); | |
$result = ( ! empty(static::$_cached_objects[$class][$id])) ? static::$_cached_objects[$class][$id] : false; | |
return $result; | |
} | |
static protected $cache_context = null; | |
public static function set_cache_context($cache_context) | |
{ | |
static::$cache_context = $cache_context; | |
} | |
protected static function reset_cache_context() | |
{ | |
static::set_cache_context(join('|', array_keys(static::properties()))); | |
} | |
public static function _init() | |
{ | |
static::reset_cache_context(); | |
} | |
public static function query($options = array()) | |
{ | |
$result = Query_ContextAwareCache::forge(get_called_class(), array(static::connection(), static::connection(true)), $options); | |
return $result; | |
} | |
public static function find($id = null, array $options = array()) | |
{ | |
static::reset_cache_context(); | |
return parent::find($id, $options); | |
} | |
protected function create() | |
{ | |
// Only allow creation with new object, otherwise: clone first, create later | |
if ( ! $this->is_new()) | |
{ | |
return false; | |
} | |
$this->observe('before_insert'); | |
// Set all current values | |
$query = Query_ContextAwareCache::forge(get_called_class(), static::connection(true)); | |
$primary_key = static::primary_key(); | |
$properties = array_keys(static::properties()); | |
foreach ($properties as $p) | |
{ | |
if ( ! (in_array($p, $primary_key) and is_null($this->{$p}))) | |
{ | |
$query->set($p, $this->{$p}); | |
} | |
} | |
// Insert! | |
$id = $query->insert(); | |
// when there's one PK it might be auto-incremented, get it and set it | |
if (count($primary_key) == 1 and $id !== false) | |
{ | |
$pk = reset($primary_key); | |
// only set it if it hasn't been set manually | |
is_null($this->{$pk}) and $this->{$pk} = $id; | |
} | |
// update the original properties on creation and cache object for future retrieval in this request | |
$this->_is_new = false; | |
$this->_original = $this->_data; | |
static::$_cached_objects[get_class($this)][static::implode_pk($this)] = $this; | |
$this->observe('after_insert'); | |
return $id !== false; | |
} | |
} | |
class Query_ContextAwareCache extends \Orm\Query | |
{ | |
public function hydrate(&$row, $models, &$result, $model = null, $select = null, $primary_key = null) | |
{ | |
if ($model) | |
{ | |
$context = is_array($selects = $this->select()) ? join('|', str_replace($this->alias.'.', '', Arr::pluck($selects, 0))) : $selects; | |
$model::set_cache_context($context); | |
} | |
// First check the PKs, if null it's an empty row | |
$r1c1 = reset($select); | |
$prefix = substr($r1c1[0], 0, strpos($r1c1[0], '.') + 1); | |
$obj = array(); | |
foreach ($primary_key as $pk) | |
{ | |
$pk_c = null; | |
foreach ($select as $s) | |
{ | |
$s[0] === $prefix.$pk and $pk_c = $s[1]; | |
} | |
if (is_null($row[$pk_c])) | |
{ | |
return false; | |
} | |
$obj[$pk] = $row[$pk_c]; | |
} | |
// Check for cached object | |
$pk = count($primary_key) == 1 ? reset($obj) : '['.implode('][', $obj).']'; | |
$obj = $this->from_cache ? $model::cached_object($pk, $model) : false; | |
// Create the object when it wasn't found | |
if ( ! $obj) | |
{ | |
// Retrieve the object array from the row | |
$obj = array(); | |
foreach ($select as $s) | |
{ | |
$f = substr($s[0], strpos($s[0], '.') + 1); | |
$obj[$f] = $row[$s[1]]; | |
if (in_array($f, $primary_key)) | |
{ | |
$obj[$f] = \Orm\Observer_Typing::typecast($f, $obj[$f], call_user_func($model.'::property', $f)); | |
} | |
unset($row[$s[1]]); | |
} | |
$obj = $model::forge($obj, false, $this->view ? $this->view['_name'] : null, $this->from_cache); | |
} | |
else | |
{ | |
// add fields not present in the already cached version | |
foreach ($select as $s) | |
{ | |
$f = substr($s[0], strpos($s[0], '.') + 1); | |
if ( ! isset($obj->{$f})) | |
{ | |
$obj->{$f} = $row[$s[1]]; | |
} | |
} | |
} | |
// if the result to be generated is an array and the current object is not yet in there | |
if (is_array($result) and ! array_key_exists($pk, $result)) | |
{ | |
$result[$pk] = $obj; | |
} | |
// if the result to be generated is a single object and empty | |
elseif ( ! is_array($result) and empty($result)) | |
{ | |
$result = $obj; | |
} | |
// start fetching relationships | |
$rel_objs = $obj->_relate(); | |
foreach ($models as $m) | |
{ | |
// when the expected model is empty, there's nothing to be done | |
if (empty($m['model'])) | |
{ | |
continue; | |
} | |
// when not yet set, create the relation result var with null or array | |
if ( ! array_key_exists($m['rel_name'], $rel_objs)) | |
{ | |
$rel_objs[$m['rel_name']] = $m['relation']->singular ? null : array(); | |
} | |
// when result is array or singular empty, try to fetch the new relation from the row | |
$this->hydrate( | |
$row, | |
! empty($m['models']) ? $m['models'] : array(), | |
$rel_objs[$m['rel_name']], | |
$m['model'], | |
$m['columns'], | |
$m['primary_key'] | |
); | |
} | |
// attach the retrieved relations to the object and update its original DB values | |
$obj->_relate($rel_objs); | |
$obj->_update_original_relations(); | |
return $obj; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment