【ThinkPHP5】 学习笔记-转载
project 应用部署目录 ├─application 应用目录(可设置) │ ├─common 公共模块目录(可更改),不肯直接通过浏览器访问,详细办法请通过继承或者其他。 │ ├─index 模块目录(可更改) │ │ ├─config.php 模块配置文件 │ │ ├─common.php 模块函数文件 │ │ ├─controller 控制器目录 │ │ ├─model 模型目录 │ │ ├─view 视图目录 │ │ └─ ... 更多类库目录 │ ├─command.php 命令行工具配置文件 │ ├─common.php 应用公共(函数)文件 │ ├─config.php 应用(公共)配置文件 │ ├─database.php 数据库配置文件,可设置本项目的数据库情况。 │ ├─tags.php 应用行为扩展定义文件,相当于钩子。对框架进行拓展。改变框架执行流程。 │ └─route.php 路由配置文件,配置这个选项可以美化URL ├─extend 扩展类库目录(可定义),下载第三方的库使用的。不包含composer ├─public WEB 部署目录(对外访问目录) │ ├─static 静态资源存放目录(css,js,image) │ ├─index.php 应用入口文件 │ ├─router.php 快速测试文件,可以用来在没安装apache的时候启动框架的web服务器。 │ └─.htaccess 用于 apache 的重写 ├─runtime 应用的运行时目录(可写,可设置)。日志、缓存和编译文件等。 ├─vendor 第三方类库目录(Composer),通过composer安装的文件都会出现在这里。 ├─thinkphp 框架系统目录 │ ├─lang 语言包目录 │ ├─library 框架核心类库目录 │ │ ├─think Think 类库包目录 │ │ └─traits 系统 Traits 目录 │ ├─tpl 系统模板目录 │ ├─.htaccess 用于 apache 的重写 │ ├─.travis.yml CI 定义文件 │ ├─base.php 基础定义文件,定义一些常量。 │ ├─composer.json composer 定义文件 │ ├─console.php 控制台入口文件 │ ├─convention.php 惯例配置文件,框架默认的配置文件 │ ├─helper.php 助手函数文件(可选) │ ├─LICENSE.txt 授权说明文件 │ ├─phpunit.xml 单元测试配置文件 │ ├─README.md README 文件 │ └─start.php 框架引导文件 ├─build.php 自动生成定义文件(参考) ├─composer.json composer 定义文件 ├─LICENSE.txt 授权说明文件 ├─README.md README 文件 ├─think 命令行入口文件
未提及到的个别目录:
public\robots:给搜索引擎使用的,可以设置哪些不给搜索引擎爬取等。比如前台希望能,而后台不希望给搜索引擎看到。配置这个文件即可。
\thinkphp\tpl\default_index.tpl:自动生成的控制器模板文件
\thinkphp\tpl\dispatch_jump.tpl:网站跳转成功或者失败而出现的文件。
\thinkphp\tpl\page_trace.tpl:调试时候显示的模板文件。
\thinkphp\tpl\think_exception.tpl:异常时候的模板文件
application\extend\:放第三方的类库的,如exmail,支付函数等等。
public\static\:拿来放第三方的静态资源的,比如jquery,编辑器等等。
application\admin\extra\:放extend里面的第三方类库对应的配置文件的。
————关于common模块的使用:由于common模块比较特殊,是不能直接访问的。但是common是可以给其他模块调用的。所以采用继承的方式进行使用。
以下为例,在index/Index/user方法使用common\Index控制下的a方法:
<?php namespace app\index\controller; use app\common\controller\Index as commonIndex; //声明使用common\Index控制器,并重命名为commonIndex,这时候其实是个类了。 class Index extends commonIndex //采用继承的方式 { public function user (){ return $this->a(); //请注意:这里是$this,代表的就是extend的commonIndex这个类。 } }
————以上只是一种方法,可以不用继承,而在用的时候先进行实例化,再进行->方法操作即可。效果相同。
TP框架的惯例配置:在ThinkPHP的convention.php里面。
应用配置:
开发中不允许改变框架的任何文件,否则后期升级框架就会非常的麻烦。一旦升级就很多东西都没了。那么如何自定义配置呢?在application中配置config.php即可。
请注意:TP5.0.10的调试模式的开启和关闭是在config.php里面的。而且默认是关闭的。卧槽!
加载模板采用return $this->fetch();如下
<?php namespace app\admin\controller; use think\controller; class Index extends Controller { public function index(){ return $this->fetch(); } }
——请注意:这时候的fetch()是默认加载跟方法同名的index.html模板的,如果你想加载相同控制器下的login模板,直接写return $this->fetch('login');如果你想跨模块调用,可以直接一级级往上改变,比如return $this->fetch('index/index');
关于数据库的设置:
模型层:用来操作数据库的,所以,一个模型文件通常对应一个数据表名字,并且与数据表的名字一致。比如:
这是我的数据表的名字:
这是我的操作的模型层的文件名:(前缀blog_在database.php文件里面设置过了。)
获取input进来的数据:通过input('post.')来获取所有。.后面加参数就是获取某个
个function login() { //测试数据库连接 //$data = db('admin')->where('admin_id',2)->find(); //dump($data); if (request()->isPost()) { //halt($_POST); //将请求交给模型层进行处理。 //$res = (new Admin())->login(input('post.')); dump(input('post.')); } }
get传参的演示:
前端:
<a href="{:url('admin/index/useredit',['admin_id'=>$user.admin_id,])}" class="edit btn btn-primary">编辑</a>
控制器:
$admin_id=input('admin_id',0); dump($admin_id);
ajax异步发数据以及请求:
后台:
if (request()->isPost()){ //通过ajax接收来自前端的admin_id,才能确定要操作的是哪一个。 if(input('admin_id')){ return input('admin_id'); }
前端:
$('.edit').click(function () { adminId = $(this).attr('idx'); $.ajax({ type: "POST", url: "{:url('admin/index/useredit')}", data: { admin_id:adminId, }, dataType: "json", timeout:3000, success: function(data){ if(data){ alert(data); } } }); })
将数据添加/插入数据库:
$data = [ 'admin_username' => input('post.admin_username'), 'admin_password' => md5(input('post.admin_password')), ]; db('admin')->insert($data);
验证器:
这是5.0
推荐的验证方式,为具体的验证场景或者数据表定义好验证器类,直接调用验证类的check
方法即可完成验证,下面是一个例子:
我们定义一个\app\index\validate\User
验证器类用于User
的验证。
前端验证输入:
原先我是用JQ写的,如下:
var adminusername = $('#adminusername').val(); var adminpassword = $('#adminpassword').val(); var captcha = $('#captcha').val(); if(adminusername == '' || adminpassword == ''){ layer.alert('账号或密码不能为空!'); return false; } if(captcha == ''){ layer.alert('请输入验证码!'); return false; }
以下为实例,登录的例子代码:
目录结构如下:
前端登录界面的login.html
<form action="login" method="post"> <h2 class="text-center text-primary">后台管理</h2> <div class="form-group"> <label for="adminusername">账号:</label> <input required type="text" id="adminusername" name="admin_username" class="form-control" placeholder="请输入用户名"> </div> <div class="form-group"> <label for="adminpassword">密码:</label> <input required type="password" id="adminpassword" name="admin_password" class="form-control" placeholder="请输入密码"> </div> <div class="form-group"> <label for="captcha">验证码</label> <input required type="text" id="captcha" name="captcha" class="form-control" placeholder="请输入验证码"> </div> <div><img src="{:captcha_src()}" alt="captcha" onclick="this.src = this.src + '?' + Math.random()"/></div> <div> <input type="submit" class="btn btn-success form-control" value="登录"> </div> <div class="text-center text-info">Copyright Linfeng © 2017 - 2027</div> </form>
控制器Login.php的代码:
<?php namespace app\admin\controller; use think\controller; use app\common\model\Admin; class Login extends Controller { function login() { //测试数据库连接 //$data = db('admin')->where('admin_id',2)->find(); //dump($data); if (request()->isPost()) { //将请求交给模型层进行处理,我们在模型层设置了验证以及返回的错误信息了。 $res = (new Admin())->login(input('post.')); if ($res['valid']){ //说明登录成功 $this->success($res['msg'],'admin/index/index');exit; }else{ //说明登录失败 $this->error($res['msg']);exit; } } //加载模板 return $this->fetch(); } }
模型层common/Admin.php
<?php namespace app\common\model; use think\Loader; use think\Model; class Admin extends Model { protected $pk = 'admin_id';//主键 protected $table = 'blog_admin';//请注意,必须得写完整的表名 /* * 登录 * */ public function login($data) { //1、执行验证(账号密码是否输入、验证码是否输入和正确),放在了validate/Admin.php $validate = Loader::validate('Admin'); if (!$validate->check($data)){ //如果验证不成功,返回错误信息给控制器。 return ['valid' => '0','msg' => $validate->getError()]; } //2、比对用户名和密码是否正确 $userinfo = $this->where('admin_username',$data['admin_username'])->where('admin_password',md5($data['admin_password']))->find(); if (!$userinfo){ //说明在数据库未匹配到该用户 return [ 'valid' => '0', 'msg' => '用户名或者密码错误', ]; } //3、正确,将用户信息存入session中。 session('admin.admin_id',$userinfo['admin_id']); session('admin.admin_username',$userinfo['admin_username']); return [ 'valid' => '1', 'msg' => '登录成功!', ]; } }
验证模块validate\Admin.php
<?php namespace app\admin\validate; use think\Validate; class Admin extends Validate { protected $rule = [ /*以下注释是因为前端做了处理,不然总是因为未输入而跳转,麻烦。*/ /*'admin_username' => 'require', 'admin_password' => 'require', 'captcha' => 'require|captcha',*/ 'captcha' => 'require|captcha', ]; protected $message = [ /*'admin_username.require' => '请输入用户名', 'admin_password.require' => '请输入密码', 'captcha.require' => '请输入验证码',*/ 'captcha.captcha' => '验证码不正确', ]; }
公共层Common.php
<?php namespace app\admin\controller; use think\controller; use think\Request; class Common extends Controller { public function __construct(Request $request = null) { parent::__construct($request); //执行登录验证,以下相当于$_SESSION['admin']['admin_id'],这个写法在TP框架中不能用了。 if (!session('admin.admin_id')) { $this->redirect('admin/login/login'); } } }
关于模型层的举例:
模型:
namespace app\index\model; use think\Model; class User extends Model// { }
控制器里面的调用方式:
namespace app\index\controller; use app\index\model\User;//使用 class Index { public function index() { $user = new User();// } }
请求:可以使用 think\Request,即use think\Request;
$request = Request::instance(); // 获取当前域名 echo 'domain: ' . $request->domain() . '<br/>'; // 获取当前入口文件 echo 'file: ' . $request->baseFile() . '<br/>'; // 获取当前URL地址 不含域名 echo 'url: ' . $request->url() . '<br/>'; // 获取包含域名的完整URL地址 echo 'url with domain: ' . $request->url(true) . '<br/>'; // 获取当前URL地址 不含QUERY_STRING echo 'url without query: ' . $request->baseUrl() . '<br/>'; // 获取URL访问的ROOT地址 echo 'root:' . $request->root() . '<br/>'; // 获取URL访问的ROOT地址 echo 'root with domain: ' . $request->root(true) . '<br/>'; // 获取URL地址中的PATH_INFO信息 echo 'pathinfo: ' . $request->pathinfo() . '<br/>'; // 获取URL地址中的PATH_INFO信息 不含后缀 echo 'pathinfo: ' . $request->path() . '<br/>'; // 获取URL地址中的后缀信息 echo 'ext: ' . $request->ext() . '<br/>';
可以通过Request对象完成全局输入变量的检测,获取和安全过滤,包括$_GET/$_POST等等
验证码:
后面加随机数,是因为每次的src都不一样,就会重新请求验证码类。
<div><img src="{:captcha_src()}" alt="captcha" onclick="this.src = this.src + '?' + Math.random()"></div>
同时,验证码提供了配置项,所以可以直接加在application下的config.php文件里面。
独立验证(专门建验证文件请查看上面的验证)
任何时候,都可以使用Validate
类进行独立的验证操作,例如:
$validate = new Validate([ 'name' => 'require|max:25', 'email' => 'email' ]); $data = [ 'name' => 'thinkphp', 'email' => 'thinkphp@qq.com' ]; if (!$validate->check($data)) { dump($validate->getError()); }
————请注意:上面的例子的$data经常会由其他地方传进来进行验证。如:
public function pass($data) { //1、执行验证 $validate = new Validate( [ //'admin_id' => 'require', 'admin_password' => 'require', 'new_password' => 'require', 'confirm_password' => 'require|confirm:new_password',//本字段与new_password进行比对。 ], [ 'admin_password.require' => '请输入原密码', 'new_password.require' => '请输入新密码', 'confirm_password.require' => '请输入确认密码', 'confirm_password.confirm' => '两次密码必须一致', ] ); if (!$validate->check($data)) { dump($validate->getError()); } //2、原始密码是否正确 //3、修改密码 }
模板继承:
1、在view模块下建立模板base.html,并在其主区域用标签{block name='main'} {/block}包含起来。
2、在view\index\index.html继承base.html,并替换(其实是填充,之前并没有内容){block name='main'} {/block}里面的内容。
————这里我们需要特别注意:需要在base.html上写一个{block name="script"}{/block},继承界面的JS写在这个区域的。如下:上面的JS是公用的,下面的是拿来放每个界面不同的JS的。
函数:在php文件中可以直接使用,在模板中使用需要加冒号:
在模板中使用函数session:得加冒号:如下:
<strong class="font-bold">{:session('admin.admin_username')}</strong>
——上面的session('admin.admin_username')是TP框架定义的session函数。
在模板中生成地址,采用url函数,记得加冒号:
<li><a href="{:url('admin/index/userlist')}">用户列表</a></li>
form表单填写地址,直接填写模块/控制器/方法名:
<form action="{:url('admin/index/useredit')}" method="post">
————当然,action可以不写,会传到页面对应的方法上。{ }其实就是相当于在html界面的<?php ?>而已。
通过ajax传参:
$('.edit').click(function () { adminId = $(this).attr('idx'); $.ajax({ type: "POST", url: "{:url('admin/index/useredit')}", data: { admin_id: adminId, }, dataType: "json", timeout: 3000, success: function () { if (data) { alert(1); } } }); })
volist的应用:
控制器代码:
function userlist(){ $users = db('admin')->select(); //在模板中分配变量 $this->assign('users',$users); return $this->fetch(); }
前端代码:
{volist name="users" id="vo"} <tr> <td>{$vo.admin_id}</td> <td>{$vo.admin_username}</td> <td>{$vo.admin_password}</td> <td><a title="">删除</a></td> </tr> {/volist}
关于TP5中如何让左侧导航栏显示和隐藏的问题:
由于一个函数对应一个html界面,所以,我们可以在函数中直接给模板分配变量。这样就省去了采用cookie等方法记住所点击的界面了。如下:
控制器代码:
function index(){ //分配所在界面,以便于展开导航栏对应的模块。 $this->assign('active_li','index'); //加载模板 return $this->fetch(); }
请注意,我们向外分配的变量为当前的函数名(一个函数对应一个界面),然后展开导航条对应的模块,__FUNCTION__在php中是用于获取当前函数名的。上面可以改成:
function index(){ //分配所在界面的方法,以便于展开导航栏对应的模块。 $this->assign('active_li',__FUNCTION__); //加载模板 return $this->fetch(); }
前端模板代码:
var activeLi = '{$active_li}'; $('.' + activeLi).addClass('active');