thinkphp5.0学习

1、框架概述

1.什么是框架

框架就是一些代码类、方法(函数)、变量、常量的集合,这些代码是功能结构性的代码(并非业务代码)

业务代码其实就是具体的一些模块的增删改查逻辑代码。

使用框架开发项目,有便于代码重用、开发效率高、代码规范好、便于功能扩展等优点。

2.用框架和不用那个效率高?

项目小:原生快。
项目大:框架快(原因是项目太大,那么肯定不会是你单人开发,所以如果没有统一的规范的话,那么每个人的习惯和思维不太一样,比如文件乱放,代码这里丢一坨,哪里丢一坨,会导致很多问题,因为项目大,所以需要复用的地方肯定也比较多,那么此时框架就会提高效率)

3.常用的框架

  • Zend Framework 框架,PHP官方框架。
  • YII框架,又叫易框架
  • Symfony 框架。
  • Laravel框架,市场使用较多。
  • Codelgniter框架,简称CI框架。
  • ThinkPHP框架,简称TP框架,常用版本:3.2.3和 5.0.*版本。

Zend Framework :用的人真的不太多,比较重
YII:国内也还有一部分在用
Symfony:国内几乎没有,国外很多很多,封装思想很好
Laravel:国内用它的也非常多,我也经常用,相当优雅,用过的都说好。
Codelgniter:通常和ThinkPHP3.2作比较,封装的也不是很深,适合入门,还包含很多面向过程的思想,封装了很大一批的函数直接调用的,不是通过对象调用方法的,现在见到的一般就是一些老项目在用了,10-11年是很火的,因为很简单
ThinkPHP:目前好像是到tp6了,它经典的版本应该是3.2.3和5.0系列和5.1系列,到现在的tp6,如果你碰到一些15年左右的项目,很有可能就是tp3.2做的

这些框架大多都基于MVC设计思想和面向对象的

M:模型model,处理业务数据,与数据库做交互。

V:视图view,显示html页面,用户能够看到并与之交互的页面。

C:控制器controller,接收请求,调用模型处理数据,调用视图显示页面。

整个网站应用,分为模型、视图、控制器三大部分组成。

2、框架的下载

1.框架下载

http://www.thinkphp.cn/down/framework.html
#composer 地址
https://packagist.org/packages/topthink/think#v5.0.24

在这里插入图片描述
注意:php版本太高,会报错,各种报错,现在都php8了,建议用tp5.0系列的时候php版本也用php5.4及以上版本

2.配置虚拟主机

<VirtualHost *:80>
	# 设置网站目录
	DocumentRoot "F:\wamp\www\tpshop\public"
	ServerName www.tpshop.com
	# 错误日志
	ErrorLog "F:\wamp\www\tpshop\logs\error.log"
	# 成功日志
	CustomLog "F:\wamp\www\tpshop\logs\access.log" combined
	# 设置目录访问权限
	<Directory "F:\wamp\www\tpshop\public">
	    # 指定目录启用特性
	    Options Indexes FollowSymLinks 
	    # 是否允许使用.htaccess文件
	    AllowOverride All
	    # 访问目录权限 apache2.4
	    Require all granted
		# 默认起始页面
		DirectoryIndex index.php
	</Directory>
</VirtualHost>

因为配置了错误日志,所以需要在项目根目录创建一个logs文件夹,否则无法启动
在这里插入图片描述
域名解析
在这里插入图片描述
成功访问
在这里插入图片描述

3、tp框架基础

1.目录结构

project  应用部署目录
├─application           应用目录(可设置)
│  ├─common             公共模块目录(可更改)
│  ├─index              模块目录(可更改)
│  │  ├─config.php      模块配置文件
│  │  ├─common.php      模块函数文件
│  │  ├─controller      控制器目录
│  │  ├─model           模型目录
│  │  ├─view            视图目录
│  │  └─ ...            更多类库目录
│  ├─command.php        命令行工具配置文件
│  ├─common.php         应用公共(函数)文件
│  ├─config.php         应用(公共)配置文件
│  ├─database.php       数据库配置文件
│  ├─tags.php           应用行为扩展定义文件
│  └─route.php          路由配置文件
├─extend                扩展类库目录(可定义)
├─public                WEB 部署目录(对外访问目录)
│  ├─static             静态资源存放目录(css,js,image)
│  ├─index.php          应用入口文件
│  ├─router.php         快速测试文件
│  └─.htaccess          用于 apache 的重写
├─runtime               应用的运行时目录(可写,可设置)
├─vendor                第三方类库目录(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                 命令行入口文件

extend:拓展目录,可以被自动加载
runtime:访问页面的时候会自动生成出来,很多时候改代码不生效,可能就是这个缓存问题,可以尝试删除该目录,重新访问,其它的记本是每个后面都说的很清楚

最重要的一点就是记住:入口文件在哪里
在这里插入图片描述

注意:下载下来的和这个目录结构是有出入的,比如刚下载的框架
在这里插入图片描述
还有一个注意的点是:每个模块下都有自己的配置文件和函数文件
在这里插入图片描述
注意:这个think文件用来用指令来快速创建目录结构的
在这里插入图片描述

2.配置文件

2.1配置文件的层级

框架主配置文件(惯例配置文件) thinkphp/convention.php

应用公共配置文件 application/config.php, application/database.php 对整个应用生效

模块配置文件 application/模块目录/config.php 对当前模块生效

注意:一般不要去改框架主配置文件,改应用公共配置文件就行了,原因是要升级的时候,直接替换掉thinkphp这个核心目录。

2.1配置文件的其它说明

配置文件格式 return array( 键值对 );
加载顺序: 框架主配置文件 》 应用公共配置文件 》 模块配置文件
配置文件生效顺序: 后加载的生效(后加载的配置项会覆盖之前配置项)

3.函数文件

框架助手函数文件 thinkphp/helper.php

应用公共函数文件 application/common.php

模块函数文件 application/模块目录/common.php

我们知道函数名称重复会报错,自己定义函数的时候我们可以借鉴thinkphp/helper.php里面的写法,定义之前先进行判断
在这里插入图片描述
注意:一般不建议直接修改thinkphp/helper.php

4.开发规范

ThinkPHP5遵循PSR-2命名规范和PSR-4自动加载规范,同时弄了一些自己的一些规范

https://www.kancloud.cn/manual/thinkphp5/118007

在这里插入图片描述
拓展知识:PSR代码规范

https://www.kancloud.cn/thinkphp/php-fig-psr/3139

5.请求的生命周期

框架的生命周期,也就是请求的执行流程

请求开始-》入口文件public/index.php->底层流程start.php->注册自动加载-》注册错误和异常机制-》应用初始化-》URL访问检测-》路由检测-》请求分发-》控制器方法-》

控制器-》模型-》-》返回数据到控制器
控制器-》视图(响应输出)-》结束

4、控制器

1.控制器的后缀

打开配置文件application/config.php,有如下配置

'controller_suffix' => false,

在这里插入图片描述
修改控制器后缀的话

'controller_suffix' => 'Controller',

表示控制器以Controller为后缀。例如Index控制器,文件名为IndexController.php

2.控制器的定义

定义位置及命名规则

定义位置:application/模块目录/controller/目录下

命名规则:控制器名称(首字母大写) + (控制器后缀,默认没有) + .php

默认:Index控制器 Index.php
在这里插入图片描述
我们给它改改,再访问看看
在这里插入图片描述
在这里插入图片描述

示例:我们模仿默认的Index创建一个用户控制器User.php

<?php
//1.引入命名空间
namespace app\index\controller;

//2.引入 基类控制器
use think\Controller;

//定义当前的控制器类,并继承控制器基类(可选)
class User extends Controller
{
    public function index()
    {
        return "我是这个Index模型下的/User控制器下的/index方法";
    }
}

在这里插入图片描述

3.框架中的命名空空间

命名空间本身是PHP就有的,用来防止命名冲突问题的。

TP框架中的命名空间,通常和目录挂钩。

原因:TP中的自动加载机制,会将类的命名空间作为加载路径的一部分。
在这里插入图片描述

如果自己手写过mvc框架,那么这点肯定是可以理解的

TP中命名空间使用:

①声明命名空间 使用namespace关键字

②引入指定的类 使用use关键字 命名空间\类名称

③完全限定式访问 在使用类时,\完整命名空间\类名称(继承和实例化)

如果一个类没有命名空间,使用 \类名

4.url访问

(见手册–架构–URL访问)
ThinkPHP5.0框架中,默认使用PATH_INFO方式的url进行访问。

格式

http://域名/入口文件/模块名/控制器名称/操作方法名称/参数名/参数值

例子

http://www.tpshop.com/index.php/Index/Test/index/page/10

隐藏入口文件写法

http://域名/模块名/控制器名称/操作方法名称/参数名/参数值

例子:

http://www.tpshop.com/index/user/index

需要对apache进行设置(手册–架构–URL访问、手册–部署–URL重写)

在这里插入图片描述
步骤总结:

httpd.conf配置文件中加载了mod_rewrite.so模块
在这里插入图片描述

虚拟主机配置中AllowOverride None 将None改为 All
在这里插入图片描述

在应用入口文件同级目录添加.htaccess文件,内容如下

<IfModule mod_rewrite.c>
Options +FollowSymlinks -Multiviews
RewriteEngine on

RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.*)$ index.php/$1 [QSA,PT,L]
</IfModule>

