MetaModel – 元数据子表数据处理类 [ 2.0 版本 ]
说明
处理使用类似WordPress Posts 表 和 Postmeat 表 之间的元数据关系的增删改查操作。
版本
V 0.8.0
使用步骤
假定:表postmeta是表posts的元数据从表(数据结构请查询 WordPress 对应的表结构)
1、主表模型(posts)继承 MetaModel
2、重写静态函数 metaModelName() 和 metaRelevanceField()。必须重写。
3、使用处理函数meta进行元数据处理
示例
$post = Posts::findOne(1);
$post->meta('key'); //获取元数据 key 的反序列化内容 ,为空返回 null
$post->meta('key',false); //直接获取元数据 key 内容
$post->meta('key','value'); //为元数据 key 写入序列化后的value值
$post->meta('key','value',false); //为元数据 key 直接写入value值
$post->meta(['key'...],['value'...]); //为元数据键值序列写入对应的值
$post->deleteMeta('key'); //删除元数据 $key
更新地址:http://www.sv0.cn/blog/metamodel/
V0.8.0 下载地址:http://www.sv0.cn/blog/wp-content/uploads/2015/12/MetaModel.rar
下载地址在更新后会发生变化,请移步 更新地址 查看
/**
* MetaModel - Yii2 - 元数据子表数据处理类
*
* 处理使用类似WordPress Posts 表 和 Postmeat 表 之间的元数据关系的增删改查操作。
*
* 使用步骤
* 假定:posts 是主表 postmeta 是从表(数据结构请查询 WordPress 对应的表结构)
* 1、主表(posts)继承 MetaModel 类别
* 2、重写静态函数 metaModelName() 和 metaRelevanceField()。必须重写。
* 3、使用处理函数meta进行元数据处理
* $post = Posts::findOne(1);
* $post->meta('key'); //获取元数据 key 的反序列化内容 ,为空返回 null
* $post->meta('key',false); //直接获取元数据 key 内容
* $post->meta('key',$value); //为元数据 key 写入序列化后的value值
* $post->meta('key',$value,false); //为元数据 key 直接写入value值
* $post->meta(['key'...],[$value...]); //为元数据键值序列写入对应的值
* $post->delete('key'); //删除元数据 $key *
* @version V 0.8.0
* @link http://www.sv0.cn/
* @copyright qcheat702@163.com
* @license http://www.sv0.cn/blog/metamodel/
* @update http://www.sv0.cn/blog/metamodel/
*/
namespace app\models;
use Yii;
use yii\base\Model;
class MetaModel extends \yii\db\ActiveRecord
{
public $_config;
public $_metas;
public $_metaErrors;
/**
* =======================需要重写的函数
*/
/**
* 元数据规则,(格式与Yii2 Rule定义方式一致)需要重写
* @return array 规则序列 目前只有 exist 生效 [[*],'safe'] 代表接受所有未定义的元数据
*/
public function metaRules(){
return [
[['*'], 'safe']
];}
/**
* 元数据键值标签,未定义的键值标签将是键值本身 需要重写
* @return array 标签序列
*/
public function metaLabels(){return [];}
/**
* 静态 包含命名空间的完整元数据模型名称,需要重写
* @return String [description]
*/
static public function metaModelName(){return '[namaspace]/ModelName';}
/**
* 静态 元数据关联字段,需要重写
* @return String 元数据模型与主体主键关联的字段名称
*/
static public function metaRelevanceField(){return 'ModelName_ID';}
/**
* =======================需要重写的函数 end
*/
/**
* 获取/设置 元数据
* @param string/array $keys
* 元数据键值/元数据键值对序列
* keys为字符串,不设置$values,则返回值
* keys为字符串,设置$values,则设置值
* keys键值序列,按序列则返回值
* keys键值序列,$values与之一一对应,则设置值
* @param mixed/array/null(default) $value 值
* @param Boolean $encode 是否编码,默认true
* @return [type] [description]
*/
public function meta($keys=null,$values=null,$encode=true)
{
//如果键值是字符串
if( is_string($keys) )
{
//如果不设置值
if( is_null($values) )
{
$meta = $this->getMetas($keys,$encode);
if( is_null($meta) )return null;
// return $meta;
return $meta->meta_value;
// else return $meta->meta_value;
}else
$this->setMatas($keys,$values,$encode);
}
//如果键值是数组
if( is_array($keys) ){
if( is_array($values) ){
if( count($keys) !== count($values) )
throw new ErrorException('键值序列与值序列长度不一致');
foreach ($keys as $ko => $option)
$this->setMeta($option,$values[$ko],$encode);
}else
return $this->getMetas();
}
}
//获取配置 暂未使用
public function getConfig(){
$config = $this->_config;
if( !empty($config) )
foreach ($config as $key => $value)
{
if( !isset($value['label']) )$value['label'] = $key;
$config[$key] = $value;
}
return $config;
}
//写入配置 暂未使用
public function setConfig($config){
$this->_config = $config;
}
/**
* 元数据值编码
* @param mixed $data 数据
* @return string 编码后的元数据值
*/
public function encodeMetaValue($data)
{
return serialize($data);
}
/**
* 元数据值解码
* @param string $data 数据
* @return mixed 解码后的元数据值
*/
public function decodeMetaValue($string)
{
return @unserialize($string);
}
/**
* 获取元数据标签
* @param mixed[string/array/null] $metas 元数据键值或键值序列
* @return mixed[string/array/null] 对应的元数据标签。元数据为字符串,返回其标签字符串,未定义标签则返回其本身;元数据为数组,则返回以其自身为键值的元数据标签序列;为空返回所有已定义的标签
*/
public function getMataLabels($meta_keys=null)
{
//获取所有的元数据标签
$metaLabels = $this->metaLabels();
//如果没有参数,返回全部已定义以的标签
if( is_null($meta_keys) )return $metaLabels;
//如果参数是字符串
if( is_string($meta_keys) )
return isset($metaLabels[$meta_keys])?$metaLabels[$meta_keys]:$meta_keys;
//如果参数是数组
if( is_array($meta_keys) )
{
$_arr = null;
foreach ($meta_keys as $key => $value)
$_arr[$value] = isset($metaLabels[$value])?$metaLabels[$value]:$value;
return $_arr;
}
return null;
}
/**
* 获取元数据规则
* @param string $meta_key 元数据键值
* @return array/null 元数据规则数组,无效的键值会抛出错误
*/
public function getMetaRules($meta_key=null)
{
$metarules = null;
foreach ($this->metaRules() as $kr => $vr)
{
foreach ($vr[0] as $km => $vm)
$metarules[$vm][$vr[1]] = isset($vr[2])?$vr[2]:true;
$metarules[$vm]['exist'] = true;
}
return $metarules;
}
/**
* 校验 (该函数尚未完成)
* @param string $meta_key 键
* @param string/null(default) $value 值,值为空只校验是否存在,否则校验值是否符合规则
* @return boolean 是否校验成功
*/
public function metaValidate($meta_key,$value=null)
{
$metarules = $this->getMetaRules();
//校验是否存在
if( isset($metarules['*']['safe']) || isset($metarules[$meta_key]['exist']) )
return true;
//校验键值是否符合规则
// (待补充)
$this->addError('_metaErrors',$meta_key.' : 不在可接受的元数据简直范围内');
return false;
}
/**
* 获取元数据属性键值对
* @param mixed[string/array] $metas 元数据键值/元数据键值序列
* @return array/null 参数为字符串返回单一元数据/参数为元数据键值序列时返回以元数据键值为键值的元数据序列
*/
public function getMetaAttributes($meta_keys)
{
if( empty($meta_keys) ) return null;
//如果元数据键值是字符串
if ( is_string($meta_keys) )
return $this->getMeta($meta_keys);
//如果元数据键值是数组序列
if( is_array($meta_keys) )
{
$_arr = null;
foreach ($meta_keys as $km => $meta_key)
{
$_mata = $this->getMeta($meta_key);
if( !is_null($_mata) )
$_arr[$meta_key] = $this->getMeta($meta_key);
}
return $_arr;
}
return null;
}
/**
* 获取单个元数据属性
* @param string $meta 元数据键值
* @return array/null 元数据属性数组
*/
public function getMetaAttribute($meta_key)
{
if( $this->metaValidate($meta_key) )return null;
return
[
'key' => $meta_key,
'label' => $this->getMataLabels($meta_key),
'rules' => $this->getMetaRules($meta_key)
];
}
/**
* 批量设置元数据
* @param string/array $options 元数据键值或键值对序列
* @param mixed $value 元数据值,当参数$options为字符串时生效,空值不更新
* @param boolean $encode 是否编码,默认true
*/
public function setMatas($options,$value=null,$encode=true)
{
if( is_string($options) )
$this->setMeta($options,$value,$encode);
if( is_array($options) )
foreach ($options as $key => $option){
$this->setMeta($key,$option,$encode);
}
}
/**
* 设置元数据
* @param string $key 元数据键值
* @param mixed $value 元数据值
* @param boolean $encode 是否编码,默认true
* @return true/false 设置成功或者失败
*/
public function setMeta($key,$value,$encode=true)
{
if( empty($this->primaryKey) )return false;
//校验
if( !$this->metaValidate($key,$value) )
return false;
$meta = $this->getMetas($key);
if( is_null($meta) ){
$meta = static::metaModel();
$relevance = static::metaRelevanceField();
$meta->$relevance = $this->primaryKey;
$meta->meta_key = $key;
}
$meta->meta_value = ($encode?$this->encodeMetaValue($value):$value.'');
if( !$meta->save() ){
// $this->addError('_metaErrors',$meta->getErrors());
//errors:保存到元数据表出错
throw new ErrorException('保存到元数据表'.$meta->tableName().'出错');
return false;
}
return true ;
}
/**
* 获取指定的元数据
* @param mixed[string/array/null(default)] $metas 元数据键值或者键值序列,为空返回所有已经存在的元数据
* @param boolean $decode 是否解编码,默认true
* @return array/null 元数据AR对象或AR对象序列
*/
public function getMetas($meta_keys=null,$decode=true)
{
$metas = $this->findMetaModels();
if( $decode )
foreach ($metas as $km => $meta){
$_decodeValue = $this->decodeMetaValue($meta->meta_value);
//如果解码正确,则输出解码后的数据
if( $_decodeValue !== false )
$meta->meta_value = $_decodeValue;
}
if( is_string($meta_keys) ){
foreach ($metas as $key => $meta)
if( $meta->meta_key === $meta_keys ) return $meta;
return null;
}
if( is_array($meta_keys) ){
$metas = null;
foreach ($metas as $key => $meta)
if( in_array($meta->meta_key, $meta_keys) )
$metas[] = $meta;
return $metas;
}
return null;
}
/**
* 获取元数据
* @param [type] $meta_key 元数据键值
* @param boolean $decode 是否解码( decodeMetaValue )
* @return models[] 元数据模型序列
*/
public function getMeta($meta_key,$decode=true)
{
$meta = $this->findMetaModels($meta_key);
if( is_null($meta) )return false;
if( $decode ){
$_decodeValue = $this->decodeMetaValue($meta->meta_value);
//如果解码正确,则输出解码后的数据
if( $_decodeValue !== false )
$meta->meta_value = $this->decodeMetaValue($meta->meta_value);
}
return $meta;
}
/**
* 删除元数据
* @param String $meta_keys [description]
* @return true/False [description]
*/
public function deleteMeta($meta_key){
$metas = $this->getMetas($meta_key);
if( empty($metas) )return false;
return $metas->delete();
}
/**
* 获取元数据模型
* @return model
*/
static private function metaModel()
{
$model = static::metaModelName();
return new $model;
}
/**
* 查找元数据模型集
*/
private function findMetaModels($forceNew = false)
{
if( !isset($this->_metas) || $forceNew )
{
$model = static::metaModel();
$relevance = static::metaRelevanceField();
$query = $model->find();
$query->andFilterWhere([$relevance=>$this->primaryKey]);
$this->_metas = $query->all();
}
$metas = $this->_metas;
return $metas;
}
public function getMetaQuery(){
$meta = static::metaModel();
$metaRelevanceField = static::metaRelevanceField();
$primaryKey = static::primaryKey();
$primaryKey = $primaryKey[0];
return $this->hasMany($meta->className(), [$metaRelevanceField =>$primaryKey ]);
}
/**
* [findWithMeta description]
* @param [type] $conditions [description]
* @return ActiveQuery
*/
static public function findWithMeta($conditions){
$query = static::find();
$query->from(static::tableName() . ' m');
$meta = static::metaModel();
$primaryKey = static::primaryKey();
$primaryKey = $primaryKey[0];
$metaRelevanceField = static::metaRelevanceField();
if( is_array($conditions) )
{
$i = 1;
foreach ($conditions as $key => $condition)
{
$alias = 't'.$i;
$on = '
m.`'.$primaryKey.'` = '.$alias.'.`'.$metaRelevanceField.'`
AND ('.$alias.'.meta_key=\''.$key.'\' AND '.$alias.'.meta_value = \''.$condition.'\')
AND '.$alias.'.meta_value != \'\'';
$query->innerJoin($meta::tableName().' '.$alias,$on);
$i++;
}
}
return $query;
}
}
qcheat702
注册时间:2013-12-04
最后登录:2016-05-31
在线时长:23小时33分
最后登录:2016-05-31
在线时长:23小时33分
- 粉丝2
- 金钱25
- 威望10
- 积分355
热门源码
- 基于 Yii 2 + Bootstrap 3 搭建一套后台管理系统 CMF
- 整合完 yii2-rbac+yii2-admin+adminlte 等库的基础开发后台源码
- 适合初学者学习的一款通用的管理后台
- yii-goaop - 将 goaop 集成到 Yii,在 Yii 中优雅的面向切面编程
- yii-log-target - 监控系统异常且多渠道发送异常信息通知
- 店滴云1.3.0
- 面向对象的一小步:添加 ActiveRecord 的 Scope 功能
- Yii2 开源商城 FecShop
- 基于 Yii2 开发的多店铺商城系统,免费开源 + 适合二开
- leadshop - 基于 Yii2 开发的一款免费开源且支持商业使用的商城管理系统
共 3 条评论
点个赞,是我需要的东东,谢谢作者分享~
谢谢,能有用真好。
点个赞~~~~
元数据是什么啊
元数据的概念可以度娘 。简单的实现形式就是使用两张表达到类似 “ 按需自动扩展数据字段 ” 的目的。