在之前的文章,已经实现了注册登录的功能,主要熟悉TP与HTML、JS交互,数据库的基本操作等。接下来就要登录到主页,熟悉一下列表的处理,以及数据库多表联查操作。为了简化模型,列表的字段仅有文章标题、简介、内容、封面图片、作者字段。
Session保持,从登录到主页
要想实现上述的功能,就需要先进入到首页,这里设计的是用户必须先登录才能进入到首页,因此需要使用Session来记录登录的状态。在TP中,使用Session格外简单。
创建一个session
session('name','value');
删除一个session
session('name',null);
删除所有session
session(null);
以上仅是最基本的使用方法,还有其他的一些用法可以查看文档。
所以,需要在登录成功时,把session创建好,进入主页后检查session是否存在,存在则继续,不存在就返回到登录。修改login方法:
public function login() {
//HTTP协议,传输json需要添加请求头
header('Content-Type:application/json; charset=utf-8');
...//校验
session('username', $user_name);
$return['code'] = 1;
$return['message'] = '登录成功';
echo json_encode($return);
}
然后在index.html里点击登录按钮时,加入以下跳转语句:
window.location.href = "{:U('Index/home')}";
为了测试这一点,先写一个简单的主页,仅仅输出一句话。然后创建home方法:
public function home() {
$username = session('username');
if (empty($username)) {
$this->redirect('Index/index');
} else {
$this->display();
}
}
这段逻辑是如果session为空,就跳转到登录页面,成功获取到session时才显示主页。跳转要用重定向redirect
方法。
以上便实现了携带登录信息并跳转到主页的功能了,然而有一个细节问题是,当用户点击浏览器的返回按钮时,页面又回退到了之前的登录页面,很显然这不是我们希望的行为。我们希望用户点返回按钮时,如果已经登录了,依然停在主页。一般的做法是:进入登录页时请求数据,如果是已登录状态,就跳转到主页,这样点击返回按钮时,返回到了登录页,登录页又重新跳转到了主页,便实现了我们需要的功能。代码比较简单,节约篇幅就不粘贴了,可以在文末链接查看。
创建文章数据表,初始化一些测试数据
在数据库中加入以下这张表:
create table if not exists article(
id int unsigned auto_increment,
title varchar(50) not null,
descript text not null,
content text not null,
image_path varchar(100) not null,
author_id int unsigned not null,
create_time int unsigned not null default 0,
primary key (id)
)engine=InnoDB default charset=utf8;
其中author_id
对应的是User表中对应作者的id。然后在项目的根目录创建一个upload文件夹,因为是练手,所以图片都直接放在项目里了,实际中当项目比较大时,文件都是专门放在另外的服务器的。然后找几张图片,命名后放在以下路径:
接下来在数据库中插入几条数据,其中图片的路径写相对于根目录的路径,也就是/upload/home/image/xxx.jpg
。示例如下:
insert into article (title,descript,content,image_path,author_id,create_time)
values ('重磅消息1','Python超过Java了1','Python超过Java了,在Github上排名第二,Java屈居第三。1','/upload/home/image/article1.jpg',1,0);
多表联查,显示在主页
如文章一开始所言,在页面上展示列表需要的字段有:文章标题、简介、封面图和作者信息。前几个字段都在article
这张表中,而作者的信息是通过author_id
字段关联到user
表中的,所以想要获取作者的信息,就涉及到了联查。在MySQL中,使用join
关键字进行联查。规则为:
... FROM table1 INNER|LEFT|RIGHT JOIN table2 ON condition
其中INNER表示取得两个表中存在连接匹配关系的记录,LEFT表示取得左表(table1)完全记录,即使右表(table2)并无对应匹配记录,RIGHT表示取得右表(table2)完全记录,即使左表(table1)并无匹配对应记录。
文字表述很是生硬,下面看如何利用这个规则来查询出我们需要的数据,因为article表和user表对我们一样重要,所以应该使用INNER模式:
select
article.title,
article.descript,
article.content,
article.image_path,
user.user_name
from
article
inner join
user
on
article.author_id=user.id;
以上语句就表示,找到一条article
记录,根据它的author_id
找到一条user
记录,如果这个条件成立,就把它的结果合并成一条数据返回,数据只取我们select
的字段。把数据库中所有的数据都找完之后就返回了一个列表,这个列表就是我们需要的。除此以外,如果两个表中有重复的字段时,还可以使用别名来区分,如这条语句使用别名就表示为:
select
a.title title,
a.descript descript,
a.content content,
a.image_path image_path,
u.user_name user_name
from
article a
inner join
user u
on
a.author_id=u.id;
也就是给article
起别名为a
,给user
起别名为u
,并给每个字段都起了别名,这样,如果a
和u
中如果有相同的字段,可以通过不同的命名使返回结果符合预期。
以上是用MySQL命令行实现的查询,那么用TP该怎么写呢?首先别名使用alias
方法,限定要查询的字段使用field
,join则有对应的方法,名称也为join
。所以以上语句使用TP的连贯操作如下:
$Article = M('Article');
$res = $Article
->alias('a')
->field('a.title title,a.descript descript,a.content content,a.image_path image_path,u.user_name user_name')
->join('inner join user u on a.author_id=u.id')
->select();
当使用的join为inner
方式时,join方法中的“inner join”可以省略。
获取到数据后,需要把数据渲染到页面上,这里有两种方式可以选择。一种是已经很熟悉的Ajax,还有一种则是在HTML中嵌入php代码。因为更熟悉Ajax,这里先展示Ajax的写法。由于界面是列表,所以<div>
等标签只能动态创建,我们使用jQuery完成这个功能类似如下:
$.each(list,function(index,value,array)){
$('container').append('{这里写要添加的div}');
}
套用一下,这里list就是我们的数组,$.each
是jQuery里的foreach循环的写法,后边的index、value就表示位置和值。append
方法就是往container
中添加组件,把全部代码都写在参数里就好了,这里参数是字符串,所以引用变量要用+
和字符串连接起来。例如:
'<span class="left author">' +
value.user_name +
'</span>'
......
原理就是这样的,要看详细的代码,可以在文末链接找。
接下来实现第二种方案,就是在HTML中嵌入php代码。这种方式,就需要在调用display
方法前,把数据从数据库中查询出来,然后通过assign
方法绑定到页面上,然后在页面里的php代码就可以获取到数据的值。修改home方法:
public function home() {
$username = session('username');
if (empty($username)) {
$this->redirect('Index/index');
} else {
$Article = M('Article');
$res = $Article
->alias('a')
->field('a.title title,a.descript descript,a.content content,a.image_path image_path,u.user_name user_name')
->join('user u on a.author_id=u.id')
->select();
$this->assign('articles', $res);
$this->display();
}
}
以上代码使用assign
把数据绑定到了页面上articles
变量。接下来我们在html中使用这个变量。因为是数组,所以也需要遍历。
<foreach name="articles" item="art">
<div class="wz">
<h3><a href="#" title="{$art.title}">{$art.title}</a></h3>
......
</div>
</foreach>
可以看到,使用也是非常简单,只是使用变量时要使用php的规则,并且用花括号括起来。
在实际中,根据需要两种方式都可以选择,如果是前后端分离,肯定只能用第一种方式了,或者用别的框架实现,但php都只以接口的形式提供数据。
这样一个展示列表的页面就完成了,相关代码已经同步到github。
奉上github地址:https://github.com/LtLei/PHPLearn。