首页 » PHP » 正文

thinkphp5学习笔记(9)

(8)模型输出

以 User 模型为例,模型定义如下:

<?php
namespace app\index\model;
use think\Model;
class User extends Model
{
}

输出数组
可以使用 toArray 方法把当前的模型对象输出为数组。
修改 User 控制器的 read 操作方法如下:

// 读取用户数据并输出数组
public function read($id = '')
{
$user = UserModel::get($id);
dump($user->toArray());
}

访问 http://tp5.com/user/20 页面输出结果为:

array (size=7)
'id' => int 20
'nickname' => string '张三' (length=6)
'email' => string 'zhanghsan@qq.com' (length=16)
'birthday' => string '1988/01/15' (length=10)
'status' => string '待审核' (length=9)
'create_time' => string '2016-05-02 16:40:57' (length=19)
'update_time' => string '2016-05-02 16:40:57' (length=19)

可以看到,User模型的数据已经经过了读取器方法处理。

隐藏属性

如果输出的时候需要隐藏某些属性,可以使用:

// 读取用户数据并输出数组
public function read($id = '')
{
$user = UserModel::get($id);
dump($user->hidden(['create_time','update_time'])->toArray());
}

指定属性
或者指定一些属性输出,则可以用:

// 读取用户数据并输出数组
public function read($id = '')
{
$user = UserModel::get($id);
dump($user->visible(['id','nickname','email'])->toArray());
}

追加属性
如果读取器定义了一些非数据库字段的读取,例如:

<?php
namespace app\index\model;
use think\Model;
class User extends Model
{
// status修改器
protected function getUserStatusAttr($value)
{
$status = [-1 => '删除', 0 => '禁用', 1 => '正常', 2 => '待审核'];
return $status[$value];
}
}

而我们如果需要输出 user_status 属性数据的话,可以使用 append 方法,用法如下:

// 读取用户数据并输出数组
public function read($id = '')
{
$user = UserModel::get($id);
dump($user->append(['user_status'])->toArray());
}

输出JSON
对于 API 开发而言,经常需要返回 JSON 格式的数据,修改 read 操作方法改成 JSON 输出:

// 读取用户数据输出JSON
public function read($id = '')
{
$user = UserModel::get($id);
echo $user->toJson();
}

或者采用更简单的方法输出 JSON ,下面的方式是等效的:

// 读取用户数据直接输出JSON
public function read($id = '')
{
echo UserModel::get($id);
}
toJson输出方法仍然支持 hidden 、 visible 和 append 方法。

—————————————————————
视图和模板

模板输出
首先来看如何输出一个数据集,我们修改 User 控制器的 index 方法如下:

<?php
namespace app\index\controller;
use app\index\model\User as UserModel;
use think\Controller;
class User extends Controller
{
// 获取用户数据列表并输出
public function index()
{
$list = UserModel::all();
$this->assign('list', $list);
$this->assign('count', count($list));
return $this->fetch();
}
}

1
2

这里用到的其中两个方法 assign 和 fetch ,也是最常用的两个方法。
assign 方法可以把任何类型的变量赋值给模板,关键在于模板中如何输出,不同的变量类型需要采用不同
的标签输出。
前面我们已经学习过, fetch 方法默认渲染输出的模板文件应该是当前控制器和操作对应的模板,也就是:
application/index/view/user/index.html

接下来,定义视图文件的内容,采用 volist 标签输出数据集:

<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>查看用户列表</title>
<style>
body{
color: #333;
font: 16px Verdana, "Helvetica Neue", helvetica, Arial, 'Microsoft YaHei', sans-ser
if;
margin: 0px;
padding: 20px;
}
a{
color: #868686;
cursor: pointer;
}
a:hover{
text-decoration: underline;
}
h2{
color: #4288ce;
font-weight: 400;
padding: 6px 0;
margin: 6px 0 0;
font-size: 28px;
border-bottom: 1px solid #eee;
}
div{
margin:8px;
}
.info{
padding: 12px 0;
border-bottom: 1px solid #eee;
}
.copyright{
margin-top: 24px;
padding: 12px 0;
border-top: 1px solid #eee;
}
</style>
</head>
<body>
<h2>用户列表({$count})</h2>
{volist name="list" id="user" }
<div class="info">
ID:{$user.id}<br/>
昵称:{$user.nickname}<br/>
邮箱:{$user.email}<br/>
生日:{$user.birthday}<br/>
</div>
{/volist}
<div class="copyright">
<a title="官方网站" href="http://www.thinkphp.cn">ThinkPHP</a>
<span>V5</span>
<span>{ 十年磨一剑-为API开发设计的高性能框架 }</span>
</div>
</body>
</html>