这个要注意:一般原生的php环境比如amp一个一个分别安装的一般是没问题的,但是如果是phpstudy的话,可能会有问题(不推荐大家用集成环境)
比如不携带入口文件访问会出现 No input file specified
需要修改一下.htaccess文件

<IfModule mod_rewrite.c>
Options +FollowSymlinks -Multiviews
RewriteEngine on

RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.*)$ index.php?/$1 [QSA,PT,L]
</IfModule>

在这里插入图片描述
在这里插入图片描述
大白话,就是说/index/user/index这一部分不是一个文件不是一个目录,它就会去找index.php文件,然后通过一个?把这一串,传递给框架中的入口文件进行处理(那个$1 就是反向引用前面那一大串路径),框架就会解析这个路径,把第一个斜杠后面的当作模块,第二个当作控制器,第三个当作方法名称。

在这里插入图片描述

使用Apapche的重写机制隐藏入口文件后,如果在整个url后面加上.html后缀, 让整个url看起来像是访问的静态页面。这叫做“伪静态”。

5.调试模式

见手册–错误与调试–调试模式

在这里插入图片描述
然后我地址乱输入一个
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

5、模块创建

1.创建前台模块和后台模块

一个典型的应用是由多个模块组成的(通常有前台网站模块和后台管理系统模块),这些模块通常都是应用目录下面的一个子目录,每个模块都有自己独立的配置文件、公共文件和类库文件。

我们给项目创建home(前台)和admin(后台)两个模块:
在这里插入图片描述
在这里插入图片描述
编写控制器和方法
在这里插入图片描述
在这里插入图片描述

2.配置默认的访问模块

打开配置文件application/config.php,有如下配置
在这里插入图片描述

'default_module' => 'index',

表示默认访问模块为index模块

可以更改默认模块为home模块

'default_module' => 'home',

在这里插入图片描述
此时直接输入域名,就会发现,直接访问到home模块了
在这里插入图片描述
注意:可以省略的规则只能是从后往前一级一级的省略

6、命令行创建模块目录及文件

这里是用phpstorme演示,这里就把刚才手动创建的模块删除,方便演示

1.命令行创建模块

php think build --module 模块名

在这里插入图片描述

2.命令行创建控制器

php think make:controller 模块名/控制器名 
php think make:controller 模块名/控制器名 --plain

加上 --plain 参数 表示创建没有方法的空控制器类。否则控制器类中会自带一些方法
在这里插入图片描述
在这里插入图片描述

3.命令行创建模型

php think make:model 模块名/模型名

注意:模型名首字母大写。

在这里插入图片描述

4.其它命令

有兴趣的可以自己看看
在这里插入图片描述

7、Request请求类

1.获取输入变量

(见手册–请求–输入变量)

比如这个地址:

http://www.tpshop.com/home/index/index/id/10/name/jack?age=20&sex=man

在这里插入图片描述
该如何接收?原生php接收是用这些方式

在这里插入图片描述
使用框架则不要用原生的接收了,框架封装过的做过一些特殊的处理功能也比较强大
有两种方式

第一种直接使用助手函数input助手函数来接收参数

input('name');//jack

第二种可以使用\think\Request

$request = \think\Request::instance();

或者使用助手函数得到request实例

$request = request();

例子:

Request::instance()->param('name');//jack

再或者如果继承了控制器基类可以这样使用
在这里插入图片描述

      $id = $this->request->param('id');
        dump($id);

在这里插入图片描述

它能够调用的方法有如下
在这里插入图片描述
param:能自动识别GET、POST或者PUT请求的一种变量获取方式,是系统推荐的获取请求参数的方法

这里主要说明一下get和route的区别
route只能取到这部分的参数
在这里插入图片描述
get方法只能取到如下部分的参数,这就是区别
在这里插入图片描述
代码演示

        $request = request();
        $get = $request->get();
        $param = $request->param();
        $route = $request->route();

        dump($get);
        dump($param);
        dump($route);

在这里插入图片描述

在这里插入图片描述

参数的解释

变量类型方法('变量名/变量修饰符','默认值','过滤方法')

变量修饰符
例如

input('get.id/d');
input('post.name/s');
input('post.ids/a');
Request::instance()->get('id/d');

在这里插入图片描述
什么时候这个默认/s会出问题呢?
比如你表单里面要接收一个爱好,name属性值比如我设置为如下
在这里插入图片描述

这个时候如果被转换为字符串就会报错,所以该参数需要接收为数组

Request::instance()->get('hobby/a');

第二个参数 默认值
比如没有传递,我接收一个默认值

Request::instance()->get('age',20);

第三个参数 过滤方法
在这里插入图片描述
第三个参数我们直接写上方法名称就行

Request::instance()->get('age',20,'trim');

回头我们看看param方法

// 获取当前请求的name变量
Request::instance()->param('name');
// 获取当前请求的所有变量(经过过滤)
Request::instance()->param();
// 获取当前请求的所有变量(原始数据)
Request::instance()->param(false);
// 获取当前请求的所有变量(包含上传文件)
Request::instance()->param(true);

input()与之等效的操作是

input('param.name');
input('param.');
或者
input('name');
input('');

param默认不传递参数是获取所有的经过过滤的数据
这个默认过滤的方法在配置文件中进行配置,
在这里插入图片描述
默认框架是空的,我们可以自己传递一个trim方法

在这里插入图片描述

实际操作
在这里插入图片描述

在这里插入图片描述

2.判断变量是否传递

Request::instance()->has('id','get');
Request::instance()->has('name','post');
input('?get.id');
input('?post.name');

3.参数绑定

手册–请求–参数绑定

3.1按照参数名称绑定

我们通过命令行创建控制器 后面不加参数 --plain时默认带有几个方法,我们发现它有的方法是需要参数的
在这里插入图片描述
在这里插入图片描述
这就是参数绑定,否则,我们想得到这个id就还需要下面的操作

在这里插入图片描述
一般我们只接收id,但是也可以接收多个
在这里插入图片描述

在这里插入图片描述
如果进行了参数绑定,没有传递参数则会报错
在这里插入图片描述
此时我们可以给一个默认值
在这里插入图片描述

在这里插入图片描述

3.2按照顺序绑定

一般我们不推荐用这个
在这里插入图片描述
在这里插入图片描述

4.依赖注入

手册–请求–依赖注入
依赖注入:简单的说,要在一个类A中使用另一个依赖类B时,不直接在类A中实例化类B,而是先实例化类B后再以参数的形式传入类A.

ThinkPHP的依赖注入(也称之为控制反转)是一种较为轻量的实现,无需任何的配置,并且主要针对访问控制器进行依赖注入。可以在控制器的构造函数或者操作方法(指访问请求的方法)中类型声明任何(对象类型)依赖,这些依赖会被自动解析并注入到控制器实例或方法中。

依赖注入基本原理代码示例

<?php
//一个请求类
class Request{
    public function param(){
        return 'params';
    }
}

//我们自己的控制器
class Goods{
    
    //控制器中的方法
    public function index(){
        $request = new Request();
        $params = $request->param();
        return $params;
    }
}

$goods = new Goods();
echo $goods->index();

在这里插入图片描述
在这里插入图片描述

这是最基本原理,当然了,框架的话,肯定会检测你方法是否传递了一个依赖对象,然后才判断是否要传递实例化对象到方法中

<?php
//一个请求类
class Request{
    public function param(){
        return 'params';
    }
}

//我们自己的控制器
class Goods{

    //控制器中的方法
    public function index(Request $request){
        $params = $request->param();
        return $params;
    }
}

$goods = new Goods();
$request = new Request();
echo $goods->index($request);



在这里插入图片描述
在这里插入图片描述

5.总结

