/** * 获取当前类型的数据 * * @param OOP_ORM_Data $obj * @param $data * @param $compiled_data * @return mixed */ public function &get_data(OOP_ORM_Data $obj, &$data, &$compiled_data, &$compiled_raw_data) { $config = $this->config(); $fun = $config['func']; $args = $config['args']; foreach ($args as &$item) { if ($item === '$this') { $item = $obj; } elseif (is_string($item) && substr($item, 0, 7) === '$this->') { $key = substr($item, 7); $item = $obj->{$key}; } } if (count($fun) === 1) { $tmp_data = call_user_func_array($fun[0], $args); } else { if ($fun[0] === '$this') { $fun[0] = $obj; $tmp_data = $obj->__orm_callback('get_by_function_di', $fun, $args); } else { $tmp_data = call_user_func_array($fun, $args); } } if (false === $config['runtime']) { # 非实时运行 $compiled_data[$this->key] = $tmp_data; $compiled_raw_data[$this->key] = $tmp_data; } return $tmp_data; }
/** * 构造数据 * * @param OOP_ORM_Data $obj * @param $data * @param $compiled_data * @return bool * @throws Exception */ public function &get_data(OOP_ORM_Data $obj, &$data, &$compiled_data, &$compiled_raw_data) { $parent_offset = $this->config['parent_offset']; $sub_offsets = $this->config['sub_offsets']; $tmp_data =& $obj->{$parent_offset}; foreach ($sub_offsets as $key) { if (null === $tmp_data) { throw new Exception("Illegal string offset '{$key}' of class {$this->class_name}, key:{$this->key}"); } if (is_object($tmp_data)) { if (isset($tmp_data->{$key})) { $tmp =& $tmp_data->{$key}; } else { $tmp = null; } } elseif (is_array($tmp_data)) { if (isset($tmp_data[$key])) { $tmp =& $tmp_data[$key]; } else { $tmp = null; } } else { throw new Exception("Illegal string offset '{$key}' of class {$this->class_name}, key:{$this->key}"); } unset($tmp_data); $tmp_data =& $tmp; unset($tmp); } # 移除指针 unset($compiled_data[$this->key]); # 重新赋值 $compiled_data[$this->key] =& $tmp_data; # 记录一个副本用于判断是否修改 $compiled_raw_data[$this->key] = $tmp_data; # 回调 $obj->__orm_callback('set_virtual_field_update', $parent_offset, $this->key); return $compiled_data[$this->key]; }
/** * 根据index获取一个唯一的缓存key * @param string $index * @return string */ public static function get_offset_cache_key(\OOP_ORM_Data $data_obj, $index) { $id_field_name = $data_obj->id_field_name(); $id_value = $data_obj->{$id_field_name}; return '_ORM_OFFSET_CACHE_' . \str_replace('\\', '__', \get_class($data_obj)) . '_' . $id_value . '_' . $index; }
/** * 设置用户 * * @param Member $member * @return Session */ public function set_member(OOP_ORM_Data $member) { Session::$member = $member; if ($member->id > 0) { # 设置用户数据 $member_data = $member->get_field_data(); $_SESSION['member'] = $member_data; } else { # 游客数据则清空 unset($_SESSION['member']); } return $this; }
/** * 用于给ORM回调设置数据 * @param array $data 待设置的数据 * @param boolean $is_field_key 待设置的数据的key是否数据库的字段,true是,false则为offset */ protected function __orm_callback_ini_data_($data = null, $is_field_key = false) { if (!is_array($data)) { return false; } # 记录当前orm是否构造完成 $created = $this->_orm_data_is_created; # 将orm设置为未构造状态,因为set_data时会根据构造状态执行不同的操作 $this->_orm_data_is_created = false; # 如果是字段数据,则整理为offset数据 if ($is_field_key) { foreach ($data as $key => $value) { # 获取当前字段的首个offset $offset = current($this->_get_offset_name_by_field($key)); if (!$offset) { $offset = $key; } $this->set_data($offset, $value, false); } } else { # 设置数据 $this->set_data($data, null, false); } # 还原状态 $this->_orm_data_is_created = $created; # ID数据缓存,用于重复ID主键数据查询时直接返回 if (IS_CLI && $is_field_key) { $id_field_name = $this->id_field_name(); $id = $data[$id_field_name]; if (OOP_ORM_Data::$_id_field_cache_data_num > OOP_ORM_Data::$max_id_cache_num) { // 超过最大cache数则清除掉 OOP_ORM_Data::$_id_field_cache_data = array(); } if ($id && !isset(OOP_ORM_Data::$_id_field_cache_data[$this->_class_name][$id])) { OOP_ORM_Data::$_id_field_cache_data[$this->_class_name][$id] = $data; OOP_ORM_Data::$_id_field_cache_data_num += 1; } } }
/** * 根据$bulider条件解析获取已缓存在PHP的数据 * @param array $bulider * @param array $id_cache_data * @return boolean 是否需要再次读取 */ protected function _get_id_field_cache_data(&$bulider, &$id_cache_data) { $not_need_find = false; # $bulider条件中只有1个where,则尝试在数据ID缓存中获取 if (count($bulider['where']) == 1 && ($bulider['where'][0]['AND'][1] == '=' || $bulider['where'][0]['AND'][1] == 'in')) { # foreach ($bulider['where'] as $k => $v) { if ($v && $k != 'where') { return $not_need_find; } } $field_name = $bulider['where'][0]['AND'][0]; if ($field_name == $this->id_field_name()) { $value = $bulider['where'][0]['AND'][2]; $id_data = OOP_ORM_Data::id_field_cache_data($this->get_orm_name('Data'), $value); if ($id_data) { # 获取到数据 if ($bulider['where'][0]['AND'][1] == 'in') { $new_value = array(); foreach ($value as $v) { if (!isset($id_data[$v])) { $new_value[] = $v; } } if ($new_value) { # 更新where条件 $bulider['where'][0]['AND'][2] = $new_value; } else { $not_need_find = true; } $id_cache_data = $id_data; } else { $not_need_find = true; $id_cache_data = array($id_data); } } } } return $not_need_find; }
/** * 删除当前管理员 * * @see OOP_ORM_Data::delete() * @return integer 操作行数 * @throws Exception */ public function delete() { $id = $this->id; $rs = parent::delete(); if ($rs) { # 删除管理员对应的用户组设置 $orm_group = new ORM_Admin_MemberGroup_Finder(); $orm_group->db()->where('admin_id', $id)->delete($orm_group->ids_tablename()); } return $rs; }
/** * 获取一个根据主键唯一的实例化对象 * * @param $orm_data_name * @param $data * @param OOP_ORM $finder * @param bool $is_field_key * @param array $delay_data_setting 延迟读取参数 * @return OOP_ORM_Data */ public static function create_instance($orm_data_name, array $data = array(), $finder = null, $is_field_key = false, array $delay_data_setting = array()) { $orm_data_name = strtolower($orm_data_name); if ('oop_orm_data' === $orm_data_name) { # $orm_data_name = OOP_ORM_Data 的话是虚拟对象,虚拟对象不缓存 return new $orm_data_name($data, $finder, $is_field_key, $delay_data_setting); } if ($data && isset(OOP_ORM_Data::$INSTANCE_BY_PK[$orm_data_name]) && OOP_ORM_Data::$INSTANCE_BY_PK[$orm_data_name]) { # 复用寄存器中的对象 /** * 利用一个临时对象获取主键名 * * @var $tmp_obj OOP_ORM_Data */ $tmp_obj = current(OOP_ORM_Data::$INSTANCE_BY_PK[$orm_data_name]); # 获取主键 $pk_name = $tmp_obj->get_pk_name(); unset($tmp_obj); if ($pk_name) { $tmp_id = array(); if ($is_field_key) { # 字段名 foreach ($pk_name as $field_name) { $tmp_id[] = $data[$field_name]; } $pk = implode(',', $tmp_id); } else { /** * 实例化一个新的对象 * * @var $orm OOP_ORM_Data */ $tmp_orm = new $orm_data_name($data, $finder, $is_field_key, $delay_data_setting); # 字段名 foreach ($pk_name as $field_name) { $tmp_id[] = $orm->{$field_name}; } $pk = implode(',', $tmp_id); } } else { $pk = null; } if ($pk && isset(OOP_ORM_Data::$INSTANCE_BY_PK[$orm_data_name][$pk])) { /** * 获取唯一主键的对象 * * @var $orm OOP_ORM_Data */ $orm = OOP_ORM_Data::$INSTANCE_BY_PK[$orm_data_name][$pk]; # 更新ORM数据 if ($data) { $orm->__orm_callback('renew_data', $data, $is_field_key); } if ($finder) { $orm->__orm_callback('set_finder', $finder); } return $orm; } } if (isset($tmp_orm)) { $orm = $tmp_orm; } else { if (!class_exists($orm_data_name, true)) { throw new Exception("Class '{$orm_data_name}' not found", E_ERROR); } /** * 实例化一个新的对象 * * @var $orm OOP_ORM_Data */ $orm = new $orm_data_name($data, $finder, $is_field_key, $delay_data_setting); } if ($data && ($pk = $orm->pk())) { if (OOP_ORM_Data::$NEW_INSTANCE_COUNT >= OOP_ORM_Data::$RELEASE_INSTANCE_COUNT) { $old_released_count = OOP_ORM_Data::$RELEASED_COUNT; foreach (OOP_ORM_Data::$INSTANCE_BY_PK as $item) { foreach ($item as $o) { /** * @var $o OOP_ORM_Data */ $o->__orm_callback('try_release'); } } unset($item); unset($o); $released_count = OOP_ORM_Data::$RELEASED_COUNT - $old_released_count; # 重置计数器 OOP_ORM_Data::$NEW_INSTANCE_COUNT = 0; OOP_ORM_Data::$ALL_INSTANCE_COUNT -= $released_count; if (IS_DEBUG && $released_count) { Core::debug()->info("auto release {$released_count} orm."); } } OOP_ORM_Data::register_instance($orm, $orm_data_name, $pk); } return $orm; }
/** * 创建一条数据 * * 如果 `$data` 是数据库获取的内容,`$is_field_key` 请设置成 true * * `$is_field_key` 详细说明: * `$is_field_key` 是所传进来的数据的key是对象的键名还是字段的键名,true:对应字段的键名,false:对应对象的键名 * 差别在于: * 由于ORM DATA的键名可以和数据库的字段名称不一样,所以在设置数据的时候需要指定是哪个数据,如果键名和数据库的字段名完全一样,这样的话则没有区别 * * @param array $data 数据 * @param boolean $is_field_key 数据的键名是否数据库字段,默认false * @param string $group_id 分组ID,可不传 * @throws Exception */ public function create(array $data = array(), $is_field_key = false, $group_id = null) { $orm_data_name = $this->get_orm_name('data'); /** * @var $orm OOP_ORM_Data */ $orm = OOP_ORM_Data::create_instance($orm_data_name, $data, $this, $is_field_key); if ($group_id) { # 设置组ID $orm->__orm_callback('add_group_id', $group_id); } return $orm; }
protected static function set_query_info(OOP_ORM_Data $obj, OOP_ORM $finder, $config) { # WHERE if ($config['where']) { $finder->where($config['where']); } # MAPPING if ($config['mapping']) { foreach ($config['mapping'] as $k => $v) { $finder->where($k, $obj->{$v}); } } # 绑定数据 if (isset($config['bind']) && $config['bind']) { $finder->where($config['bind'], $obj->get_data_by_field_name($config['bind'], true)); } if (isset($config['order_by']) && $config['order_by']) { foreach ($config['order_by'] as $k => $v) { $finder->order_by($k, $v); } } # OFFSET if (isset($config['offset']) && $config['offset'] > 0) { $finder->offset($config['offset']); } # GROUP BY if (isset($config['group_by']) && $config['group_by']) { foreach ($config['group_by'] as $item) { $finder->group_by($item); } } # ORDER BY if (isset($config['order_by']) && $config['order_by']) { foreach ($config['order_by'] as $key => $item) { $finder->order_by($key, $item); } } # IN if (isset($config['in']) && $config['in']) { foreach ($config['in'] as $key => $item) { $finder->in($key, $item); } } # LIMIT if (isset($config['limit']) && $config['limit']) { $finder->limit($config['limit']); } # LIKE if (isset($config['like']) && $config['like']) { $finder->like($config['like']); } # HAVING if (isset($config['having']) && $config['having']) { $finder->having($config['having']); } # 支持扩展所有的方法 if (isset($config['other']) && $config['other']) { foreach ($config['other'] as $argv) { $k = array_pop($argv); call_user_func_array(array($finder, $k), $argv); } } }
protected function format_field_value(OOP_ORM_Data $obj, &$data, $new_data, $format_type) { # 数据主键 $id = $obj->pk(','); # 这个是对应主表的表名称,它和元数据的 table_name 字段是对应的 $table = $obj->finder()->tablename(); # 这个是metadata所在的表名称 $my_table = $this->table_name; $meta_group = $this->meta_group; if (null === $new_data || '' === $new_data || array() === $new_data) { # 删除了 # 读取已经加载的所有元数据 $old_metadata = $obj->__orm_callback('get_metadata'); if (isset($old_metadata[$my_table][$meta_group])) { foreach ($old_metadata[$my_table][$meta_group] as $hash => $item) { # 遍历所有当前组的数据 if ($item['table_name'] === $table && $item['field_name'] === $this->field_name) { # 把当前字段的数据全部设置成 null 以便进行删除处理 $data[$my_table][$hash] = null; } } } return; } # 读取已经加载的所有元数据 $old_metadata = $obj->__orm_callback('get_metadata'); $old_item_data = array(); if (isset($old_metadata[$my_table][$meta_group])) { foreach ($old_metadata[$my_table][$meta_group] as $hash => $item) { # 把数据整理到一个数组里 if ($item['table_name'] === $table && $item['field_name'] === $this->field_name) { # 把当前字段的数据全部设置成 null 以便进行删除处理 $old_item_data[$hash] = $item; } } } # 读取新数据 if ($this->config['depth']) { # 处理多行数据 $new_item_data = array(); foreach ($new_data as $k => $v) { $tmp = $this->get_meta_item($table, $id, $k, $v); $new_item_data[$tmp['hash']] = $tmp; } } else { $tmp = $this->get_meta_item($table, $id, 0, $new_data); $new_item_data[$tmp['hash']] = $tmp; } foreach ($new_item_data as $hash => $item) { $tmp_value = $item['meta_value']; if ($tmp_value !== array() && null !== $tmp_value) { if ($format_type) { # 动态格式化 if (is_array($tmp_value) || is_object($tmp_value)) { $tmp_value = serialize($tmp_value); } } elseif (isset($this->config['format']) && $this->config['format']) { # 格式化数据 $this->_format_data($tmp_value); } } $tmp_value = (string) $tmp_value; if ('' === $tmp_value) { # 空字符串,则移除 null unset($new_item_data[$hash]); } else { $new_item_data[$hash]['meta_value'] = $tmp_value; if (isset($old_item_data[$hash]) || array_key_exists($hash, $old_item_data)) { if ($old_item_data[$hash]['meta_value'] === $tmp_value) { # 相同数据,全部去掉掉则不更新 unset($new_item_data[$hash]); unset($old_item_data[$hash]); } else { unset($old_item_data[$hash]); } } } } # 把老数据清理掉 if ($old_item_data) { foreach ($old_item_data as $hash => $item) { $new_item_data[$hash] = null; } } $new_data = $new_item_data; if (isset($data[$my_table])) { $data[$my_table] += $new_data; } else { $data[$my_table] = $new_data; } }
/** * 根据index获取一个唯一的缓存key * @param string $index * @return string */ public static function get_offset_cache_key(OOP_ORM_Data $data_obj, $index) { $id_field_name = $data_obj->id_field_name(); $id_value = $data_obj->{$id_field_name}; return '_ORM_OFFSET_CACHE_' . get_class($data_obj) . '_' . $id_value . '_' . $index; }
/** * 加载对应数据库所有元数据 * * @param OOP_ORM_Data $obj * @return $this * @throws Exception */ public function load_all_metadata(OOP_ORM_Data $obj) { $class_name = $obj->class_name(); $meta_table_of_key = OOP_ORM_DI::get_meta_table_of_key($class_name); $meta_group_of_key = OOP_ORM_DI::get_meta_group_of_key($class_name); if (!$meta_table_of_key) { # 没有元数据 return $this; } # 没有主键 if (!$obj->pk()) { return $this; } $keys_of_table = array(); foreach ($meta_table_of_key as $key => $table) { $keys_of_table[$table][] = $key; } $data = array(); $groups_of_table = array(); # 读数据 foreach ($keys_of_table as $table => $keys) { foreach ($this->load_metadata($obj, $table) as $hash => $item) { $data[$table][$item['meta_group']][$hash] = $item; } foreach ($keys as $key) { $group = $meta_group_of_key[$key]; $groups_of_table[$table][$group] = $group; } } foreach ($groups_of_table as $table => $groups) { foreach ($groups as $group) { # 预置空数据 $obj->__orm_callback('set_metadata', $table, $group, array()); } } foreach ($data as $table => $group_data) { foreach ($group_data as $group => $item) { $obj->__orm_callback('set_metadata', $table, $group, $item); } } return $this; }