ThinkPHP5.0 默认使用的是一个内置的编译型模板引擎,包含了一系列的模板标签,我们会陆续介绍一些
常用的标签用法。
index方法给模板赋值了两个变量 count 和 list ,分别是标量和二维数组,标量的输出很简单,使用:
{$count} 便可,一看就明白。
二维数组通常使用 volist 标签输出。

{volist name="list" id="user"}
ID:{$user.id}<br/>
昵称:{$user.nickname}<br/>
邮箱:{$user.email}<br/>
生日:{$user.birthday}<br/>
------------------------<br/>
{/volist}

volist 标签的 name 属性就是模板变量的名称, id 属性则是定义每次循环输出的变量,在volist标签中间
使用 {$user.id} 表示输出当前用户的id属性,以此类推下面的内容则依次输出用户的相关属性。

ID:{$user.id}<br/>
昵称:{$user.nickname}<br/>
邮箱:{$user.email}<br/>
生日:{$user.birthday}<br/>

分页输出
可以很简单的输出用户的分页数据,控制器 index 方法修改为:

// 获取用户数据列表
public function index()
{
// 分页输出列表 每页显示3条数据
$list = UserModel::paginate(3);
$this->assign('list',$list);
return $this->fetch();
}

模板文件修改为:

<link rel="stylesheet" href="/static/bootstrap/css/bootstrap.min.css" />
<h2>用户列表({$list->total()})</h2>
{volist name="list" id="user"}
ID:{$user.id}<br/>
昵称:{$user.nickname}<br/>
邮箱:{$user.email}<br/>
生日:{$user.birthday}<br/>
------------------------<br/>
{/volist}
{$list->render()}

公共模板
加上之前定义的创建用户的模板,现在已经有两个模板文件了,为了避免重复定义模板,可以把模板的公共
头部和尾部分离出来,便于维护。
我们把模板文件拆分为三部分:

application/index/view/user/header.html
application/index/view/user/index.html
application/index/view/user/footer.html

header.html 内容为:

<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>查看用户列表</title>
<style>
body{
color: #333;
font: 16px Verdana, "Helvetica Neue", helvetica, Arial, 'Microsoft YaHei', sans-ser
if;
margin: 0px;
padding: 20px;
}
a{
color: #868686;
cursor: pointer;
}
a:hover{
text-decoration: underline;
}
h2{
color: #4288ce;
font-weight: 400;
padding: 6px 0;
margin: 6px 0 0;
font-size: 28px;
border-bottom: 1px solid #eee;
}
div{
margin:8px;
}
.info{
padding: 12px 0;
border-bottom: 1px solid #eee;
}
.copyright{
margin-top: 24px;
padding: 12px 0;
border-top: 1px solid #eee;
}
</style>
</head>
<body>

footer.html 内容为:

<div class="copyright">
<a title="官方网站" href="http://www.thinkphp.cn">ThinkPHP</a>
<span>V5</span>
<span>{ 十年磨一剑-为API开发设计的高性能框架 }</span>
</div>
</body>
</html>

index.html 内容为:

{include file="user/header" /}
<h2>用户列表({$count})</h2>
{volist name="list" id="user" }
<div class="info">
ID:{$user.id}<br/>
昵称:{$user.nickname}<br/>
邮箱:{$user.email}<br/>
生日:{$user.birthday}<br/>
</div>
{/volist}
{include file="user/footer" /}

公共头部模板文件中可能存在一些变量,例如这里的页面标题不同的页面会有不同,可以使用

{include file="user/header" title="查看用户列表" /}

然后把头部模板文件中的

<title>查看用户列表</title>

改为:

<title>[title]</title>

如果需要传递多个变量,则使用多个属性即可,例如:

{include file="user/header" title="查看用户列表" keywords="thinkphp" /}

也可以支持传递动态变量的方式,例如:

{include file="user/header" title="$title" /}

模板定位

fetch 方法的第一个参数表示渲染的模板文件或者模板表达式。
通常我们都是使用的模板表达式,而不需要使用完整的文件名。
模板文件名可以随意命名,如果把 index.html 文件改成:
application/index/view/user/list.html
index操作方法中的fetch方法需要改成:
return $this->fetch(‘list’);

而如果fetch方法改成:
return $this->fetch(‘index/list’);
那么实际渲染的模板文件则是
application/index/view/index/list.html
当然,你可以设置更多的目录级别,例如:
return $this->fetch(‘one/two/three/list’);
那么实际渲染的模板文件则是
application/index/view/one/two/three/list.html
有一些和模板定位相关的设置参数能够帮助你调整模板文件的位置和名称。
通常来说,模板相关的参数可以直接在配置文件中配置 template 参数,默认的配置如下:

'template' => [
// 模板引擎类型 支持 php think 支持扩展
'type' => 'Think',
// 模板路径
'view_path' => '',
// 模板后缀
'view_suffix' => '.html',
// 模板文件名分隔符
'view_depr' => DS,
// 模板引擎普通标签开始标记
'tpl_begin' => '{',
// 模板引擎普通标签结束标记
'tpl_end' => '}',
// 标签库标签开始标记
'taglib_begin' => '{',
// 标签库标签结束标记
'taglib_end' => '}',
],

view_path 参数决定了你的模板文件的根目录,如果没有设置的话系统会默认使用当前模块的视图目录
view 。

如果希望自定义模板文件的位置、命名和后缀,可以对模板参数稍加修改如下:

'template' => [
// 模板引擎类型 支持 php think 支持扩展
'type' => 'Think',
// 模板路径
'view_path' => '../template/index/',
// 模板后缀
'view_suffix' => '.tpl',
// 模板文件名分隔符
'view_depr' => '_',
],

通过配置我们把当前渲染的模板文件移动到了
ROOT_PATH/template/index/user_index.tpl

模板布局
现在使用模板布局来进一步简化模板定义。
首先需要定义一个布局模板文件,放到 application/index/view/layout.html 内容如下:

{include file="user/header" /}
{__CONTENT__}
{include file="user/footer" /}

application/index/view/user/index.html 改成:

{layout name="layout" /}
<h2>用户列表({$count})</h2>
{volist name="list" id="user" }
<div class="info">
ID:{$user.id}<br/>
昵称:{$user.nickname}<br/>
邮箱:{$user.email}<br/>
生日:{$user.birthday}<br/>
</div>
{/volist}

在index模板文件中开头定义 layout 标签 ,表示当前模板使用了布局,布局模板文件为 layout.html ,
布局模板中的 {__CONTENT__} 会自动替换为解析后的index.html内容。
如果你的布局模板中不是使用 {__CONTENT__} 的话,可以改成:

{layout name="layout/newlayout" replace="[__REPLACE__]" /}

那么回自动读取模板文件
application/index/view/layout/newlayout.html ,内容如下:

{include file="user/header" /}
[__REPLACE__]
{include file="user/footer" /}

如果你所有的模板文件都统一使用布局,并且都是有同一个布局模板,那么可以统一配置而不需要在模板文
件中使用 layout 标签定义。
在应用配置或者模块配置中添加如下设置参数:

'template' => [
'layout_on' => true,
'layout_name' => 'layout',
'layout_item' => '[__REPLACE__]'
]

模板文件中只需要定义如下:

<h2>用户列表({$count})</h2>
{volist name="list" id="user" mod="2" }
<div class="info">
ID:{$user.id}<br/>
昵称:{$user.nickname}<br/>
邮箱:{$user.email}<br/>
生日:{$user.birthday}<br/>
</div>
{/volist}

如果想动态控制模板文件使用布局,则可以在控制器中使用:

// 获取用户数据列表
public function index()
{
$list = UserModel::all();
$this->assign('list', $list);
$this->assign('count', count($list));
// 动态使用布局
$this->view->engine->layout('layout','[__REPLACE__]');
return $this->fetch();
}
注意:这里调用的是 this->view->engine 对象的 layout 方法,并不是所有的模板引擎都支持布局
功能,如果你使用的是其它的模板引擎,可能不提供 layout 方法。

如果使用配置方式开启了布局模板,也可以使用该方法临时关闭布局,例如:

// 获取用户数据列表
public function index()
{
$list = UserModel::all();
$this->assign('list', $list);
$this->assign('count', count($list));
// 临时关闭布局
$this->view->engine->layout(false);
return $this->fetch();
}

或者直接在模板文件的开头加上 {__NOLAYOUT__} 标签:

{__NOLAYOUT__}
<h2>用户列表({$count})</h2>
{volist name="list" id="user" mod="2" }
<div class="info">
ID:{$user.id}<br/>
昵称:{$user.nickname}<br/>
邮箱:{$user.email}<br/>
生日:{$user.birthday}<br/>
</div>
{/volist}

标签定制
可以设置模板标签的定界符:

'template' => [
// 模板引擎类型 支持 php think 支持扩展
'type' => 'Think',
// 模板路径
'view_path' => '../template/index/',
// 模板后缀
'view_suffix' => '.tpl',
// 模板文件名分隔符
'view_depr' => '_',
// 模板引擎普通标签开始标记
'tpl_begin' => '{',
// 模板引擎普通标签结束标记
'tpl_end' => '}',
// 标签库标签开始标记
'taglib_begin' => '<',
// 标签库标签结束标记
'taglib_end' => '>',
],