//1.获取请求对象  
$request = request();
$request = \think\Request::instance();
$request = $this->request; //仅限于继承了底层控制器的情况下
public function save(Request $request)  //依赖注入
   //2. 接收请求参数 param方法
    $params = $request->param();
	$params = input();
	$params = request()->param();
	$id = $request->param('id');
	$id = input('id');
	public function edit($id)//参数绑定

8、视图

1.视图的组成

View视图类(继承了自定义模板引擎,功能与Smarty类似)
HTML模板文件

2.模板的定义

手册–模板–模板定位

为了对模板文件更加有效的管理,ThinkPHP对模板文件进行目录划分,默认的模板文件定义规则是:视图目录/控制器名(小写)/操作名(小写)+模板后缀

默认的视图目录是模块的view目录,框架的默认视图文件后缀是.html。

2.1return view()

在这里插入图片描述
在这里插入图片描述

2.2return $this->fetch()

在这里插入图片描述
在这里插入图片描述

2.3 名称不一样传递参数

在这里插入图片描述

2.4给模板传递参数

在这里插入图片描述
页面上输出
在这里插入图片描述
在这里插入图片描述
直接使用view()方法传递参数

        $user = ['id'=>11,'name'=>'Jack'];
        $age = 30;
        return view('edit',['user'=>$user,'age'=>$age]);

在这里插入图片描述
在这里插入图片描述
使用compact函数,简化一点代码,效果是一样的
在这里插入图片描述

9、静态模板和框架整合

一般模板去网上扒,要么前台写好,要么自己边开发边写
在这里插入图片描述

1.整合步骤

模板整合思路:

①确定页面的访问路径(模块、控制器、方法)

②新建对应的控制器方法,在方法中调用模板

③将模板页面移动到对应的视图目录下(创建子目录)

④将静态资源文件移动到public/static/admin目录下

⑤修改模板文件中静态资源路径

2.模板布局

手册–模板–模板布局
使用模板布局,就是把多个模板页面都有的公共代码给抽取出来,放到一个公共位置开发维护

好处:相同的代码只维护一份,减少代码工作量
后台全局布局设置步骤:
①修改配置文件application/admin/config.php,加入以下设置

'template'  =>  [
    'layout_on'     =>  true,//开启布局
    'layout_name'   =>  'layout',//布局文件名称
]

在这里插入图片描述

②将静态资源文件移动到/public/static/admin目录下

在这里插入图片描述

③在application/admin/view目录下,新建layout.html

将后台页面公共的头部、底部代码提取到layout.html中,在中间位置放一个特殊字符串“{CONTENT}”,表示此位置,替换为原始要访问的页面内容。

layout.html文件中, 只保留所有页面公共 的css和js相关代码,修改静态资源路径

注: 一定不能 直接将所有css和js都放在layout.html中。

注:TP框架中,模板中的静态资源路径,不能使用相对路径./ ,必须使用以/开头的路径。

④临时关闭模板布局
全局布局设置,对所有页面全部生效。

特殊页面(不需要使用布局的页面),可以在控制器方法中,临时关闭模板布局。

$this->view->engine->layout(false);

比如登录页面,不需要使用布局

3.首页整合

实际上就是首页只加载首页所需的一部分,然后把首页所需要的js单独放到该页面
在这里插入图片描述

4.后台登录页面

后台登录页是它没有公共区域
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
需要临时关闭模板布局

$this->view->engine->layout(false);

在这里插入图片描述
发现页面没生效?这个时候把缓存目录删除即可
在这里插入图片描述
执行命令

php think clear

或者手动删除
在这里插入图片描述
页面刷新,成功

在这里插入图片描述

10、模型

1.导入数据库

新建tpshop数据库(create database tpshop character set utf8 collate utf8_general_ci)

导入数据表
导入数据表(source sql路径)

说明:如果导入sql文件时,有报错,提示类似“不能使用innodb”

解决办法:

打开mysql配置文件,修改如下
在这里插入图片描述

default-storage-engine=INNODB

重启mysql即可。
如果重启失败,找到mysql的安装目录下data目录,删除以ib开头的文件(可以先备份),再重启。

在这里插入图片描述
导入成功后就有一个统一前缀的数据库
在这里插入图片描述

2.配置数据库连接

一般要修改的也就这几个
在这里插入图片描述
在这里插入图片描述
注:框架底层使用PDO来连接数据库,从配置文件中读取相关连接信息。

'auto_timestamp'  => true    	// 自动写入时间戳字段

(手册–模型–时间戳)

设置为true 表示数据表新增数据、修改数据的时候会自动维护对应的时间信息

字段名默认创建时间字段为create_time,更新时间字段为update_time,支持的字段类型包括timestamp/datetime/int

在这里插入图片描述

3.模型的定义

(见手册–模型–定义)

定义位置:application/当前分组目录/model目录下

命名规则:模型会自动对应数据表,模型类的命名规则是除去表前缀的数据表名称,采用驼峰法命名,并且首字母大写,例如:

模型名约定对应数据表(假设数据库的前缀定义是 think_)
Userthink_user
UserTypethink_user_type

可以使用命令行创建模型:

php think make:model 模块名/模型名

示例:创建后台商品模型 Goods.php

php think make:model admin/Goods

在这里插入图片描述

4.特殊表名称的处理

特殊表:没有前缀的表,或者前缀与配置项的设置不一致。

解决办法:模型中使用$table属性来设置完整数据表名称。

在这里插入图片描述

11、查询多条数据

(手册–模型–查询)
增删改查 (CURD create update read delete)

创建控制器进行测试

实例化模型,通过命名空间查找,一个反斜杠+模型的命名空间+类名();

 //实例化模型,传统的写法
$model  = new \app\admin\model\Goods();

在这里插入图片描述
在这里插入图片描述
同样的可以把命名空间提到上面,这样显得代码比较干净

在这里插入图片描述
还有一个注意的点,如果控制器和模型发生重名通过取别名解决

在这里插入图片描述

1.获取多个数据

1.1静态调用all/select方法

// 获取所有数据 all 和 select

$list = User::all();

// 根据主键获取多个数据all 和 select   where id in (1,2,3)

$list = User::all('1,2,3');

$list = User::all([1,2,3]);

//或者使用数组查询(只能用all不能用select)   where status = 1

$list = User::all(['status'=>1]);

1.2动态调用all方法或者select方法

$user = new User();

//查询所有数据all 和 select

$list = $user->select();

//根据主键查询多条数据all 和 select

$list = $user->select('1,2,3');

$list = $user->select([1,2,3]);

//或者使用数组查询(只能用all不能用select)

$list = $user->all(['status'=>1]);

注:all方法或者select方法返回的是一个包含模型对象的二维数组或者空数组
顶层返回的是集合还是数组就看配置文件的配置

在这里插入图片描述

1.3实际演示

可以得出
返回的数据结构是,最外层是一个数组,里面是一个一个的对象,一个对象代表一条数据
在这里插入图片描述

在这里插入图片描述
要打印里面每条数据的字段,可以循环


        $model  = new Goods();

        $data =  $model::select();
        foreach ($data as $v){
            dump($v->goods_name);
            //或者
            dump($v['goods_name']);
        }

在这里插入图片描述
在这里插入图片描述

1.4查询指定的3条数据

在这里插入图片描述

        $model  = new Goods();

//        $data =  $model::select('32,33,34');
        //或者这样
        $data =  $model::select([32,33,34]);

        foreach ($data as $v){
            dump($v->goods_name);
        }

1.5为了打印数据查看方便的方法

这个只是为了打印好看,实际上开发的时候,直接把返回的结果当数组用就行了

        $model  = new Goods();

        $data =  $model::select([32,33,34]);

        //&表示地址引用这样修改的数据在$data 中才会生效
        foreach ($data as &$v){
            $v = $v->toArray();
        }
        //循环结束要记得销毁$v
        unset($v);

        //或者这样
//        foreach ($data as $k=>$v){
//            $data[$k] = $v->toArray();
//        }

        dump($data);

在这里插入图片描述

或者用框架的方法,效果同上

 $model  = new Goods();

        $data =  $model::select([32,33,34]);

        //利用框架的Collection类的方法
        $data = (new \think\Collection($data))->toArray();

        dump($data);

2.案例:后台商品列表展示

所用知识点:获取多个数据、变量输出与数组遍历、URL生成

2.1控制器中调用模型查询数据(模板变量赋值)

四种方式都可以用

{$v.id}
{$v['goods_name']}
{$v->goods_price}
{$v:goods_number}

在这里插入图片描述

2.2链接到新增url地址

这个地址是不需要参数的

