前面我们已经完成了orm最核心部分–拼凑字符串,接下来我们需要执行拼凑完成的sql语句。这里只完成了insert操作
折腾(二)-与pdo进行组合,实现执行拼凑完成的sql语句
我们先建立两张表
user
名 | 类型 | 长度 | 小数点 | 允许空值 |
---|---|---|---|---|
user_id | int | 11 | 0 | false |
user_name | varchar | 20 | 0 | false |
user_pwd | varchar | 32 | 0 | false |
order
名 | 类型 | 长度 | 小数点 | 允许空值 |
---|---|---|---|---|
order_id | int | 11 | 0 | false |
user_id | int | 11 | 0 | false |
order_price | decimal | 5 | 2 | false |
执行insert后的效果
与pdo组合之后的代码如下,所示,有兴趣可以研究下:
<?php
ini_set('display_errors',1);
ini_set('error_reporting',E_ALL);
$map=function ($items) {
if (!is_array($items)) {
return $items;
} else {
$result="";
foreach ($items[1] as $item) {
if ($result!="")
$result.=",";
$result.=$item.$this->_aliastb($item);//类似news,news_class 添加到form后面
}
return $items[0].$result;
}
};
class orm
{
public $sql=array(
"select"=>"select ",
"from"=>array("from ",array()),
"where"=>" where ",
"orderby"=>" order by ",
"insertinto"=>"insert into ",//insert操作
"insertfields"=>"",
"values"=>" values"
);
public $errorCode="";//错误代码
public $sql_bak=[];
public function __construct()
{
$this->sql_bak=$this->sql;
$this->db=new PDO("mysql:host=127.0.0.1;dbname=testOrm","root","hello2016");//初始化数据库连接
}
public function select()
{
$fields=func_get_args();
foreach ($fields as $field) {
if (is_array($field)) {
$get_key=key($field);//获取数组的key,其实就是表的名字,还需要在字段前面加上表前缀
$this->__add(__FUNCTION__, $this->_aliastb($get_key).'.'.$field[$get_key]);
} else {
$this->__add(__FUNCTION__, $field);
}
}
return $this;
}
//插入数据
public function insert() {
$params=func_get_args();//获取可变参数
$fields=[];
$fields_values=[];
$callback=[];
foreach ($params as $param) {
if (is_array($param)) {//代表要拼接的是字段和值
foreach ($param as $item) {
//取出字段名
$field=key($item);
//取出字段的值
$field_value=$item[$field];
//把上面的字段和字段值插入相对应的数组
$fields[]=$field;
//拼凑字符串的时候,判断是否是字符串,如果是字符串则要加上单引号
if (is_string($field_value)) {
$field_value="'".$field_value."'";
}
$fields_values[]=$field_value;
}
//处理完参数之后,构造要插入字段的拼凑
$this->__add("insertfields", '('.implode($fields,',').')');
$this->__add("values", '('.implode($fields_values,',').')');
}
//如果是字符串说明传的是表名
if (is_string($param)) {
$this->__add("insertinto", $param);
}
if(is_bool($param) && $param) //如果传过来的参数是 布尔型,且为true,则默认开启事务
{
$this->db->beginTransaction();
}
if (is_callable($param)) {
$callback[]=$param;
}
}
if(count($callback)>0)
{
$this->exec();//如果有匿名函数,则先执行SQL
$this->clearConfig(); //恢复配置到最开始状态,防止执行其他SQL时产生冲突。大家可以把SQL保存到 某个类属性中
foreach($callback as $call)//最后统一执行各个回调函数
{
$call=Closure::bind($call,$this);//这样在匿名函数中就可以使用$this ,且这个$this就是orm对象
$call();//手工调用 匿名函数,这就是回调
}
}
return $this;
}
//避免sql语句相互干扰
function clearConfig()//恢复到原有配置
{
$this->sql=$this->sql_bak;
}
//排序
function orderby($str, $order)
{
$order=' '.$order;
if (is_array($str)) {
$tb=key($str);
$this->__add(__FUNCTION__, $this->_aliastb($tb).'.'.$str[$tb].$order);
} else {
$this->__add(__FUNCTION__, $str.$order);
}
return $this;
}
//给表加别名
public function _aliastb($tbName) {
return ' _'.$tbName;
}
public function from($tableName)//处理from过程
{
if (is_array($tableName)) {//是数组的话就是代表多张表关联
if (count($tableName)!=2) return $this;//参数值类似[["name"=>classid""],["name_class"]=>"id"],小于2灭有意义
$tb1=current($tableName);
$tb2=next($tableName);
//第一步,把表的key值作为from参数进行处理
$tb1_key=key($tb1);
$tb1_value=$tb1[$tb1_key];
$tb2_key=key($tb2);
$tb2_value=$tb2[$tb2_key];
$this->__add(__FUNCTION__, $tb1_key);
$this->__add(__FUNCTION__, $tb2_key);
//第二步,拼凑where条件
$whereString=' _'.$tb1_key.'.'.$tb1_value.'='."_".$tb2_key.'.'.$tb2_value;
$this->where($whereString);
return $this;
} else { //字符串则表示单张表查询
$this->__add(__FUNCTION__, $tableName);
return $this;
}
}
public function where($str) {
$this->__add(__FUNCTION__, $str, " and ");
return $this;
}
public function __add($key, $str, $spliter=",")//实现字符串的累加
{
//调用不存在的方法,直接返回
if(!array_key_exists($key, $this->sql)) return ;
if (is_array($this->sql[$key])) {
//如果已经存在该项表明我们不做什么处理
if (!in_array($str, $this->sql[$key][1])) {
$this->sql[$key][1][]=$str;
}
} else {
//如果是字符串,直接进行字符串累加
// if (trim($this->sql[$key])!=$key)
if (preg_replace('/\s/', '', $this->sql[$key])!=$key && preg_replace("/\s/", '', $this->sql[$key])!="")
$this->sql[$key].=$spliter;
$this->sql[$key].=$str;
}
}
public function __toString()
{
global $map;
$map=Closure::bind($map ,$this);
//
$filter=function ($value, $key) {
// if(!is_string($value)) return true;
if(is_array($value)) {
if(count($value[1])>0) return true;
return false;
}
//如果是空字符串也不参与累加
if(preg_replace("/\s/", '', $value)==$key || preg_replace("/\s/", "", $value )=="")
return false;
return true;
};
$this->sql=array_filter($this->sql, $filter, ARRAY_FILTER_USE_BOTH );
$res=array_map($map, array_values($this->sql));//
$this->sql=$this->sql_bak;
return implode(array_values($res), ' ');//把新的数组重新构建成一个字符串
}
public function exec()
{
//测试执行方法
$sql=strval($this); //会自动调用 _tostring方法
$stmt=$this->db->prepare($sql);
if(!$stmt->execute())//执行失败,
{
if($this->db->inTransaction()) //判断是否开启了事务
{
$this->db->rollBack();//执行回滚
}
$this->errorCode=$stmt->errorCode();
echo "执行Sql".$sql.'出错,错误代码:'.$this->errorCode.",错误信息:".$stmt->errorInfo()[2];
}
return $this;
}
function getLastInsertID() //获取上一条SQL执行情况
{
return $this->db->lastInsertId();
}
function getAll() //获取全部取出的结果
{
return $this->db->fetchAll();
}
function commit()
{
//提交事务
if($this->db->inTransaction())
$this->db->commit();
}
}
$orm=new orm();
echo $orm->insert(true,[
['user_name'=>"seven"],
['user_pwd'=>md5('123')]
],"user",function(){
$userid=$this->getLastInsertID(); //获取用户注册后的自增ID
$this->insert([
['user_id'=>intval($userid)],
['order_price'=>100],
],"orders",function(){
if($this->errorCode=="")
{
$this->commit();
echo "sucess!";
}
else
{
echo "fail!";
}
});
});