并且修改 index.html 模板中的标签修改如下:

<h2>用户列表({$count})</h2>
<div class="info">
<volist name="list" id="user" >
ID:{$user.id}<br/>
昵称:{$user.nickname}<br/>
邮箱:{$user.email}<br/>
生日:{$user.birthday}<br/>
</volist>
</div>

输出替换
为了更加清晰,需要把资源文件独立出来,并在模板文件中引入,例如增加
public/static/common.css 文件:

body{
color: #333;
font: 16px Verdana, "Helvetica Neue", helvetica, Arial, 'Microsoft YaHei', sans-ser
if;
margin: 0px;
padding: 20px;
}
a{
color: #868686;
cursor: pointer;
}
a:hover{
text-decoration: underline;
}
h2{
color: #4288ce;
font-weight: 400;
padding: 6px 0;
margin: 6px 0 0;
font-size: 28px;
border-bottom: 1px solid #eee;
}
div{
margin:8px;
}
.info{
padding: 12px 0;
border-bottom: 1px solid #eee;
}
.copyright{
margin-top: 24px;
padding: 12px 0;
border-top: 1px solid #eee;
}

我们在header.html文件中引入资源文件

<html>
<head>
<meta charset="UTF-8">
<title>[title]</title>
<link charset="utf-8" rel="stylesheet" href="/static/common.css">
</head>
<body>

但这样有一个问题,如果部署的目录变化的话,资源文件的路径就会跟着变化,这里我们采用输出替换功
能,使得资源文件的引入动态化
可以在输出之前对解析后的内容进行替换,使用:

// 读取用户数据
public function read($id='')
{
$user = UserModel::get($id);
$this->assign('user',$user);
$this->view->replace([
'__PUBLIC__' => '/static',
]);
return $this->fetch();
}

模板文件改为:

<html>
<head>
<meta charset="UTF-8">
<title>[title]</title>
<link charset="utf-8" rel="stylesheet" href="__PUBLIC__/common.css">
</head>
<body>

最终输出的时候,会自动进行 __PUBLIC__ 替换。

渲染内容
有时候,并不需要模板文件,而是直接渲染内容或者读取数据库中存储的内容,控制器方法修改如下:

<?php
namespace app\index\controller;
use app\index\model\User as UserModel;
use think\Controller;
class User extends Controller
{
// 获取用户数据列表并输出
public function index()
{
$list = UserModel::all();
$this->assign('list', $list);
$this->assign('count', count($list));
// 关闭布局
$this->view->engine->layout(false);
$content = <<<EOT
<style>
body{
color: #333;
font: 16px Verdana, "Helvetica Neue", helvetica, Arial, 'Microsoft YaHei', sans-ser
if;
margin: 0px;
padding: 20px;
}
a{
color: #868686;
cursor: pointer;
}
a:hover{
text-decoration: underline;
}
h2{
color: #4288ce;
font-weight: 400;
padding: 6px 0;
margin: 6px 0 0;
font-size: 28px;
border-bottom: 1px solid #eee;
}
div{
margin:8px;
}
.info{
padding: 12px 0;
border-bottom: 1px solid #eee;
}
.copyright{
margin-top: 24px;
padding: 12px 0;
border-top: 1px solid #eee;
}
</style>
<h2>用户列表({\$count})</h2>
<div>
{volist name="list" id="user" }
ID:{\$user.id}<br/>
昵称:{\$user.nickname}<br/>
邮箱:{\$user.email}<br/>
生日:{\$user.birthday}<br/>
------------------------<br/>
{/volist}
</div>
<div class="copyright">
<a title="官方网站" href="http://www.thinkphp.cn">ThinkPHP</a>
<span>V5</span>
<span>{ 十年磨一剑-为API开发设计的高性能框架 }</span>
</div>
EOT;
return $this->display($content);
}
}

display 方法用于渲染内容而不是模板文件输出,和直接使用 echo 输出的区别是 display 方法输出的
内容支持模板标签的解析。

助手函数
可以使用系统提供的助手函数view简化模板渲染输出(注意不适用于内容渲染输出):
前面的模板渲染代码可以改为:

<?php
namespace app\index\controller;
use app\index\model\User as UserModel;
class User
{
// 读取用户数据
public function read($id='')
{
$user = UserModel::get($id);
return view('', ['user' => $user], ['__PUBLIC__' => '/static']);
}
}
使用 view 助手函数,不需要继承 think\Controller 类。该方法的第一个参数就是渲染的模板表达
式。
博主的文章或程序如果给您带来了价值,感谢您打赏一二
微信扫码支付 支付宝扫码支付

发表评论