<a class="btn btn-primary" href="/index.php/admin/goods/create.html">新增</a>

在这里插入图片描述
不推荐上面这种写法,因为有的人可能加了入口文件有的人没加,有的人可能还会在url地址后面加上?来传递参数,没有进行统一规范
推荐使用用框架封装的函数url

<a class="btn btn-primary" href="{:url('admin/goods/create')}">新增</a>

可以省略模块名和控制器名称

<a class="btn btn-primary" href="{:url('create')}">新增</a>

如果不写就会从当前页面自动取模块和控制器
在这里插入图片描述
所以推荐所有的地址都写全,这样比较直观

其中{:url()} 的冒号代表调用函数,不是在输出变量

2.3链接到编辑url地址

这个地址是需要传递一个参数的

 <a href="{:url('admin/goods/edit',['id'=>$v.id])}"> 编辑 </a>

在这里插入图片描述

2.4链接中一些引号的注意事项

观察这个发现是双引号里面我们要跳转链接

 <a href="javascript:void(0);" onclick="if(confirm('确认删除?')) location.href='#'"> 删除 </a>

在这里插入图片描述
解决办法,就是需要转义一下

 <a href="javascript:void(0);" onclick="if(confirm('确认删除?')) location.href='' +
                     '{:url(\'admin/goods/delete\',[\'id\'=>$v.id])}'"> 删除 </a>

在这里插入图片描述

3.模板中变量输出与数组遍历

3.1模板赋值

在控制器中,使用$this -> assign(“视图模板中的变量名”, 变量值);

使用传入参数方法:view(‘模板名’, [‘视图模板中的变量名’ => 变量值]);

3.2变量输出

在模板文件中,直接输出变量 {$变量名}

输出数组中的值: 点语法 {$变量名.键名} ; 数组语法 {$变量名[‘键名’]}

输出对象中的属性: 冒号语法 {$变量名:属性名} ; 对象语法 {$变量名->属性名]}

3.3默认值设置语法

{$变量名|default=”默认值”}

3.4循环输出标签volist

见手册–模板–内置标签

TP框架内置的遍历数组的标签: volist标签 和foreach标签。

{volist name='数组变量名' key='k' id='v' offset='5' length='10' empty='nothing'}{/volist}

name:要遍历的数组名,不需要$符号

key:定义循环变量名,默认为i, 当前遍历的是第几个,从1开始计数,与原数组下标无关

id:当前的循环变量,是一个变量名

offset:指定从第几个开始遍历,从0开始计数

length:指定遍历多少个元素就结束。

empty:没有数据时显示的内容

其中:如果没有定义key属性, 可以直接输出{$key}变量表示原数组的下标。

注意:这几个属性的值必须有单、双引号

            {volist name='list' key='k' id='v' offect='3' length='5' empty='哦!抱歉没有找到任何数据'}
            <tr class="info">
                <td>{$v.id}</td>
                <td><a href="javascript:void(0);">{$v['goods_name']}</a></td>
                <td>{$v->goods_price}</td>
                <td>{$v:goods_number}</td>
                <td><img src="img/goods04_thumb.jpg"></td>
                <td>{$v->create_time}</td>
                <td>
                    <a href="{:url('admin/goods/edit',['id'=>$v.id])}"> 编辑 </a>
                    <a href="javascript:void(0);" onclick="if(confirm('确认删除?')) location.href='' +
                     '{:url(\'admin/goods/delete\',[\'id\'=>$v.id])}'"> 删除 </a>
                </td>
            </tr>
            {/volist}

在这里插入图片描述

3.5循环输出标签foreach

Foreach标签和volist标签类似,用法更加简单
最简单的用法:

{foreach $list as $k=>$v} {/foreach}

也可以使用完整写法:

{foreach name='数组变量名' key='k' item='v'}{/foreach}

name:要遍历的数组名,不需要$符号

key:定义循环变量名,原数组的下标

item:当前的循环变量,是一个变量名

其中,使用完整写法时,如果没有定义key属性, 可直接输出{$key}变量表示原数组的下标。

简单语法:
在这里插入图片描述

完整语法
在这里插入图片描述

4.URL生成

手册–路由–URL生成
URL生成使用 \think\Url::build() 方法或者使用系统提供的助手函数url(),参数一致

Url::build('地址表达式',['参数'],['URL后缀'],['域名'])
url('地址表达式',['参数'],['URL后缀'],['域名'])

地址表达式和参数就不 解释了

URL后缀:boolean或者字符串
false:不携带html后缀,
true:携带html后缀,

域名: boolean或者字符串
false:不带域名
true:携带域名

        dump(url('admin/goods/index'));
        dump(url('admin/goods/edit',['id'=>1,'page'=>10]));
        dump(url('admin/goods/edit',['id'=>1,'page'=>10],false));
        dump(url('admin/goods/edit',['id'=>1,'page'=>10],"htm"));
        dump(url('admin/goods/edit',['id'=>1,'page'=>10],true,true));
        dump(url('admin/goods/edit',['id'=>1,'page'=>10],true,"www.baidu.com"));

在这里插入图片描述
在这里插入图片描述

12、查询一条数据

1.获取一个数据

1.1静态调用get方法或者find方法

//取出主键为1的数据  where id = 1

$user = \app\admin\model\User::get(1);

$user = \app\admin\model\User::find(1);

//使用数组查询(非主键字段),只能用get不能用find   where name = 'thinkphp'

$user = User::get(['name' => 'thinkphp']);

//取出第一条数据,只能用find不能用get

$user = User::find();

1.2动态调用get方法或者find方法

$user = new User();

//取出主键为1的数据

$info = $user->find(1);

$info = $user->get(1);

//使用数组查询(非主键字段),只能用get不能用find

$info = $user->get(['name' => 'thinkphp']);

//取出第一条数据,只能用find不能用get

$info = $user->find();

注:get或者find方法返回的是当前模型的对象实例或者null
返回的模型对象,可以直接当做数组使用,也可以调用toArray() 直接转化为数组。

在这里插入图片描述
在这里插入图片描述
可以直接当作数组用
在这里插入图片描述

2商品的详情页案例

先去列表页,把跳转链接整好
在这里插入图片描述

在这里插入图片描述
查询数据跳转视图
在这里插入图片描述
展示数据
在这里插入图片描述
在这里插入图片描述

13、其它查询方法

见手册–数据库–查询构造器–查询语法

1.where方法(查询语法)

where('字段名','表达式','查询条件');

whereOr('字段名','表达式','查询条件');
表达式含义
EQ、=等于(=)
NEQ、<>不等于(<>)
GT、>大于(>)
EGT、>=大于等于(>=)
LT、<小于(<)
ELT、<=小于等于(<=)
LIKE模糊查询
[NOT] BETWEEN(不在)区间查询
[NOT] IN(不在)IN 查询
[NOT] NULL查询字段是否(不)是NULL
[NOT] EXISTSEXISTS查询
EXP表达式查询,支持SQL语法
> time时间比较
< time时间比较
between time时间比较
notbetween time时间比较

注:where方法中,如果比较表达式是等于,可以省略这个参数。

$info = User::where('id','=','1')->find();

$info = User::where('id','1')->find();

$info = User::where('name','like','%thinkphp%')->select();

在这里插入图片描述
在这里插入图片描述

注意:使用了where方法后,查询数据可以使用find方法和select方法,不能使用get方法和all方法。(原因:where方法返回的是Query对象,不是模型对象)
在这里插入图片描述

在这里插入图片描述
批量条件查询(手册-数据库-查询构造器-高级查询)

在这里插入图片描述

2.连贯操作(链式操作)

手册–数据库–查询构造器–链式操作
原理:中间调用的方法,返回值是对象,可以继续调用对象的其他方法。

一条sql语句的组成可以很复杂,里边有where、order by、group by、限制查询的字段、limit、having限制条件等等,这些复杂的条件在tp框架中都有封装

注:TP框架中,中间的方法没有顺序要求,当时用于获取最终结果的find和select等方法,必须在最后。

$model = new Address();

$model->field('id,name')->select(); //指定要查询的字段,原生sql中select后面的字段

$model->order('id desc,time desc')->select(); //相当于原生sql中的order by

$model->limit(3)->select(); //相当于原生sql中的limit条件

$model->limit(0,3)->select(); 

$model->limit('0,3')->select(); 

$model->group('cate_id')->select();  //相当于原生sql中的group by

$model->having('id>3')->select();  //相当于原生sql中的having条件

$model->alias('a')->join('think_user_type t','a.id=t.user_id', 'left')->select(); //alias方法设置别名,join方法连表查询


