Skip to content

Instantly share code, notes, and snippets.

@sj-i
Last active August 29, 2015 14:16
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save sj-i/db9e9c72a5fff1bf28a0 to your computer and use it in GitHub Desktop.
Save sj-i/db9e9c72a5fff1bf28a0 to your computer and use it in GitHub Desktop.
FuelPHPのOrmをselectを考慮したものにする
<?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