需求:
- 商品表的管理:CRUD、搜索、排序、翻页
- 考虑SQL注入
- 使用js插件:时间插件,在线编辑器
- 图片生成缩略图,节省带宽,加载快
创建一个控制器完成商品表的操作
namespace Admin\Controller;
use Think\Controller;
class GoodsController extends Controller
{
public function add()
{
// 2.处理表单
if(IS_POST)
{
//3. 先生成模型
// D和M的区别:D生成我们自己创建的模型对象,M生成TP自带的模型对象
// 这里我们要生成我们自己创建的模型,因为这里要使用我们自己创建的模型中的验证规则来验证表单
// 这里用M可以添加成功但是验证表单的功能会失败,因为验证规则是在我们自己定义的模型中的,而M生成的是TP自带的模型里没有验证规则
$model = D('Goods');
// 4. a.接收表单中所有的数据并存到模型中 b.使用I函数过滤数据 c.根据模型中定义的规则验证表单
//5.在create方法时传入第二个参数标记是什么类型的表单,其中1:添加,2:修改
if($model->create(I('post.'), 1))
{
// 5. 插入数据库
if($model->add())
{
// 6. 提示信息
$this->success('操作成功!', U('lst'));
// 7.停止执行后面的代码
exit;
}
}
// 8. 如果上面失败,获取失败的原因
$error = $model->getError();
// 9. 显示错误信息,并跳回到上一个页面
$this->error($error);
}
// 1.显示表单
$this->display();
}
public function edit()
{
// 处理表单
if(IS_POST)
{
$model = D('Goods');
if($model->create(I('post.'), 2))
{
// save方法的返回值是影响的记录数(mysql_affected_rows),如果修改时没有修改任何值会返回0.如果失败返回FALSE
if(FALSE !== $model->save())
{
$this->success('操作成功!', U('lst?p='.I('get.p')));
exit;
}
}
// 如果失败显示错误信息
$this->error($model->getError());
}
// 接收商品的ID
$id = I('get.id');
// 先从数据库中取出要修改的记录的信息
$model = M('Goods');
$info = $model->find($id);
$this->assign('info', $info);
// 显示修改的表单
$this->display();
}
public function delete()
{
$model = D('Goods');
$model->delete(I('get.id'));
$this->success('操作成功!', U('lst?p='.I('get.p')));
}
// 列表
public function lst()
{
$model = D('Goods');
// 获取带翻页的数据
$data = $model->search();
$this->assign(array(
'data' => $data['data'],
'page' => $data['page'],
));
$this->display();
}
}
创建模型
class GoodsModel extends Model
{
// 在添加时调用create方法时允许接收的字段
protected $insertFields = array('goods_name','price','goods_desc','is_on_sale');
// 在修改时表单中可以有哪些字段
protected $updateFields = array('id', 'goods_name','price','goods_desc','is_on_sale');
// 定义表单验证的规则,控制器中的create方法时用
protected $_validate = array(
array('goods_name', 'require', '商品名称不能为空!', 1),
array('goods_name', '1,45', '商品名称必须是1-45个字符', 1, 'length'),
array('price', 'currency', '价格必须是货币格式', 1),
array('is_on_sale', '0,1', '是否上架只能是0,1两个值', 1, 'in'),
);
// TP在调用add方法之前会自动调用这个方法,我们可以把在插入数据库之前要执行的代码写到这里
// 第一个参数:就是表单中的数据(要插入到数据库中的数据)是一个一维数组
// 第二个参数:额外信息,:当前模型对应的实际的表名是什么
// 说明:在这个函数中要改变这个函数外部的$data,需要按钮引用传递,否则修改也无效
// 说明:如果return false是指控制器中的add方法返回了false
protected function _before_insert(&$data, $option)
{
// 获取当前时间
$data['addtime'] = time();
// 上传LOGO
if(isset($_FILES['logo']) && $_FILES['logo']['error'] == 0)
{
$rootPath = C('IMG_rootPath');
$upload = new \Think\Upload(array(
'rootPath' => $rootPath,
));// 实例化上传类
$upload->maxSize = (int)C('IMG_maxSize') * 1024 * 1024;// 设置附件上传大小
$upload->exts = C('IMG_exts');// 设置附件上传类型
/// $upload->rootPath = $rootPath; // 设置附件上传根目录
$upload->savePath = 'Goods/'; // 图片二级目录的名称
// 上传文件
$info = $upload->upload();
if(!$info)
{
// 先把上传失败的错误信息存到模型中,由控制器最终再获取这个错误信息并显示
$this->error = $upload->getError();
return FALSE; // 返回控制器
}
else
{
$logoName = $info['logo']['savepath'] . $info['logo']['savename'];
// 拼出缩略图的文件名
$smLogoName = $info['logo']['savepath'] . 'thumb_' .$info['logo']['savename'];
// 生成缩略图
$image = new \Think\Image();
// 打开要处理的图片
$image->open($rootPath.$logoName);
$image->thumb(150, 150)->save($rootPath.$smLogoName);
// 把图片的表单放到表单中
$data['logo'] = $logoName;
$data['sm_logo'] = $smLogoName;
}
}
}
protected function _before_update(&$data, $option)
{
// 上传LOGO
if(isset($_FILES['logo']) && $_FILES['logo']['error'] == 0)
{
$rootPath = C('IMG_rootPath');
$upload = new \Think\Upload(array(
'rootPath' => $rootPath,
));// 实例化上传类
$upload->maxSize = (int)C('IMG_maxSize') * 1024 * 1024;// 设置附件上传大小
$upload->exts = C('IMG_exts');// 设置附件上传类型
/// $upload->rootPath = $rootPath; // 设置附件上传根目录
$upload->savePath = 'Goods/'; // 图片二级目录的名称
// 上传文件
$info = $upload->upload();
if(!$info)
{
// 先把上传失败的错误信息存到模型中,由控制器最终再获取这个错误信息并显示
$this->error = $upload->getError();
return FALSE; // 返回控制器
}
else
{
$logoName = $info['logo']['savepath'] . $info['logo']['savename'];
// 拼出缩略图的文件名
$smLogoName = $info['logo']['savepath'] . 'thumb_' .$info['logo']['savename'];
// 生成缩略图
$image = new \Think\Image();
// 打开要处理的图片
$image->open($rootPath.$logoName);
$image->thumb(150, 150)->save($rootPath.$smLogoName);
// 把图片的表单放到表单中
$data['logo'] = $logoName;
$data['sm_logo'] = $smLogoName;
// 删除商品的原图片
// 先根据商品的ID取出这件商品的图片的路径
$logo = $this->field('logo,sm_logo')->find($option['where']['id']);
// 从配置文件取出图片所在目录
$rp = C('IMG_rootPath');
// 删除图片
unlink($rp . $logo['logo']);
unlink($rp . $logo['sm_logo']);
}
}
}
public function search()
{
/************ 搜索 ****************/
$where = array(); // 默认情况下的搜索条件为空
// 商品名称的搜索
$goodsName = I('get.goods_name');
if($goodsName)
$where['goods_name'] = array('like', "%$goodsName%");
// 价格的搜索
$startPrice = I('get.start_price');
$endPrice = I('get.end_price');
if($startPrice && $endPrice)
$where['price'] = array('between', array($startPrice, $endPrice));
elseif ($startPrice)
$where['price'] = array('egt', $startPrice);
elseif ($endPrice)
$where['price'] = array('elt', $endPrice);
// 上架的搜索
$isOnSale = I('get.is_on_sale', -1);
if($isOnSale != -1)
$where['is_on_sale'] = array('eq', $isOnSale);
// 是否删除的搜索
$isDelete = I('get.is_delete', -1);
if($isDelete != -1)
$where['is_delete'] = array('eq', $isDelete);
// 时间的搜索
$startAddtime = I('get.start_addtime');
$endAddtime = I('get.end_addtime');
if($startAddtime && $endAddtime)
$where['addtime'] = array('between', array(strtotime("$startAddtime 00:00:00"), strtotime("$endAddtime 23:59:59")));
elseif ($startAddtime)
$where['addtime'] = array('egt', strtotime("$startAddtime 00:00:00"));
elseif ($endAddtime)
$where['addtime'] = array('elt', strtotime("$endAddtime 23:59:59"));
/***************** 排序 ******************/
$orderby = 'id'; // 默认排序字段
$orderway = 'desc'; // 默认排序方式
$odby = I('get.odby');
if($odby && in_array($odby, array('id_asc','id_desc','price_asc','price_desc')))
{
if($odby == 'id_asc')
$orderway = 'asc';
elseif ($odby == 'price_asc')
{
$orderby = 'price';
$orderway = 'asc';
}
elseif ($odby == 'price_desc')
$orderby = 'price';
}
/************ 翻页 *************/
// 总的记录数
$count = $this->where($where)->count();
// 生成翻页对象
$page = new \Think\Page($count, 10);
$page->setConfig('next', '下一页');
$page->setConfig('prev', '上一页');
// 获取翻页字符串
$pageString = $page->show();
// 取出当前页的数据
$data = $this->where($where)->limit($page->firstRow.','.$page->listRows)->order("$orderby $orderway")->select();
//echo $this->getLastSql();
return array(
'page' => $pageString,
'data' => $data,
);
}
// 在控制器中调用delete方法之前会自动调用
protected function _before_delete($option)
{
// 先根据商品的ID取出这件商品的图片的路径
$logo = $this->field('logo,sm_logo')->find($option['where']['id']);
// 从配置文件取出图片所在目录
$rp = C('IMG_rootPath');
// 删除图片
unlink($rp . $logo['logo']);
unlink($rp . $logo['sm_logo']);
}
}
在师徒模板中,可以不需要使用tp标签输出变量,循环,判断,直接用php自身的
<?php foreach($data as $k=>$v): ?>
<?php endforeach; ?>
<?php if(): ?>
<?php endif; ?>
注意
我们在写其他控制器的CRUD时,都可以按照这种方式来做,提醒一下,向上传文件显示图片的代码,我们可以封装到Common/Common/function.php,然后可以直接调用使用