//Address::alias('a')->join('tpshop_user u','a.user_id = u.id', 'left')->select();

原生的sql联表查询

SELECT * FROM `tpshop_goodspics` g LEFT JOIN tpshop_goods gs on g.goods_id = gs.id;

3.统计查询(聚合查询)

手册–模型–聚合,
手册–数据库–查询构造器–聚合查询

一般要查询这条数据是否存在就可以使用这个聚合查询,如果结果不等于0就表示存在

方法说明
count统计数量,参数是要统计的字段名(可选)
max获取最大值,参数是要统计的字段名(必须)
min获取最小值,参数是要统计的字段名(必须)
avg获取平均值,参数是要统计的字段名(必须)
sum获取总分,参数是要统计的字段名(必须)

这些方法的返回值是具体的数据。在连贯操作中只能放在最后,不需要使用find和select。

count方法 相当于 select count(*) from tpshop_user;

在这里插入图片描述

4、数据字段查询

4.1查询一条记录的一个字段的值

Goods::where(‘id’, 2)->value(‘goods_name’);

在这里插入图片描述

在这里插入图片描述

4.2查询多条记录的一个字段的值,返回一个一维索引数组

Goods::where(‘id’, ‘GT’, 2)->column(‘goods_name’);

在这里插入图片描述
在这里插入图片描述

4.3查询多条记录的一个字段的值,以id字段值作为数组索引

Goods::where(‘id’, ‘GT’, 2)->column(‘goods_name’, ‘id’);

在这里插入图片描述

5、数据字段查询

Trace调试功能就是ThinkPHP提供给开发人员的一个用于开发调试的辅助工具。可以实时显示当前页面的操作的请求信息、运行情况、SQL执行、错误提示等

开启trace调试:

修改application/config.php , 配置以下参数:

'app_trace' => true

开启后在右下角,在这里插入图片描述在这里插入图片描述
在这里插入图片描述

6.小结

在这里插入图片描述
在这里插入图片描述

14、模板中数据的展示

1、条件判断标签if

TP框架中内置了if标签,用于在模板文件中进行if判断。语法如下:

{if condition="($name == 1) OR ($name > 100) "} value1

{elseif condition="$name eq 2"/}value2

{else /} value3

{/if}

也可以写为以下形式:

{if ($name == 1)}value1

{/if}

2、范围判断标签in

范围判断标签包括in notin between notbetween四个标签,都用于判断变量是否中某个范围。

{in name="id" value="1,2,3"} id在范围内

{/in}

{in name="id" value="$range"} id在范围内

{/in}

Name属性值为变量名,不带$符号

Value属性值可以是字符串范围,也可以是数组变量或者字符串变量。

相当于原生php中的 if(in_array())

3、使用函数

手册–模板–使用函数
在模板文件中输出变量,可以对变量使用函数进行处理

语法:两种语法:

