## 数据获取
像一般应用一样,我们首页就是Index/index 方法。
看看代码:
~~~
public function index($page = 1){
$this->lists($page);
$this->display();
}
~~~
怎么这么短,参数绑定了一个分页参数page。
这个Common模块里设置了一下:
`'VAR_PAGE'=>'page',`
因为考虑到默认的p参数可能以后会被占用。page更语义化点。
列表数据的逻辑主要集中在lists方法里。
So,我们来一探它的究竟。
~~~
public function lists($page = 1){
$map = array();
$list_row = I('r', 10);
$postModel = D('Post');
//tag搜索
$tags = I('get.tag');
if($tags){
$ids = $postModel->where(" FIND_IN_SET('{$tags}',tags)")->getField('id', true);
$this->assign('title', "标签 <i>{$tags}</i> 下的文章");
if(!empty($ids))
$map['id'] = array('in',$ids);
}
//关键词搜搜
if(I('get.kw')){
$kw = trim(I('get.kw'));
$map['title'] = array('like',"%{$kw}%");
$like_id = $postModel->where("content LIKE '%{$kw}%' OR description LIKE '%{$kw}%'")->getField('id', true);
if($like_id)
$map['id'] = array('in', $like_id);
}
//区分所有人和本人发布的文章
if( false !== strpos(__SELF__, 'mine') && is_login()){
$map['member_id'] = session('user.uid');
}
//归档搜索
if(isset($_GET['year']) && isset($_GET['month'])){
$year = CONTROLLER_NAME;
$month = ACTION_NAME;
$map['_string'] = "`deadline` LIKE binary('{$year}-{$month}%')";
}
$map['deadline'] = array('elt', datetime());
$this->assign('list', $postModel->where($map)->page($page, $list_row)->order('`deadline` DESC')->select());
/* 分页 */
$total = $postModel->where($map)->count();
$page = new \Think\Page($total, $list_row);
$page->rollPage = 5;
$page->setConfig('prev','上一页');
$page->setConfig('next','下一页');
$page->setConfig('theme','<div class="pager">%UP_PAGE% %DOWN_PAGE%</div>');
$p = $page->show();
$this->assign('_page', $p? $p: '');
//tag列表
$this->assign('tags', M('Tags')->order('count DESC')->select());
//获取归档
$list = $postModel->where($map)->order('`deadline` DESC,`id` DESC')->select();
$date = $time = array();
foreach ($list as $key => $value) {
if($value['deadline'])
$time[] = date('F Y', strtotime($value['deadline']));
}
$time = array_unique($time);
foreach ($time as $key => $value) {
$date[] = array(
'text'=> $value,
'link'=> date('Y/m', strtotime($value))
);
}
$this->assign('archive', $date);
}
~~~
~~~
$map = array();
$list_row = I('r', 10);
$postModel = D('Post');
~~~
先定义一个查询用的map数组变量。
并且每页展示数量获取r get或post参数。并且默认值为10。先这样写,支持以后通过传参控制每页显示多少篇文章。
定义一个变量存储实例化Post的模型。
然后就开始查数据并赋值模板变量$list:
~~~
$map['deadline'] = array('elt', datetime());
$this->assign('list', $postModel->where($map)->page($page, $list_row)->order('`deadline` DESC')->select());
~~~
默认查询是发布文章截止发布日期时间过后,也就是当前时间大于截止发布时间的文章。
然后用了查询里的page 方法传 $page 页数和 $list_row 每页数量 并按发布截止时间降序 分页后查询。
这里用了一个技巧,直接赋值 而不是先定义一个变量等于查询结果。多一个变量就多占一部分内存,而且这个变量后面我们不会再操作和用到。
而且$postModel 因为后面要用到。所以我们用变量缓存Post 模型实例。并且,因为我们查询需要用到Post模型的类方法,所以用D。如果只是简单查询,最好还是用M函数。
主要列表数据查完后,就是分页和其他额外数据查询。
分页后面会讲。
额外数据标签查询。
也是一句话:
~~~
//tag列表
$this->assign('tags', M('Tags')->order('count DESC')->select());
~~~
然后我们看下index模板,
~~~
<extend name="Index/base" />
<block name="header">
<div class="blog-header">
<h4>{$title|default=""}</h4>
</div>
</block>
<block name="main">
<volist name="list" id="post" key="post_k">
<assign name="tpl" value="$post.type"/>
<switch name="tpl">
<case value="text"><include file="Index/text" /></case>
<case value="picture"><include file="Index/picture" /></case>
<case value="music"><include file="Index/music" /></case>
<case value="video"><include file="Index/video" /></case>
</switch>
</volist>
<empty name="list">
<div class="text-center">
<img src="__IMG__/logo-grey.png" alt="" width="135">
<br><br>
对不起,没有相应的文章
</div>
</empty>
{$_page}
</block>
<block name="sidebar">
<include file="Index/post_btn" />
<div class="sidebar-module sidebar-module-inset">
<h4>热门标签</h4>
<ul class="list-unstyled side-tracked-tag">
<volist name="tags" id="tag">
<li>
<a class="followed-tag clearfix" href="{:U('/')}?tag={$tag['title']}">
<span class="glyphicon glyphicon-tag" aria-hidden="true"></span>
<span class="">{$tag.title}</span>
</a>
</li>
</volist>
</ul>
</div>
<div class="sidebar-module">
<h4>归档</h4>
<ol class="list-unstyled">
<volist name="archive" id="vo">
<li><a href="{:U($vo['link'])}">{$vo.text}</a></li>
</volist>
</ol>
</div>
</block>
<block name="script">
<script type="text/javascript" src="__BOWER__/audiojs/audiojs/audio.min.js"></script>
<script src="__STATIC__/swipebox/js/jquery.swipebox.js"></script>
<link rel="stylesheet" href="__STATIC__/swipebox/css/swipebox.css">
<script type="text/javascript">
$(function(){
var single = audiojs;
single.events.ready(function() {
var a1 = single.createAll('', $('.single audio'));
});
//图片灯箱
$( '.swipebox' ).swipebox();
})
</script>
</block>
~~~
继承Index/base 父模板,header block部分提供一个默认为空的标题。
~~~
<block name="header">
<div class="blog-header">
<h4>{$title|default=""}</h4>
</div>
</block>
~~~
然后 main block是列表显示。
~~~
<block name="main">
<volist name="list" id="post" key="post_k">
<assign name="tpl" value="$post.type"/>
<switch name="tpl">
<case value="text"><include file="Index/text" /></case>
<case value="picture"><include file="Index/picture" /></case>
<case value="music"><include file="Index/music" /></case>
<case value="video"><include file="Index/video" /></case>
</switch>
</volist>
<empty name="list">
<div class="text-center">
<img src="__IMG__/logo-grey.png" alt="" width="135">
<br><br>
对不起,没有相应的文章
</div>
</empty>
{$_page}
</block>
~~~
逻辑就是 遍历 list变量,然后 通过assign 模板标签临时赋值tpl为文章类型,本来想通过这个类型动态include的模板的,结果发现不行。include 标签的file属性不支持动态变量。
如果你想动态加载的模板个数有限, 就像我这样switch 后 case里include写死的模板吧。
然后还通过empty 标签 考虑了没数据list的样式。
可爱的小鹿:
![2015-06-30/5592afd665aa8](http://box.kancloud.cn/2015-06-30_5592afd665aa8.png)
这也是搜索不到数据的呈现。
各个文章类型的,前面讲发布时顺带说过部分代码,
现在只说明一个类型文本。
~~~
<div class="blog-post text">
<present name="post.title"><h2 class="blog-post-title">{$post.title}</h2></present>
<p class="blog-post-meta">{$post.update_at|friendly_datetime} by <a href="#">{$post.author}</a></p>
<section class="blog-post-content">
{$post.content|htmlspecialchars_decode}
</section>
<section>
<neq name="Think.const.CONTROLLER_NAME" value="Post">
<a href="{:U('/Post/'.$post['id'])}" class="more" target="_blank">未完,继续阅读→</a>
<?php if (is_login() && is_login() == $post['member_id']): ?>
<a href="/api.php/post?id={$post.id}" class="ajax-delete confirm">删除</a>
<?php endif ?>
<br>
<br>
</neq>
{$post.tags|get_tag}
</section>
</div>
~~~
基本容器都会带上各自类型的类名,如文本就是text,以此类推。
然后就是 更新时间,已经发布者昵称加空间链接。然后就是内容显示,有的类型是描述字段,注意最新版tp,i函数默认用htmlspecialchars过滤了 读出来必须htmlspecialchars_decode。否则看到的是html标签。
如这样:
![2015-06-30/5592b1c024d5f](http://box.kancloud.cn/2015-06-30_5592b1c024d5f.png)
接下来就是空间文章的权限操作显示,并且在详情页时没有这块的显示。
通过neq 标签+控制器常量区分
`<neq name="Think.const.CONTROLLER_NAME" value="Post"`
然后里面比详情页就多了 “查看更多” 、“删除”链接。
然后是标签显示:
`{$post.tags|get_tag} `
get_tag函数也简单:
~~~
/**
* 获取标签的显示
*/
function get_tag($tags, $link = true){
if($link && $tags){
$tags = explode(',', $tags);
$link = array();
foreach ($tags as $value) {
$link[] = '<a href="'. U('/') . '?tag='.$value.'"><span class="label label-info">' . $value . '</span></a>';
}
return join($link,' ');
}else{
return $tags? $tags : '';
}
}
~~~
需要生成带链接标签时,分割,然后拼上url参数后join 空格。如果不要url就直接返回字段。
- 序
- 前言
- 内容简介
- 目录
- 基础知识
- 起步
- 控制器
- 模型
- 模板
- 命名空间
- 进阶知识
- 路由
- 配置
- 缓存
- 权限
- 扩展
- 国际化
- 安全
- 单元测试
- 拿来主义
- 调试方法
- 调试的步骤
- 调试工具
- 显示trace信息
- 开启调试和关闭调试的区别
- netbeans+xdebug
- Socketlog
- PHP常见错误
- 小黄鸭调试法,每个程序员都要知道的
- 应用场景
- 第三方登录
- 图片处理
- 博客
- SAE
- REST实践
- Cli
- ajax分页
- barcode条形码
- excel
- 发邮件
- 汉字转全拼和首字母,支持带声调
- 中文分词
- 浏览器useragent解析
- freelog项目实战
- 需求分析
- 数据库设计
- 编码实践
- 前端实现
- rest接口
- 文章发布
- 文件上传
- 视频播放
- 音乐播放
- 图片幻灯片展示
- 注册和登录
- 个人资料更新
- 第三方登录的使用
- 后台
- 微信的开发
- 首页及个人主页
- 列表
- 归档
- 搜索
- 分页
- 总结经验
- 自我提升
- 进行小项目的锻炼
- 对现有轮子的重构和移植
- 写技术博客
- 制作视频教程
- 学习PHP的知识和新特性
- 和同行直接沟通、交流
- 学好英语,走向国际
- 如何参与
- 浏览官网和极思维还有看云
- 回答ThinkPHP新手的问题
- 尝试发现ThinkPHP的bug,告诉官方人员或者push request
- 开发能提高效率的ThinkPHP工具
- 尝试翻译官方文档
- 帮新手入门
- 创造基于ThinkPHP的产品,进行连带推广
- 展望未来
- OneThink
- ThinkPHP4
- 附录