{$变量名称|函数名称=arg1,arg2,###}

参数中,可以使用### 代替输出的变量本身,如果变量本身是第一个参数,可以省略。

示例:

//对时间格式化
{$v.goods_create_time|date='Y-m-d H:i:s', ###}
//对字符串进行md5加密
{$name|md5}

{:函数名称(参数)}

{:date("Y-m-d H:i:s", $v['goods_create_time'])}

凡是php本身的函数或者框架中定义的函数,都可以在模板中直接调用。

4、系统变量

手册–模板–系统变量
TP框架自带了一个$Think变量,用于在模板中输出系统变量。

$Think.server :相当于$_SERVER

$Think.get	:相当于$_GET

$Think.post :相当于$_POST

$Think.request :相当于$_REQUEST

$Think.cookie :相当于$_COOKIE

$Think.session :相当于$_SESSION

$Think.config.名称 :输出配置参数

$Think.const.名称:输出常量

相当于框架帮我们做了以下事情
$Think = [
	'get' => $_GET,
	'post'=>$_POST

];
$this->assign('Think', $Think);

示例:
url地址:

http://www.tpshop.com/index.php/Admin/Goods/index?page=10

展示page参数值: {$Think.get.page}

5、使用运算符

在模板文件中输出变量时,可以先使用运算符进行运算。

+ 		{$a+$b}

- 		{$a-$b}

* 		{$a*$b}

/		{$a/$b}

%		{$a%$b}  取余或取模

++		{$a++}{++$a}

--		{$a--}{--$a}

15、添加数据

手册–模型–新增

1、添加一条数据(save方法)

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

1.1获取自增ID

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

Save方法返回值是写入的记录数

2、静态方法添加(create方法)

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

create返回的是模型对象

3、添加多条数据(saveAll方法)

在这里插入图片描述

        //直接在实例化的时候传入数据
        $goods  = new \app\admin\model\Goods();
        $data = [
            [
                'goods_name' => "华为",
                'goods_price' => "5000"
            ],
            [
                'goods_name' => "华为",
                'goods_price' => "5000"
            ]
        ];

       $res =  $goods->saveAll($data);

        dump($res);

在这里插入图片描述

在这里插入图片描述

saveAll返回的是包含新增模型(带自增ID)的数据集(数组)

4、过滤非数据表字段

4.1save

save方法: 调用save方法之前,先调用allowField方法
在这里插入图片描述

4.2create

create方法: 给create方法传递第二个参数,true

User::create($_POST, true);

16、添加商品案例

1.功能实现

修改添加页面的跳转地址
在这里插入图片描述
新增表单字段
在这里插入图片描述

控制器接收数据,好几种接收方法

        $params = input(); //助手函数
        $params = $request->param();//依赖注入
        $params = $this->request->param();//控制器接收
        $params = request()->param();//request助手函数
        $params = \think\Request::instance()->param();//实例化\think\Request类

在这里插入图片描述

在这里插入图片描述

操作成功后跳转列表页
在这里插入图片描述

在这里插入图片描述

        //接收参数
        $params = input();


        //添加到数据库,true,过滤非数据表字段
        \app\admin\model\Goods::create($params,true);

        //添加成功,不写跳转地址,就默认返回上个页面
        $this->success('操作成功');
        //跳转到列表页
        $this->success('操作成功','admin/goods/index');
        //可以只写方法名,默认就从当前控制器去找对应的方法
//        $this->success('操作成功','index');

在这里插入图片描述

2.小结

1.模型的时间戳功能

手册–模型–时间戳
在这里插入图片描述
注:自动写入时间戳字段,前提是数据表必须有对应的字段存在。

如果你的时间戳字段不是默认值的话

class User extends Model 
{
    // 定义时间戳字段名
    protected $createTime = 'create_at';
    protected $updateTime = 'update_at';
}

2.页面跳转与重定向

手册–控制器–跳转和重定向

成功时跳转

$this -> success(“提示信息”,“跳转地址”,“返回数据”,“等待时间”,“header信息”);

失败时跳转

$this -> error(“提示信息”,“跳转地址”,“返回数据”,“等待时间”,“header信息”);

等待时间默认3s。 跳转地址可以不写,默认跳转回上一页。
重定向跳转:用于直接跳转,不显示提示信息。

$this -> redirect(“跳转地址”,“请求参数”,“http code”);

在这里插入图片描述
这些跳转方法在父类控制器找不到的,用了php的一个新的语法traits
在这里插入图片描述
真正的类文件在这个位置
在这里插入图片描述

17、富文本编辑器的使用

1.下载ueditor

这里使用ueditor演示
下载地址:

https://github.com/fex-team/ueditor/releases

在这里插入图片描述
在这里插入图片描述

2.引入js文件

在这里插入图片描述
在这里插入图片描述

<!-- 配置文件 -->
<script type="text/javascript" src="/plugins/ueditor/ueditor.config.js"></script>
<!-- 编辑器源码文件 -->
<script type="text/javascript" src="/plugins/ueditor/ueditor.all.js"></script>
  <textarea value="Smith" id="container"  name="goods_introduce" rows="3" class="input-xlarge" style="width: 100%;height: 500px" ></textarea>
                    <!-- 实例化编辑器 -->
                    <script type="text/javascript">
                        var ue = UE.getEditor('container');
                    </script>

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

18、表单验证

见手册–验证
对接收的参数,进行格式的检测

1、验证语法

TP框架提供了一个\think\Validate验证类,也可以自定义提示信息

1.1基本使用

$validate = new Validate([
    'name'  => 'require|max:25',
    'email' => 'email'
]);
$data = [
    'name'  => 'thinkphp',
    'email' => 'thinkphp@qq.com'
];
if (!$validate->check($data)) {
    dump($validate->getError());
}

其中的require是什么意思?见下方的内置规则

1.2验证器

这个是把验证单独写到一个文件中,这个是框架推荐的做法
比如我们定义一个\app\index\validate\User验证器类用于User的验证。

namespace app\index\validate;

use think\Validate;

class User extends Validate
{
    protected $rule = [
        'name'  =>  'require|max:25',
        'email' =>  'email',
    ];

}

在需要进行User验证的地方,添加如下代码即可:

$data = [
    'name'=>'thinkphp',
    'email'=>'thinkphp@qq.com'
];

$validate = Loader::validate('User');

if(!$validate->check($data)){
    dump($validate->getError());
}

或者使用助手函数实例化验证器

$validate = validate('User');

2、内置规则

见手册–验证–内置规则
地址:

https://www.kancloud.cn/manual/thinkphp5/129356

在这里插入图片描述

3、在商品添加功能中,进行表单验证(参数检测)

步骤:

定义验证规则数组$rule

定义提示信息数组$msg

实例化验证类

调用check方法进行验证

        //接收参数
        $params = input();

        //表单验证
        //定义验证规则
        $rule =  [
            'godos_name|商品名称' => 'require',
            'godos_price|商品价格' => 'require|float|egt:0',
            'godos_number|商品数量' => 'require|integer|egt:0',
        ];
        //定义错误提示信息(可选)
        $msg = [
            'godos_price.float'=>'商品价格必须是整数或者小数'
        ];
        //实例化验证类
        $validate = new Validate($rule,$msg);

        //执行验证
        if(!$validate->check($params)){
            //验证失败
            $error_msg = $validate->getError();
            $this->error($error_msg);
        }

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

4、控制器验证

控制器继承了\think\Controller的话,可以调用控制器类提供的validate方法进行验证

$result = $this->validate(
    [
        'name'  => 'thinkphp',
      'email' => 'thinkphp@qq.com',
   ],
    [
       'name'  => 'require|max:25',
        'email'   => 'email',
    ]);
if(true !== $result){
    // 验证失败 输出错误信息
    dump($result);
}

如果定义了验证器的话,如

namespace app\index\validate;

use think\Validate;

class User extends Validate
{
    protected $rule = [
        'name'  =>  'require|max:25',
        'email' =>  'email',
    ];

    protected $message = [
        'name.require'  =>  '用户名必须',
        'email' =>  '邮箱格式错误',
    ];

    protected $scene = [
        'add'   =>  ['name','email'],
        'edit'  =>  ['email'],
    ];
}

控制器中的验证代码可以简化为:

$result = $this->validate($data,'User');
if(true !== $result){
    // 验证失败 输出错误信息
    dump($result);
}

如果要使用场景,可以使用:

$result = $this->validate($data,'User.edit');
if(true !== $result){
    // 验证失败 输出错误信息
    dump($result);
}

在validate方法中还支持做一些前置的操作回调,使用方式如下:

$result = $this->validate($data,'User.edit',[],[$this,'some']);
if(true !== $result){
    // 验证失败 输出错误信息
    dump($result);
}

实例演示
和上面的演示其实就是只有一点点差别

在这里插入图片描述

        //接收参数
        $params = input();

        //表单验证
        //定义验证规则
        $rule =  [
            'godos_name|商品名称' => 'require',
            'godos_price|商品价格' => 'require|float|egt:0',
            'godos_number|商品数量' => 'require|integer|egt:0',
        ];
        //定义错误提示信息(可选)
        $msg = [
            'godos_price.float'=>'商品价格必须是整数或者小数'
        ];
        //实例化验证类
//        $validate = new Validate($rule,$msg);

        //执行验证
//        if(!$validate->check($params)){
//            //验证失败
//            $error_msg = $validate->getError();
//            $this->error($error_msg);
//        }
        $validata = $this->validate($params,$rule,$msg);
        if($validata !== true){
            $this->error($validata);
        }

19、修改操作

手册–模型–更新

1.更新一条数据

1.1查询再修改

$user = User::get(1);
$user->name     = 'thinkphp';
$user->email    = 'thinkphp@qq.com';
$user->save();

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
注意点:如果数据没有更改再次执行结果将返回为0
在这里插入图片描述

1.2直接带更新条件更新数据

$user = new User;
// save方法第二个参数为更新条件
$user->save([
    'name'  => 'thinkphp',
    'email' => 'thinkphp@qq.com'
],['id' => 1]);

在这里插入图片描述

1.3过滤非数据表字段

上面两种方式更新数据,如果需要过滤非数据表字段的数据,可以使用
allowField(true)方法

在这里插入图片描述

1.4指定具体的字段更新

$user = new User();
// post数组中只有name和email字段会写入
$user->allowField(['name','email'])->save($_POST, ['id' => 1]);

代码示例

        $params = [
            'goods_name'=>'华为',
            'goods_price'=>'5000',
            'goods_cate' => 1
        ];

        $model = new \app\admin\model\Goods();
        $model->allowField(['goods_name','goods_price'])->save($params,['id' => 32]);

在这里插入图片描述

1.5静态方法更新(推荐)

1.5.1方法一:模型直接调用静态方法update

在这里插入图片描述

        // 参数:修改的数据 修改条件 过滤非数据表字段
        //主键ID直接在修改的数据当中可以直接修改
        $res = \app\admin\model\Goods::update(['goods_name'=>'oppo','goods_price'=>'2000','id'=>32],[],true);
        //把修改条件写在外面
        $res = \app\admin\model\Goods::update(['goods_name'=>'oppo','goods_price'=>'2000','id'=>32],['id'=>32],true);
        //简化后就是把条件写第二个参数,是一个数组
        $res = \app\admin\model\Goods::update(['goods_name'=>'oppo','goods_price'=>'2000'],['id'=>32],true);

它返回的是该模型的对象
在这里插入图片描述

注意:只有直接模型静态调用update方法的更新方式才有过滤数据表字段的功能

1.5.2方法二:update方法前用where方法限制条件

User::where('id', 1)
    ->update(['name' => 'thinkphp']);

    $res = \app\admin\model\Goods::where('id',32)->update(['goods_name'=>'oppo','goods_price'=>'3000']);
        dump($res);

在这里插入图片描述

在这里插入图片描述
注意:返回的是受影响的行数,第二次执行返回永远都是0

1.5.3两个方法的区别总结

模型update方法,和底层的update方法
返回值不同:模型返回的是模型对象,底层返回的是受影响行数
包含的功能不同:模型的update方法有过滤非数据库字段的功能,底层的没有

2.批量更新

2.1用where的限制条件

和上面的更新一条的方式语法一样,只不过是where的条件不再是一条,而是多条

        $res = \app\admin\model\Goods::where('id','>',142)->update(['goods_name'=>'oppo','goods_price'=>'3000']);
        dump($res);

在这里插入图片描述

在这里插入图片描述
注意:返回的也是受影响的行数

2.2用saveAll方法

批量更新仅能根据主键值进行更新,其它情况请使用foreach遍历更新。

$user = new User;
$list = [
    ['id'=>1, 'name'=>'thinkphp', 'email'=>'thinkphp@qq.com'],
    ['id'=>2, 'name'=>'onethink', 'email'=>'onethink@qq.com']
];
$user->saveAll($list);

实际操作

        $model = new \app\admin\model\Goods();
        $res = $model->saveAll(
            [
                ['id' => 32, 'goods_name' => 'oppo', 'goods_price' => '3000'],
                ['id' => 33, 'goods_name' => 'oppo', 'goods_price' => '3000'],
            ]
        );
        dump($res);

在这里插入图片描述
在这里插入图片描述
注意:返回的是模型对象

3.自动识别

手册-模型-更新
我们已经看到,模型的新增和更新方法都是save方法,系统有一套默认的规则来识别当前的数据需要更新还是新增。

•实例化模型后调用save方法表示新增;
•查询数据后调用save方法表示更新;
•调用模型的save方法后表示更新;

第三条规则意思是前面调用过一次save方法了,后面一次再调用save方法,不管前面是新增还是更新本次都是更新操作,原因是,第二次操作后数据库中肯定有记录了。

3.1显式更新数据:

如果你的数据操作比较复杂,可以显式的指定当前调用save方法是新增操作还是更新操作。

显式更新数据:

// 实例化模型
$user = new User;
// 显式指定更新数据操作
$user->isUpdate(true)
    ->save(['id' => 1, 'name' => 'thinkphp']);

显示新增数据

$user = User::get(1);
$user->name = 'thinkphp';
// 显式指定当前操作为新增操作
$user->isUpdate(false)->save();

20、修改商品功能案例

1、页面展示

1.1修改Goods控制器edit方法,查询原始商品数据

修改编辑页面的编辑链接
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

1.2修改view/goods/edit.html ,将原始数据展示到input输入框的value上

在这里插入图片描述

2、表单提交

2.1确认表单完整性,完善提交地址和name属性值等

在这里插入图片描述

2.2 修改view/goods/edit.html ,添加隐藏域,保存当前商品记录的主键id值

2.2.1可以在url后面传递

在这里插入图片描述

2.2.2用隐藏域传递

在这里插入图片描述

2.3修改Goods控制器update方法,接收表单提交并保存数据

可以先打印一下看看能否接收到
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

        //接收数据
        $data = $this->request->param();
        //表单验证()
        \app\admin\model\Goods::update($data,['id'=>$id],true);

        //操作反馈
        $this->success('更新成功','index');

21、删除操作

1.物理删除

1.1先查询,再调用模型的delete方法删除

$user = User::get(1);
$user ->delete();

注意:因为是先查询后删除所以删除成功后再次执行,会报错,需要加判断

在这里插入图片描述

        $goods = \app\admin\model\Goods::find(32);
        if(empty($goods)){
            echo "数据已经被删除";die();
        }
        $goods->delete();

在这里插入图片描述

1.2先调用where方法,再调用Query类的delete方法删除

User::where(‘id’, 1)->delete();
      $res =   \app\admin\model\Goods::where('id',33)->delete();
      dump($res);

在这里插入图片描述

在这里插入图片描述
再次执行结果永远都是0
在这里插入图片描述

1.3静态调用destroy方法删除(推荐)

User::destroy(1);
User::destroy(‘1,2,3’);
User::destroy([1,2,3]);
User::destroy([‘status’=>1]);
        //根据主键ID,删除一条
        $res = \app\admin\model\Goods::destroy(142);
        dump($res);

        //根据主键ID,删除多条,用逗号分割的字符串
        $res2 = \app\admin\model\Goods::destroy('143,144');
        dump($res2);

        //根据主键ID,删除多条,用逗号分割的字符串
        $res3 = \app\admin\model\Goods::destroy(['136', '137']);
        dump($res3);

        //根据条件删除
        $res4 = \app\admin\model\Goods::destroy(['goods_name' => 'oppo']);
        dump($res4);

在这里插入图片描述

在这里插入图片描述
再次执行,都是返回0
在这里插入图片描述

2trait

手册–架构–Traits引入
trait是php5.4开始引入的,tp5.0中的软删除需要使用到trait,所以我们先学习一下trait的知识

2.1初识trait

trait A{
	public function getName()
	{
		return 'This is trait';
	}
}

trait的定义,和类非常相似,只需要将关键字class换成trait即可。

2.2trait的使用

定义trait之后,在一个类中进行使用。

class B{
	use A;
}
$b = new B();
echo $b->getName(); //This is trait

2.3trait的继承关系

trait A{
    public function getName()
    {
        return 'A-getName';
    }
    
    public function getAge()
    {
        return 'A-getAge';
    }
}

class C{
    public function getName()
    {
        return 'C-getName';
    }

    public function getAge()
    {
        return 'C-getAge';
    }

    public function getSex()
    {
        return 'C-getSex';
    }
}

class B extends C{

    //使用trait
    use A;

    public function getAge()
    {
        return 'B-getAge';
    }

    public function getSex()

    {
        return 'B-getSex';
    }
}
$b = new B();
echo $b->getSex();//B-getSex
echo $b->getName();//A-getName
echo $b->getAge();//B-getAge

总结:有同名方法,当前类方法 会覆盖 trait的方法,trait的方法会覆盖继承类的方法。

2.4TP中的trait

父类控制器Controller中使用了Jump这个trait,提供了页面跳转相关方法。

模型的SoftDelete这个trait,需要在自定义模型中,手动使用,提供的是软删除相关功能。

3.软删除

手册–模型–软删除

本质是修改操作,原理:在数据表添加一个字段控制数据在页面的展示。点击删除操作时,修改对应字段的值。

因此,tp框架默认的软删除字段名称是'delete_time',数据表的默认值为null
在这里插入图片描述

3.1软删除的使用

需要在模型中进行设置

在这里插入图片描述
定义好模型后,我们就可以直接使用模型的删除方法


// 软删除
User::destroy(1);
// 真实删除
User::destroy(1,true);
$user = User::get(1);
// 软删除
$user->delete();
// 真实删除
$user->delete(true);

代码实操
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

3.2查询出携带软删除的数据

User::withTrashed()->find();
User::withTrashed()->select();

3.3只查询被软删除的数据

User::onlyTrashed()->find();
User::onlyTrashed()->select();

3.4id参数检测

因为一般我们删除数据都是通过主键ID进行删除的,所以我们需要对ID参数进行检测

        //id参数检测 要判断它是否是大于0的整数
        //不是数字 不是整数 小于等于0
        if(!is_numeric($id) || $id !=(int)$id || $id<=0){
            $this->error('参数错误');
        }
        //preg_match返回的是匹配次数,匹配到了就是1次,没有就是0次
        if(!preg_match('/^\d+$/',$id) || $id == 0){
            $this->error('参数错误');
        }

在这里插入图片描述

22、登录登出权限控制

1.封装密码加密函数

注意:后台管理员表tpshop_manager中 初始的管理员密码

密码要自己加密一个初始密码,更新到数据表

使用自定义的密码加密函数:

if (!function_exists('encrypt_password')) {

    function encrypt_password($password)
    {
        //加盐
        $salt = 'wewrrw';
        return md5(md5($password).$salt);
    }
}

在这里插入图片描述
任意找一个控制器,使用加密函数对一个自定义的初始密码进行加密输出。

  echo encrypt_password('123456');die();

在这里插入图片描述
在这里插入图片描述
将此加密后的密码,复制,修改到你的管理员表的passwod字段。
在这里插入图片描述

2、模板中使用请求参数

手册–模板–请求参数
模板支持直接输出Request请求对象的方法参数,用法如下:

格式

$Request.方法名.参数

例如

{$Request.get.id}
{$Request.param.name}

$Request.开头的变量输出会认为是系统Request请求对象的参数输出。
支持Request类的大部分方法,但只支持方法的第一个参数。
下面都是有效的输出:

// 调用Request对象的get方法 传入参数为id
{$Request.get.id}
// 调用Request对象的param方法 传入参数为name
{$Request.param.name}
// 调用Request对象的param方法 传入参数为user.nickname
{$Request.param.user.nickname}
// 调用Request对象的root方法
{$Request.root}
// 调用Request对象的root方法,并且传入参数true
{$Request.root.true}
// 调用Request对象的path方法
{$Request.path}
// 调用Request对象的module方法
{$Request.module}
// 调用Request对象的controller方法
{$Request.controller}
// 调用Request对象的action方法
{$Request.action}
// 调用Request对象的ext方法
{$Request.ext}
// 调用Request对象的host方法
{$Request.host}
// 调用Request对象的ip方法
{$Request.ip}
// 调用Request对象的header方法
{$Request.header.accept-encoding}

实际操作演示

        //临时关闭模板布局
        $this->view->engine->layout(false);
        return view();

在这里插入图片描述

模块名称{$Request.module} <br>
控制器名称{$Request.controller} <br>
方法{$Request.action} <br>

{$Request.get.id} <br>
{$Request.param.name} <br>
{$Request.host} <br>

在这里插入图片描述

在这里插入图片描述

3、TP中的cookie和session

手册–杂项–cookie,手册–杂项–session
TP框架提供了think\Cookie类和think\Session类分别操作cookie和session.
也可以使用助手函数cookie()和session()

3.1、session

3.1.1 初始化

在ThinkPHP5.0中使用\think\Session类进行Session相关操作,Session会在第一次调用Session类的时候按照配置的参数自动初始化,例如,我们在应用配置中添加如下配置:

'session'                => [
    'prefix'         => 'think',
    'type'           => '',
    'auto_start'     => true,
],

如果你应用下面的不同模块需要不同的session参数,那么可以在模块配置文件中重新设置:

'session'                => [
    'prefix'         => 'module',
    'type'           => '',
    'auto_start'     => true,
],

或者调用init方法进行初始化

Session::init([
    'prefix'         => 'module',
    'type'           => '',
    'auto_start'     => true,
]);

或者使用助手函数初始化

session([
    'prefix'     => 'module',
    'type'       => '',
    'auto_start' => true,
]);

一般情况下,我们是不需要改的

3.1.2赋值

// 赋值(当前作用域)
Session::set('name','thinkphp');
// 赋值think作用域
Session::set('name','thinkphp','think');

对应的助手函数

// 赋值(当前作用域)
session('name', 'thinkphp');
// 赋值think作用域
session('name', 'thinkphp', 'think');

3.1.3判断是否存在

// 判断(当前作用域)是否赋值
Session::has('name');
// 判断think作用域下面是否赋值
Session::has('name','think');

对应的助手函数

// 判断(当前作用域)是否赋值
session('?name');

3.1.4取值

如果name的值不存在,返回null

// 取值(当前作用域)
Session::get('name');
// 取值think作用域
Session::get('name','think');

对应的助手函数

// 取值(当前作用域)
session('name');

// 取值think作用域
session('name', '', 'think');

3.1.4删除

// 删除(当前作用域)
Session::delete('name');
// 删除think作用域下面的值
Session::delete('name','think');

对应的助手函数

// 删除(当前作用域)
session('name', null);

3.1.5清空

// 清除session(当前作用域)
Session::clear();
// 清除think作用域
Session::clear('think');

对应的助手函数

// 清除session(当前作用域)
session(null);

// 清除think作用域
session(null, 'think');

3.1.6指定作用域

// 指定当前作用域
Session::prefix('think');

3.1.7取值并删除

// 取值并删除
Session::pull('name');

3.1.8下次请求之前有效

// 设置session 并且在下一次请求之前有效
Session::flash('name','value');

3.1.9提前清除当前请求有效的数据

// 清除当前请求有效的session
Session::flush();

3.1.10、二级数组

支持session的二维数组操作,例如:


// 赋值(当前作用域)
Session::set('name.item','thinkphp');
// 判断(当前作用域)是否赋值
Session::has('name.item');
// 取值(当前作用域)
Session::get('name.item');
// 删除(当前作用域)
Session::delete('name.item');

3.2、cookie

ThinkPHP采用think\Cookie类提供Cookie支持。

如果使用默认配置,无需任何操作就可以直接调用Cookie类的相关方法

支持的参数和默认值如下


// cookie 名称前缀
'prefix'    => '',
// cookie 保存时间
'expire'    => 0,
// cookie 保存路径
'path'      => '/',
// cookie 有效域名
'domain'    => '',
//  cookie 启用安全传输
'secure'    => false,
// httponly设置
'httponly'  => '',
// 是否使用 setcookie
'setcookie' => true,


注:和session的区别就只是多了一个有效期的设置,其它都是一样的

3.2.1、初始化操作

// cookie初始化
2.Cookie::init(['prefix'=>'think_','expire'=>3600,'path'=>'/']);
3.// 指定当前前缀
4.Cookie::prefix('think_');

对应的助手函数

// 初始化
cookie(['prefix' => 'think_', 'expire' => 3600]);

3.2.2、设置


// 设置Cookie 有效期为 3600秒
Cookie::set('name','value',3600);
// 设置cookie 前缀为think_
Cookie::set('name','value',['prefix'=>'think_','expire'=>3600]);
// 支持数组
Cookie::set('name',[1,2,3]);


助手函数

// 设置
cookie('name', 'value', 3600);

3.2.3、获取

Cookie::get('name');
// 获取指定前缀的cookie值
Cookie::get('name','think_');

助手函数

// 获取
echo cookie('name');

3.2.4、删除

Cookie::delete('name');
// 删除指定前缀的cookie
Cookie::delete('name','think_');

助手函数

// 删除
cookie('name', null);

3.2.5、清空

// 清空指定前缀的cookie
Cookie::clear('think_');

助手函数

// 清空指定前缀的cookie
cookie(null, 'think_');

4、完成后台的登录功能

需要创建Manager模型:

命令行方式:

 php think make:model admin/Manager

思路:

①表单展示

②表单中的name属性值、提交地址

③提交的控制器方法中,接收数据

④查询用户表 验证用户名和密码

⑤用户名和密码正确,设置登录标识到session 跳转到后台首页

⑥用户名或密码错误,报错,返回登录页面

下面是实际操作:

在这里插入图片描述

因为现在提交地址和展示模板的地址是同一个,所以需要判断是否提交过来数据,在原生的php表单提交中,我们是通过判断$_POST[]是否为空来提交了数据

在TP框架中已经封装了来判断请求方式的方法,手册-请求-请求类型

在这里插入图片描述

    //登录
    public function login(){

        if(request()->isPost()){
            //接收参数,接收的时候已经默认调用过trim方法了,配置文件里面
            $params = input();
            //表单验证,这里就简单验证是否填写
            $rule = [
                'username|用户名'=>'require',
                'password|密码'=>'require',
                'code|验证码'=>'require',
            ];
            $res = $this->validate($params,$rule);
            if($res !== true){
                $this->error($res);
            }
            //查询管理员用户名,进行比对
            //比对方式有两种,可以先 根据用户名查询出一条数据,再比对密码  第二种 直接把用户名和密码当作条件直接一起查询
            $manager = Manager::where('username',$params['username'])->where('password',encrypt_password($params['password']))->find();

            //批量条件
            //条件
//            $where = [
//                'username'=>$params['username'],
//                'password'=>$params['password'],
//            ];
//            $manager = Manager::where($where)->find();

            if($manager){
                //登录成功
                //设置登录标志到session
                session('manger_info',$manager->toArray());
                $this->success('登录成功','admin/index/index');
            }else{
                //用户名或者密码错误
                $this->error('用户名或者密码错误');
            }

        }else{
            $this->view->engine->layout(false);
            return view();
        }

    }

在这里插入图片描述

5、完成后台的登出功能

在这里插入图片描述

    //退出功能
    public function logout(){
        //清空session
        session(null);
        //跳转到登录页面
        $this->redirect('admin/login/login');

    }

在这里插入图片描述

6、后台页面权限控制(越权访问–翻墙)

①在Admin模块Controller目录,新增一层Base控制器

php think make:controller admin/Base --plain

session(‘?name’) 表示 判断session中是否设置name,返回值是true和false;

    public function __construct(Request $request = null)
    {
        //实现父类的构造函数
        parent::__construct($request);
        //登录检测
        if(!session('?manger_info')){
            //没登陆
            $this->redirect('admin/login/login');
        }
    }

在这里插入图片描述

②所有后台其他的控制器都需要继承Base控制器(Login控制器例外

比如Index控制器、Goods控制器等

在这里插入图片描述
在这里插入图片描述

注:相同命名空间下的类,互相访问时,可以不用携带命名空间。

如果Login控制器也继承了Base控制器就会发生重定向次数过多
在这里插入图片描述

23、验证码技术

1、使用验证码的步骤

①生成验证码图片,展示在页面上

②点击图片刷新验证码功能

③提交表单后验证码的校验

2、TP中的验证码使用

手册–杂项–验证码

2.1验证码的配置

在这里插入图片描述

常参考的配置

'captcha'  => [
        // 验证码字符集合
        'codeSet'  => '2345678abcdefhijkmnpqrstuvwxyzABCDEFGHJKLMNPQRTUVWXY', 
        // 验证码字体大小(px)
        'fontSize' => 25, 
        // 是否画混淆曲线
        'useCurve' => true, 
         // 验证码图片高度
        'imageH'   => 30,
        // 验证码图片宽度
        'imageW'   => 100, 
        // 验证码位数
        'length'   => 5, 
        // 验证成功后是否重置        
        'reset'    => true
],

改自己想改的配置

    'captcha'  => [
        // 验证码位数
        'length'   => 4,
        // 是否画混淆曲线
        'useCurve' => false,
        //杂点
        'useNoise' => false,

    ],

在这里插入图片描述

2.2验证码显示

<div>{:captcha_img()}</div>
<div><img src="{:captcha_src()}" alt="captcha" /></div>

上面两种的最终效果是一样的,根据需要调用即可。

2.3点击验证码更换图片和增加鼠标手势

在这里插入图片描述

   <img class="pull-right" src="{:captcha_src()}" onclick="this.src='{:captcha_src()}?'+Math.random()" style="cursor: pointer">

2.4控制器验证

使用TP5的内置验证功能,添加captcha验证规则即可

$this->validate($data,[
    'captcha|验证码'=>'require|captcha'
]);

在这里插入图片描述

在这里插入图片描述

或者手动验证

if(!captcha_check($captcha)){
 //验证失败
};

在这里插入图片描述

剩余部分

https://blog.csdn.net/ljh101/article/details/113090876
已标记关键词 清除标记
相关推荐
©️2020 CSDN 皮肤主题: 撸撸猫 设计师:C马雯娟 返回首页