海上风电信息化


ThinkPHP8.xx

<h1>01. phpEnv配置安装</h1> <p>&lt;div style=&quot;text-align:right;color:#666;font-size:20px;&quot;&gt;主讲老师 - 李炎恢&lt;/div&gt;</p> <h3>1. 学习基础</h3> <ul> <li>ThinkPHP8.x: <ul> <li>前端基础:HTML5/CSS(必须)、JavaScript(可选、但推荐有);</li> <li>后端基础:PHP基础,版本不限,但不能太老,至少PHP5.4以上语法,TP8是兼容PHP8.x的;</li> <li>数据库基础:MySQL数据库,掌握了常规的SQL语句。</li> <li>编码思维基础:MVC、MVVM、设计模式(单例、观察者等)有简单认知即可;</li> </ul></li> </ul> <h3>2. 软件获取</h3> <ul> <li>phpEnv:</li> <li> <p>官方网站:<a href="https://www.phpenv.cn/">https://www.phpenv.cn/</a> (专业优雅强大的PHP集成环境);</p> <ul> <li>下载最新版本,自动安装后(默认C盘,可选),界面如下:</li> </ul> <p>&lt;img src=&quot;ThinkPHP8.x.assets/01-1.jpg&quot; style=&quot;zoom:80%;margin:0&quot; /&gt;</p> </li> <li> <p>简单配置:</p> <ul> <li> <p>应用软件-&gt;设置-&gt;开启CDN加速(方便我们后续安装各种软件);</p> </li> <li> <p>安装 PHP8.2 和 MySQL8 ,选择 Apache (个人向,教学方便);</p> </li> <li> <p>然后点击 启动服务 ,允许各种允许访问即可;</p> </li> <li>在浏览器输入:localhost,即可访问PHP探针。</li> </ul> <p>&lt;img src=&quot;ThinkPHP8.x.assets/01-2.jpg&quot; style=&quot;zoom:80%;margin:0&quot; /&gt;</p> </li> <li> <p>创建站点:</p> <ul> <li> <p>点击 主页 下 网站,添加一个虚拟网站,以便后续学习测试;</p> </li> <li> <p>可以选择自定义的目录,我教学方便,就默认了;</p> </li> <li> <p>添加后,会写入hosts,这样我们输入 www.tp.com 域名后就可以访问了;</p> </li> <li>默认会给你一个index.php,显示结果为:php8.2 info</li> </ul> <p>&lt;img src=&quot;ThinkPHP8.x.assets/01-3.jpg&quot; style=&quot;zoom:80%;margin:0&quot; /&gt;</p> </li> </ul> <h1>02. ThinkPHP8.x配置安装</h1> <p>&lt;div style=&quot;text-align:right;color:#666;font-size:20px;&quot;&gt;主讲老师 - 李炎恢&lt;/div&gt;</p> <h3>1. 8.x安装</h3> <ul> <li> <p>主要特性:(来自手册)</p> <ul> <li>支持PHP8强类型、支持6.x无缝升级、语义化版本策略、升级PSR规范依赖版本;</li> </ul> </li> <li>安装方式: <ul> <li>仅在windows教学,Linux或其它平台对照手册执行即可;</li> <li>键盘:win + R,输入cmd,输入composer,判断是否已经安装;</li> <li>如果没有安装composer,则:<a href="https://getcomposer.org/Composer-Setup.exe">https://getcomposer.org/Composer-Setup.exe</a> (来自手册);</li> <li>切换至你项目的根目录,比如第一节课创建的 www.tp.com 文件夹的上一层 www;</li> <li>输入安装命令:composer create-project topthink/think www.tp.com;</li> <li>注意:被安装的文件夹必须是空的,先要删除里面的内容;</li> <li>各种超时,可以先修改成国内源,比如阿里:</li> <li>composer config -g repo.packagist composer <a href="https://mirrors.aliyun.com/composer/">https://mirrors.aliyun.com/composer/</a></li> <li>查看是否成功:composer config -g -l </li> </ul></li> </ul> <h3>2. 启动程序</h3> <ul> <li> <p>IDE载入</p> <ul> <li>开发工具任意,因为我们在浏览器测试即可,我这里选择了phpStorm,备选如下:</li> <li>VS Code</li> <li>sublime Text4</li> <li>Zend Stduio</li> <li>载入项目后,在IDE的终端输入内置服务器命令:php think run,启动Web服务;</li> <li>访问方式为:www.tp.com:8000 ,默认端口8000,当然也有80端口,不过被占用了;</li> <li>此时,我们发现,phpEnv还没启动呢,怎么就可以访问了呢?</li> <li>官方手册 -&gt; 命令行 -&gt; 启动内置服务器,有讲,这是内置的Web服务器,其它服务没有;</li> <li>所以学习使用时,推荐开启着,比如数据库连接等服务还需要。</li> </ul> </li> <li> <p>删除广告</p> <ul> <li>ThinkPHP8.x目前非常的商业化,打开后,广告糊一脸,我们先把这个去掉。</li> <li>在app/controller/index.php中的index方法,自定义return结果即可。</li> <li>或者执行phpinfo()函数,来检测php版本。</li> </ul> </li> <li>配色问题 <ul> <li>我个人开发学习,都是用的深色背景,明亮代码,一般开发工具都是默认这个样式;</li> <li>也推荐学习者,也用这个默认或差不过的样式,用于保护眼睛和缓解视觉疲劳;</li> <li>但如果讲课,我一般采用的都是亮色背景,原因如下:</li> <li>场景切换:如果是深色,切换到亮色界面,对学习者那么一闪,暴击效果显著;</li> <li>专注力:深色的背景,更加容易让听课者昏睡,注意力不集中;</li> <li>上课时长:每节课10分钟上下,并不会太疲劳,自己长时间开发用深色;</li> </ul></li> </ul> <h1>03. 编码规范.目录.配置</h1> <p>&lt;div style=&quot;text-align:right;color:#666;font-size:20px;&quot;&gt;主讲老师 - 李炎恢&lt;/div&gt;</p> <h3>1. 编码规范</h3> <ul> <li>完全版参考手册,这里说重点: <ul> <li>TP8遵循PSR-2命名规范、PSR-4自动加载规范;</li> <li>类名和文件名保持一致,驼峰式命名(首字母大写)如:Index,BaseController</li> <li>方法和函数名用驼峰式命名(首字母小写)如:index(),hello()</li> <li>数据表和字段用蛇式命名(两个单词中间下划线)如:think_name,user_name</li> <li>更多对照手册</li> </ul></li> </ul> <h3>2. 目录结构</h3> <ul> <li> <p>对于初学者,一个个说是干啥的,没有意义,这里说重点:</p> <ul> <li>app目录是应用目录,我们开发程序就在这个目录</li> <li>config是配置目录,顾名思义,配置程序状态</li> <li>public是公共目录,对外访问目录,运行程序默认执行此目录的index.php</li> <li>剩下的,后续学到一个,讲一个。</li> </ul> </li> </ul> <h3>3. 配置定义</h3> <ul> <li>默认情况下,程序出错会显示:页面出错!请稍候再试~</li> <li>这种情况,一般是应用部署好后,万一出错给用户看的;</li> <li> <p>如果我们自己在开发阶段,需要开启调试模式,来提示具体的错误信息:</p> <ul> <li>在根目录有一个文件:.example.env,改成 .env ,也就是去掉点前面;</li> <li>然后在配置信息的第一行:APP_DEBUG = true 即可,false则不开启。</li> </ul> </li> <li>调试模式开启后,可以发现右下角会出现trace调试工具小图标: <ul> <li>包含了丰富的调试内容:具体自点查看。</li> </ul></li> </ul> <h1>04. URL访问模式</h1> <p>&lt;div style=&quot;text-align:right;color:#666;font-size:20px;&quot;&gt;主讲老师 - 李炎恢&lt;/div&gt;</p> <h3>1. 单应用URL</h3> <pre><code class="language-php">http://serverName/index.php/控制器/操作/参数/值…</code></pre> <ul> <li> <p>注意:这里服务器启动是 php think run 的内置服务器,下节课会探讨外置服务器;</p> </li> <li> <p>结构分析:</p> <ul> <li> <p>serverName就是我们的:www.tp.com:8000;</p> </li> <li> <p>index.php 是入口文件,带上 / ;</p> </li> <li> <p>控制器是app\controller\Index.php中的 Index 这个名称,也就是类名;</p> </li> <li> <p>操作是类里面的方法名,比如:index(默认方法),hello(普通方法);</p> </li> <li> <p>默认方法可以省略,会直接方法,其他普通方法需要键入方法名:</p> </li> <li><a href="http://www.tp.com:8000/index.php/Index">http://www.tp.com:8000/index.php/Index</a> (默认执行index操作)</li> <li><a href="http://www.tp.com:8000/index.php/Index/index">http://www.tp.com:8000/index.php/Index/index</a> (完整路径)</li> <li> <p><a href="http://www.tp.com:8000/index.php/Index/test">http://www.tp.com:8000/index.php/Index/test</a> (普通方法,必须完整路径)</p> </li> <li> <p>系统默认自带的hello方法,是针对后续路由课程的,在路由文件设置过导致无效;</p> </li> <li> <p>我们在config/app.php中将路由关闭:&quot;with_route&quot; =&gt; false,</p> </li> <li><a href="http://www.tp.com:8000/index.php/Index/hello">http://www.tp.com:8000/index.php/Index/hello</a> (执行默认参数值)</li> <li> <p><a href="http://www.tp.com:8000/index.php/Index/hello/name/World(修改参数值">http://www.tp.com:8000/index.php/Index/hello/name/World(修改参数值</a>)</p> </li> <li> <p>参数不够直观,尤其多参数的时候,也是支持传统方案的:</p> </li> <li><a href="http://www.tp.com:8000/index.php/Index/hello?name=World">http://www.tp.com:8000/index.php/Index/hello?name=World</a> (问号键值对)</li> </ul> </li> </ul> <h3>2. 多应用URL</h3> <pre><code class="language-php">http://serverName/index.php/应用/控制器/操作/参数/值…</code></pre> <ul> <li>如果开启多应用的话,URL比单应用多一个 应用 路径,其它一致;</li> <li>由于我们教学,都在单应用上,暂时不刻意演示,如果后续有机会,放到最后;</li> </ul> <h1>05. 内.外置服务器</h1> <p>&lt;div style=&quot;text-align:right;color:#666;font-size:20px;&quot;&gt;主讲老师 - 李炎恢&lt;/div&gt;</p> <h3>1. 启动内置</h3> <ul> <li>在手册命令行 -&gt; 启动内置服务器,有 php think run 启动的服务器介绍;</li> <li>启动后直接输入:127.0.0.1:8000 或 localhost:8000 或 www.tp.com:8000 访问;</li> <li>停止内置服务器,在命令行使用 ctrl + c</li> </ul> <h3>2. 启动phpEnv</h3> <ul> <li>不管是本地的外置服务器集成环境phpEnv,还是以后要部署到远程服务器,都需要配置;</li> <li>这里需要配置的重点就是伪静态,我们不启动内置服务器,只用外置访问试试;</li> <li>注意:这里外置服务器,在第一课我们已经创建了 端口为 80 的 www.tp.com;</li> <li> <p>现在,直接访问试试?但出现了如下图的错误:</p> </li> <li>我们在 www.tp.com 目录下创建一个index.html或index.php索引文件,访问后:</li> </ul> <h3>3. 配置目录</h3> <ul> <li>在第一节课,我们创建的启动目录是 www.tp.com ,但目前知道这个目录下没有 index.php;</li> <li>在手册的 基础 -&gt; 目录结构 中 public 目录 解释为:WEB目录(对外访问目录);</li> <li>并规范到:在实际项目部署中,确保只将 public 对外访问;</li> <li>所以,我们将phpEnv站点配置目录设置为:www.tp.com/pubic 即可;</li> <li>至于http.conf、伪静态和.htaccess等配置信息,默认情况下支持都用,后续需要配置再说;</li> </ul> <h1>06. 控制器的定义</h1> <p>&lt;div style=&quot;text-align:right;color:#666;font-size:20px;&quot;&gt;主讲老师 - 李炎恢&lt;/div&gt;</p> <h3>1. 定义方式</h3> <ul> <li> <p>控制器:顾名思义MVC中的C,即逻辑控制定义;</p> </li> <li> <p>默认在app\controller下编写对应的控制器类文件,如果想改默认目录:</p> <pre><code class="language-php">// 访问控制器层名称 &amp;quot;controller_layer&amp;quot; =&amp;gt; &amp;quot;controller&amp;quot;,</code></pre> </li> <li> <p>类名和文件名大小写保持一致,并采用驼峰式(首字母大写);</p> <pre><code class="language-php">// app\controller\User.php namespace app\controller; class User { public function index() { return &amp;quot;用户&amp;quot;; } public function login() { return &amp;quot;登录成功!&amp;quot;; } }</code></pre> <ul> <li>User类创建两个方法 index(默认)和 login,访问 URL 如下:</li> <li><a href="http://www.tp.com:8000/Index.php/user/">http://www.tp.com:8000/Index.php/user/</a></li> <li><a href="http://www.tp.com:8000/Index.php/user/login">http://www.tp.com:8000/Index.php/user/login</a></li> </ul> </li> <li> <p>那么如果创建的是双字母组合,比如 class HelloWorld,访问 URL 如下:</p> </li> <li> <p><a href="http://www.tp.com:8000/Index.php/helloworld">http://www.tp.com:8000/Index.php/helloworld</a></p> </li> <li> <p><a href="http://www.tp.com:8000/Index.php/hello_world">http://www.tp.com:8000/Index.php/hello_world</a></p> <pre><code class="language-php">namespace app\controller; class HelloWorld { public function index() { return &amp;quot;index&amp;quot;; } }</code></pre> </li> </ul> <h3>2. URL重写</h3> <ul> <li> <p>URL重写可以省去 index.php 入口文件的键入,默认情况下内置服务器支持重写;</p> <p><a href="http://www.tp.com:8000/User">http://www.tp.com:8000/User</a></p> </li> <li> <p>而外置服务器,比如phpEnv,省略了入口文件,则出现如下问题:</p> <p>&lt;img src=&quot;ThinkPHP8.x.assets/image-20231008153530630.png&quot; alt=&quot;image-20231008153530630&quot; style=&quot;zoom:80%;margin:0&quot; /&gt;</p> </li> <li> <p>查看手册,根据它URL重写的修改方案(Apache),需要修改.htaccess最后一行:</p> <pre><code class="language-php">#RewriteRule ^(.*)$ index.php/$1 [QSA,PT,L] Apache替换成下面一行 RewriteRule ^(.*)$ index.php [L,E=PATH_INFO:$1]</code></pre> <p>&lt;img src=&quot;ThinkPHP8.x.assets/image-20231008161340527.png&quot; alt=&quot;image-20231008161340527&quot; style=&quot;zoom:80%;margin:0&quot; /&gt;</p> </li> <li>备注:不同的环境、服务器等等都会有千奇百怪的问题,努力搜索解决即可;</li> <li>如果实在解决不了,请就用 php think run 内置服务器就了,省事。</li> <li>到时候部署到真实服务器环境,再折腾。。。</li> </ul> <h3>3. 配置渲染</h3> <ul> <li> <p>如果你想避免引入同类名时的冲突,可以 config\route.php 设置控制器后缀:</p> <pre><code class="language-php">// 是否使用控制器后缀 // 此时,User.php 就必须改成 UserController.php,并类名也需要增加后缀 &amp;quot;controller_suffix&amp;quot; =&amp;gt; true,</code></pre> </li> <li> <p>ThinkPHP 直接采用方法内 return 返回的方式直接就输出了;</p> </li> <li> <p>如果需要使用 json 输出,直接采用 json 函数;</p> <pre><code class="language-php">// json输出,不同浏览器美化样式不同,我这里用的FireFox public function json() { return json([&amp;quot;name&amp;quot; =&amp;gt; &amp;quot;王二狗&amp;quot;, &amp;quot;age&amp;quot; =&amp;gt; 25, &amp;quot;gender&amp;quot; =&amp;gt; &amp;quot;男&amp;quot;]); }</code></pre> </li> <li> <p>不推荐使用 die、exit 等 PHP 方法中断代码执行,推荐助手函数 halt();</p> <pre><code class="language-php">halt(&amp;quot;中断测试&amp;quot;);</code></pre> </li> </ul> <h1>07. 基础和空控制器</h1> <p>&lt;div style=&quot;text-align:right;color:#666;font-size:20px;&quot;&gt;主讲老师 - 李炎恢&lt;/div&gt;</p> <h3>1. 基础控制器</h3> <ul> <li> <p>一般来说,创建控制器后,推荐继承基础控制器来获得更多的功能方法;</p> </li> <li> <p>基础控制器仅仅提供了控制器验证功能,并注入了think\App和think\Request;</p> </li> <li> <p>这两个对象后面会有章节详细讲解,下面我们继承并简单使用一下;</p> <pre><code class="language-php">namespace app\controller; use app\BaseController; class User extends BaseController { public function index() { // 返回实际路径 return $this-&amp;gt;app-&amp;gt;getBasePath(); // 返回当前方法名 return $this-&amp;gt;request-&amp;gt;action(); } }</code></pre> </li> </ul> <h3>2. 空控制器</h3> <ul> <li> <p>空控制器一般用于载入不存在的控制器时,进行错误提示;</p> <pre><code class="language-php">class Error { public function __call(string $name, array $arguments) { return &amp;quot;当前控制器不存在!&amp;quot;; } }</code></pre> </li> </ul> <h1>08. 创建数据表及填充</h1> <p>&lt;div style=&quot;text-align:right;color:#666;font-size:20px;&quot;&gt;主讲老师 - 李炎恢&lt;/div&gt;</p> <h3>1. 创建数据表</h3> <ul> <li> <p>我们直接使用phpEnv自带的MySQL操作软件:HeidiSQL,简称HS;</p> </li> <li> <p>登录的时候,注意修改root和密码后,保存,下次方可直接打开;</p> </li> <li> <p>首先,我们创建一个数据库:demo,用于测试:</p> <p>&lt;img src=&quot;ThinkPHP8.x.assets/image-20231009153158426.png&quot; alt=&quot;image-20231009153158426&quot; style=&quot;zoom:80%;margin:0;&quot; /&gt;</p> </li> </ul> <h3>2. 创建用户表</h3> <ul> <li> <p>设置好数据库后,我们创建一个user表,包含id、name、age、gender、details等字段;</p> <p>&lt;img src=&quot;ThinkPHP8.x.assets/image-20231009154005270.png&quot; alt=&quot;image-20231009154005270&quot; style=&quot;zoom:80%;margin:0&quot; /&gt;</p> </li> <li> <p>然后,我们填充一些数据,方便查询测试:</p> <p>&lt;img src=&quot;ThinkPHP8.x.assets/image-20231009154404157.png&quot; alt=&quot;image-20231009154404157&quot; style=&quot;zoom:80%;margin:0&quot; /&gt;</p> </li> <li> <p>最后,我们通过SQL语句来测试一下:</p> <p>&lt;img src=&quot;ThinkPHP8.x.assets/image-20231009154542782.png&quot; alt=&quot;image-20231009154542782&quot; style=&quot;zoom:80%;margin:0&quot; /&gt;</p> </li> </ul> <h1>09. 连接数据库和查询</h1> <p>&lt;div style=&quot;text-align:right;color:#666;font-size:20px;&quot;&gt;主讲老师 - 李炎恢&lt;/div&gt;</p> <h3>1. 连接数据库</h3> <ul> <li> <p>我们可以在 <strong>config\database.php</strong> 配置文件中设置与数据库的连接信息:</p> <ul> <li> <p>如果是一般性数据库连接,在 <strong>‘’connections‘’</strong> 配置区设置即可;</p> </li> <li>如果是本地测试,它会优先读取 <strong>.env</strong> 配置,然后再读取 <strong>database.php</strong> 的配置;</li> </ul> <pre><code># .env文件,部署服务器,请禁用我 APP_DEBUG = true DB_TYPE = mysql DB_HOST = 127.0.0.1 DB_NAME = demo DB_USER = root DB_PASS = 123456 DB_PORT = 3306 DB_CHARSET = utf8 DEFAULT_LANG = zh-cn</code></pre> <ul> <li>如果禁用了 .env 配置,则会读取数据库连接的默认配置:</li> </ul> <pre><code class="language-php">// 数据库连接配置信息 &amp;quot;connections&amp;quot; =&amp;gt; [ &amp;quot;mysql&amp;quot; =&amp;gt; [ // 数据库类型 &amp;quot;type&amp;quot; =&amp;gt; env(&amp;quot;DB_TYPE&amp;quot;, &amp;quot;mysql&amp;quot;), // 服务器地址 &amp;quot;hostname&amp;quot; =&amp;gt; env(&amp;quot;DB_HOST&amp;quot;, &amp;quot;127.0.0.1&amp;quot;), // 数据库名 &amp;quot;database&amp;quot; =&amp;gt; env(&amp;quot;DB_NAME&amp;quot;, &amp;quot;demo&amp;quot;), // 用户名 &amp;quot;username&amp;quot; =&amp;gt; env(&amp;quot;DB_USER&amp;quot;, &amp;quot;root&amp;quot;), // 密码 &amp;quot;password&amp;quot; =&amp;gt; env(&amp;quot;DB_PASS&amp;quot;, &amp;quot;123456&amp;quot;), // 端口 &amp;quot;hostport&amp;quot; =&amp;gt; env(&amp;quot;DB_PORT&amp;quot;, &amp;quot;3306&amp;quot;),</code></pre> </li> </ul> <h3>2. PHP获取数据</h3> <ul> <li> <p>我们暂时没有详细学习此类语法,可以简单用一些了解一下即可:</p> <pre><code class="language-php">// 引入Db数据库类 use think\facade\Db; class User extends BaseController { public function get() { // 连接user表,查询 $user = Db::table(&amp;quot;user&amp;quot;)-&amp;gt;select(); // 输出数据 return json($user); } }</code></pre> </li> </ul> <h1>10. 构造器之数据查询</h1> <p>&lt;div style=&quot;text-align:right;color:#666;font-size:20px;&quot;&gt;主讲老师 - 李炎恢&lt;/div&gt;</p> <h3>1. table方法</h3> <ul> <li> <p>Db类旗下有一个 <strong>table</strong> 静态调用的方法,参数为完整的表名(前缀都不能省略);</p> </li> <li> <p>如果希望只查询一条数据,可以使用 <strong>find()</strong> 方法,需指定 <strong>where</strong> 条件:</p> <pre><code class="language-php">// 通过ID查询指定的数据 // find 方法查询结果不存在,返回 null,否则返回结果数组 $user = Db::table(&amp;quot;user&amp;quot;)-&amp;gt;where(&amp;quot;id&amp;quot;, 1)-&amp;gt;find();</code></pre> </li> <li> <p>想要了解执行的原生SQL是什么,可以注释掉 return 直接通过 trace 查看;</p> </li> <li> <p>使用 <strong>findOrEmpty()</strong> 方法也可以查询一条数据,但在没有数据时返回一个空数组:</p> <pre><code class="language-php">// 没有数据返回空数组 $user = Db::table(&amp;quot;user&amp;quot;)-&amp;gt;where(&amp;quot;id&amp;quot;, 11)-&amp;gt;findOrEmpty();</code></pre> </li> <li> <p>使用 <strong>findOrFail()</strong> 方法同样可以查询一条数据,在没有数据时抛出一个异常:</p> <pre><code class="language-php">// 没有数据抛出异常 $user = Db::table(&amp;quot;user&amp;quot;)-&amp;gt;where(&amp;quot;id&amp;quot;, 11)-&amp;gt;findOrFail();</code></pre> </li> <li> <p>想要获取多列数据,可以使用 <strong>select()</strong> 方法:</p> <pre><code class="language-php">// 查询所有数据 $user = Db::table(&amp;quot;user&amp;quot;)-&amp;gt;select();</code></pre> </li> <li> <p><strong>select()</strong> 方法默认返回 <strong>Collection</strong> 对象的数据集,可以通过 <strong>toArray()</strong> 方法转换成数组:</p> <pre><code class="language-php">// 用中断函数,来检测返回值 $user = Db::table(&amp;quot;user&amp;quot;)-&amp;gt;select(); halt($user); // 转换成数组 $user = Db::table(&amp;quot;user&amp;quot;)-&amp;gt;select()-&amp;gt;toArray(); halt($user);</code></pre> </li> <li> <p>多列数据也可以参与 where() 方法的筛选:</p> <pre><code class="language-php">// 多列筛选 $user = Db::table(&amp;quot;user&amp;quot;)-&amp;gt;where(&amp;quot;age&amp;quot;, 14)-&amp;gt;select();</code></pre> </li> </ul> <h3>2. 链式查询</h3> <ul> <li>我们发现通过指向符号 “-&gt;” 多次连续调用方法称为:链式查询;</li> <li>当 Db::table(&quot;user&quot;) 时,返回查询对象(Query),即可连缀数据库对应的方法;</li> <li>当返回查询对象(Query)时,就可以继续调用链式方法,where() 也是链式方法;</li> <li>而 where() 被调用后,依旧返回(Query),可以再次链式调用;</li> <li>在手册 <strong>数据库 -&gt; 查询构造器 -&gt; 链式操作</strong> 可以了解所有可链式的方法:table、where等;</li> <li>直到遇到 find() 或 select() 返回数组或数据集时,结束查询;</li> </ul> <h1>11. 表前缀之扩展查询</h1> <p>&lt;div style=&quot;text-align:right;color:#666;font-size:20px;&quot;&gt;主讲老师 - 李炎恢&lt;/div&gt;</p> <h3>1. 表前缀</h3> <ul> <li> <p>一般来说,为了保持表名统一性和防止冲突,都会给表加上一个前缀,以下划线结束;</p> <ul> <li> <p>比如:<strong>tp_user</strong>,这里的 <strong>tp_</strong> 就是表前缀,所有;</p> </li> <li> <p>我们修改MySQL中表名,然后刷新程序,报错;</p> </li> <li>当然,你可以传递 <strong>Db::table(&quot;tp_user&quot;)</strong>,但没必要;</li> </ul> </li> <li> <p>首先,我们可以来配置统一前缀:</p> <ul> <li> <p>在 .env 文件中 添加:DB<em>PREFIX = tp</em></p> </li> <li>如果部署环境 database.php 中 设置</li> </ul> <pre><code class="language-php">&amp;quot;prefix&amp;quot; =&amp;gt; env(&amp;quot;DB_PREFIX&amp;quot;, &amp;quot;tp_&amp;quot;),</code></pre> </li> <li> <p>然后,使用 <strong>Db::name(&quot;user&quot;)</strong> 方法即可:</p> <pre><code class="language-php">// 此时,tp_ 表名的前缀可以省略 $user = Db::name(&amp;quot;user&amp;quot;)-&amp;gt;select();</code></pre> </li> </ul> <h3>2. 扩展查询</h3> <ul> <li> <p>通过 <strong>value()</strong> 方法,可以查询指定字段的值(单个),没有数据返回 <strong>null</strong> ;</p> <pre><code class="language-php">// value() 方法查询单个列值 $user = Db::name(&amp;quot;user&amp;quot;)-&amp;gt;where(&amp;quot;id&amp;quot;, 3)-&amp;gt;value(&amp;quot;name&amp;quot;);</code></pre> </li> <li> <p>通过 <strong>colunm()</strong> 方法,可以查询指定列的值(多个),没有数据返回空数组;</p> <pre><code class="language-php">// colunm() 方法查询多个列值 $user = Db::name(&amp;quot;user&amp;quot;)-&amp;gt;column(&amp;quot;name&amp;quot;); // 通过id 作为索引 $user = Db::name(&amp;quot;user&amp;quot;)-&amp;gt;column(&amp;quot;name,age&amp;quot;, &amp;quot;id&amp;quot;);</code></pre> </li> <li> <p>当大量数据需要 <strong>批处理</strong> 时,比如给所有用户更新数据,就不能一次性全取出来,一批一批的来;</p> <pre><code class="language-php">// 批量处理 Db::name(&amp;quot;user&amp;quot;)-&amp;gt;chunk(2, function ($users) { foreach ($users as $user) { dump($user); } echo 1; }); // 通过获取最后的SQL语句,发现用的是LIMIT 2 return Db::getLastSql();</code></pre> </li> <li> <p>另一种处理大量数据:<strong>游标查询</strong>,为了解决内存开销,每次读取一行,并返回到下一行再读取;</p> <pre><code class="language-php">// 批量处理2 $users = Db::name(&amp;quot;user&amp;quot;)-&amp;gt;cursor(); // PHP生成器 // halt($user); foreach ($users as $user) { dump($user); }</code></pre> </li> </ul> <h1>12. 数据的新增方式</h1> <p>&lt;div style=&quot;text-align:right;color:#666;font-size:20px;&quot;&gt;主讲老师 - 李炎恢&lt;/div&gt;</p> <h3>1. 单条新增</h3> <ul> <li> <p>使用 <strong>insert()</strong> 方法可以向数据表添加一条数据,更多的字段采用默认;</p> <pre><code class="language-php">// 数据 $data = [ &amp;quot;name&amp;quot; =&amp;gt; &amp;quot;张麻子&amp;quot;, &amp;quot;age&amp;quot; =&amp;gt; 28, &amp;quot;gender&amp;quot; =&amp;gt; &amp;quot;男&amp;quot;, &amp;quot;details&amp;quot; =&amp;gt; &amp;quot;我脸上没有麻子!&amp;quot; ]; // 单条新增,成功返回1 return Db::name(&amp;quot;user&amp;quot;)-&amp;gt;insert($data);</code></pre> </li> <li> <p>如果想强行新增抛弃不存在的字段数据,则使用 <strong>strick(false)</strong> 方法,忽略异常;</p> <pre><code class="language-php">// 数据 $data = [ &amp;quot;name&amp;quot; =&amp;gt; &amp;quot;马邦德&amp;quot;, &amp;quot;age&amp;quot; =&amp;gt; 30, &amp;quot;gender&amp;quot; =&amp;gt; &amp;quot;男&amp;quot;, &amp;quot;deta&amp;quot; =&amp;gt; &amp;quot;我脸上没有麻子!&amp;quot; ]; // 单条新增,成功返回1 return Db::name(&amp;quot;user&amp;quot;)-&amp;gt;strict(false)-&amp;gt;insert($data);</code></pre> </li> <li> <p>如果我们采用的数据库是 mysql,可以支持 <strong>replace</strong> 写入;</p> </li> <li> <p>insert 和 replace insert 写入的区别,前者表示表中存在主键相同则报错,后者则修改;</p> <pre><code class="language-php">// 新增数据时,主键冲突时,直接修改这条记录 Db::name(&amp;quot;user&amp;quot;)-&amp;gt;replace()-&amp;gt;insert($data);</code></pre> </li> <li> <p>使用 <strong>insertGetId()</strong> 方法,可以在新增成功后返回当前数据 ID;</p> <pre><code class="language-php">// 返回自增ID return Db::name(&amp;quot;user&amp;quot;)-&amp;gt;replace()-&amp;gt;insertGetId($data);</code></pre> </li> </ul> <h3>2. 多条新增</h3> <ul> <li> <p>使用 <strong>insertAll()</strong> 方法,可以批量新增数据,但要保持数组结构一致;</p> <pre><code class="language-php">// 数据 $data = [[ &amp;quot;name&amp;quot; =&amp;gt; &amp;quot;林克&amp;quot;, &amp;quot;age&amp;quot; =&amp;gt; 19, &amp;quot;gender&amp;quot; =&amp;gt; &amp;quot;男&amp;quot;, &amp;quot;details&amp;quot; =&amp;gt; &amp;quot;先收集999个呀哈哈!&amp;quot; ],[ &amp;quot;name&amp;quot; =&amp;gt; &amp;quot;普尔亚&amp;quot;, &amp;quot;age&amp;quot; =&amp;gt; 100, &amp;quot;gender&amp;quot; =&amp;gt; &amp;quot;女&amp;quot;, &amp;quot;details&amp;quot; =&amp;gt; &amp;quot;我先来个返老还童,再快速长大!&amp;quot; ]]; return Db::name(&amp;quot;user&amp;quot;)-&amp;gt;insertAll($data);</code></pre> </li> <li> <p><strong>insertAll()</strong> 方法 也支持 replace 写入,如果添加数据量大,可以通过 <strong>-&gt; limit()</strong> 方法限制添加数量;</p> <pre><code class="language-php">Db::name(&amp;quot;user&amp;quot;)-&amp;gt;replace()-&amp;gt;limit(100)-&amp;gt;insertAll($data);</code></pre> </li> </ul> <h1>13. 更新删除和save方法</h1> <p>&lt;div style=&quot;text-align:right;color:#666;font-size:20px;&quot;&gt;主讲老师 - 李炎恢&lt;/div&gt;</p> <h3>1. 数据修改</h3> <ul> <li> <p>使用 <strong>update()</strong> 方法来修改数据,修改成功返回影响行数,没有修改返回 <strong>0</strong>;</p> <pre><code class="language-php">// 修改的数据 $data = [ &amp;quot;name&amp;quot; =&amp;gt; &amp;quot;王三狗&amp;quot;, &amp;quot;age&amp;quot; =&amp;gt; &amp;quot;13&amp;quot;, ]; // 执行修改并返回 return Db::name(&amp;quot;user&amp;quot;)-&amp;gt;where(&amp;quot;id&amp;quot;, 4)-&amp;gt;update($data);</code></pre> </li> <li> <p>如果修改数据包含了主键信息,比如 id,那么可以省略掉 where 条件;</p> <pre><code class="language-php">// 修改的数据 $data = [ &amp;quot;id&amp;quot; =&amp;gt; 4, &amp;quot;name&amp;quot; =&amp;gt; &amp;quot;王三狗&amp;quot;, &amp;quot;age&amp;quot; =&amp;gt; &amp;quot;13&amp;quot;, ]; // 执行修改并返回 return Db::name(&amp;quot;user&amp;quot;)-&amp;gt;update($data);</code></pre> </li> <li> <p>如果想让一些字段修改时执行 SQL 函数操作,可以使用 <strong>exp()</strong> 方法实现;</p> <pre><code class="language-php">// 让details字段内的英文大写 return Db::name(&amp;quot;user&amp;quot;)-&amp;gt;exp(&amp;quot;details&amp;quot;, &amp;quot;UPPER(details)&amp;quot;)-&amp;gt;update($data);</code></pre> </li> <li> <p>如果要自增/自减某个字段,可以使用 inc/dec 方法,并支持自定义步长;</p> <pre><code class="language-php">// 修改时,让age自增和自减,默认1,要去掉$data里面age字段的修改,不然冲突 return Db::name(&amp;quot;user&amp;quot;)-&amp;gt;inc(&amp;quot;age&amp;quot;)-&amp;gt;dec(&amp;quot;age&amp;quot;, 2)-&amp;gt;update($data); // 派生自字段,延迟执行,毫秒 setInc(&amp;quot;age&amp;quot;, 1, 600) setDec(&amp;quot;age&amp;quot;, 2, 600)</code></pre> </li> <li> <p>使用 <strong>Db::raw()</strong> 来设置每个字段的特殊需求,灵活且清晰:</p> <pre><code class="language-php">// 使用Db::raw 更加清晰灵活 Db::name(&amp;quot;user&amp;quot;)-&amp;gt;where(&amp;quot;id&amp;quot;, 4)-&amp;gt;update([ &amp;quot;details&amp;quot; =&amp;gt; Db::raw(&amp;quot;UPPER(details)&amp;quot;), &amp;quot;age&amp;quot; =&amp;gt; Db::raw(&amp;quot;age-2&amp;quot;) ]); return Db::getLastSql();</code></pre> </li> <li> <p><strong>save()</strong> 方法是一个通用方法,可以自行判断是新增还是修改(更新)数据;</p> <pre><code class="language-php">// 包含主键,即修改;否则,新增 return Db::name(&amp;quot;user&amp;quot;)-&amp;gt;save($data);</code></pre> </li> </ul> <h3>2. 数据删除</h3> <ul> <li> <p>极简删除可以根据主键直接删除,删除成功返回影响行数,否则 0;</p> <pre><code class="language-php">// 根据主键删除 Db::name(&amp;quot;user&amp;quot;)-&amp;gt;delete(8);</code></pre> </li> <li> <p>根据主键,还可以删除多条记录;</p> <pre><code class="language-php">// 根据主键删除多条 Db::name(&amp;quot;user&amp;quot;)-&amp;gt;delete([48,49,50]);</code></pre> </li> <li> <p>正常情况下,通过 where()方法来删除;</p> <pre><code class="language-php">// 条件删除 Db::name(&amp;quot;user&amp;quot;)-&amp;gt;where(&amp;quot;id&amp;quot;, 47)-&amp;gt;delete();</code></pre> </li> <li>清空表以及逻辑软删除,参考手册即可;逻辑软删除,在模型篇单独讲解,这里略过。</li> </ul> <h1>14. 查询表达式规则</h1> <p>&lt;div style=&quot;text-align:right;color:#666;font-size:20px;&quot;&gt;主讲老师 - 李炎恢&lt;/div&gt;</p> <h3>1. <strong>表达式查询</strong></h3> <ul> <li> <p>查询表达式支持大部分常用的 SQL 语句,语法格式如下:</p> <pre><code class="language-php">where(&amp;quot;字段名&amp;quot;,&amp;quot;查询表达式&amp;quot;,&amp;quot;查询条件&amp;quot;);</code></pre> </li> <li> <p>所有的表达式,查阅手册 -&gt; 查询表达式 中的表格即可;这里列出几个意思一下:</p> <table> <thead> <tr> <th style="text-align: center;">表达式</th> <th style="text-align: center;">含义</th> <th style="text-align: center;">快捷方式</th> </tr> </thead> <tbody> <tr> <td style="text-align: center;">=</td> <td style="text-align: center;">等于</td> <td style="text-align: center;"></td> </tr> <tr> <td style="text-align: center;">&lt;= time</td> <td style="text-align: center;">小于等于某个时间</td> <td style="text-align: center;">whereTime</td> </tr> <tr> <td style="text-align: center;">EXP</td> <td style="text-align: center;">SQL表达式查询</td> <td style="text-align: center;">whereExp</td> </tr> <tr> <td style="text-align: center;">[NOT] LIKE</td> <td style="text-align: center;">模糊查询</td> <td style="text-align: center;">whereLike</td> </tr> <tr> <td style="text-align: center;">[NOT] IN</td> <td style="text-align: center;">[非] IN 查询</td> <td style="text-align: center;">whereIN</td> </tr> </tbody> </table> </li> </ul> <h3>2. <strong>查询示例</strong></h3> <ul> <li> <p>条件判断类的,id大于4的;</p> <pre><code class="language-php">// 查询id大于4的数据 $user = Db::name(&amp;quot;user&amp;quot;)-&amp;gt;where(&amp;quot;id&amp;quot;, &amp;quot;&amp;gt;&amp;quot;, 4)-&amp;gt;select(); return json($user);</code></pre> </li> <li> <p>Like模糊查询,姓王的;</p> <pre><code class="language-php">// 查询姓王的用户 $user = Db::name(&amp;quot;user&amp;quot;)-&amp;gt;where(&amp;quot;name&amp;quot;, &amp;quot;like&amp;quot;, &amp;quot;王%&amp;quot;)-&amp;gt;select(); // like快捷方式 $user = Db::name(&amp;quot;user&amp;quot;)-&amp;gt;whereLike(&amp;quot;name&amp;quot;, &amp;quot;王%&amp;quot;)-&amp;gt;select();</code></pre> </li> <li> <p>IN区间查询,根据id;</p> <pre><code class="language-php">// 区间查询,支持not in $user = Db::name(&amp;quot;user&amp;quot;)-&amp;gt;where(&amp;quot;id&amp;quot;, &amp;quot;in&amp;quot;, &amp;quot;1, 3, 5&amp;quot;)-&amp;gt;select(); // 语义更好一点 $user = Db::name(&amp;quot;user&amp;quot;)-&amp;gt;where(&amp;quot;id&amp;quot;, &amp;quot;in&amp;quot;, [1,3,5])-&amp;gt;select(); // IN快捷查询,两种均可,支持whereNotIn $user = Db::name(&amp;quot;user&amp;quot;)-&amp;gt;whereIn(&amp;quot;id&amp;quot;, [1, 2, 3])-&amp;gt;select(); // Between,和IN一样 支持 not between $user = Db::name(&amp;quot;user&amp;quot;)-&amp;gt;where(&amp;quot;id&amp;quot;, &amp;quot;between&amp;quot;, [2,5])-&amp;gt;select(); // 快捷方式和IN一样:whereBetween和whereNotBetween</code></pre> </li> <li> <p>NULL查询;</p> <pre><code class="language-php">// NULL, null 或 not null: $user = Db::name(&amp;quot;user&amp;quot;)-&amp;gt;where(&amp;quot;details&amp;quot;, &amp;quot;not null&amp;quot;)-&amp;gt;select(); // 快捷方式:whereNull和whereNotNull</code></pre> </li> <li> <p>EXP查询,自定义SQL片段;</p> <pre><code class="language-php">// EXP查询,自定义SQL $user = Db::name(&amp;quot;user&amp;quot;)-&amp;gt;where(&amp;quot;id&amp;quot;, &amp;quot;EXP&amp;quot;, &amp;quot;&amp;lt;&amp;gt; 8 and id &amp;gt;5&amp;quot;)-&amp;gt;select(); // 快捷查询 $user = Db::name(&amp;quot;user&amp;quot;)-&amp;gt;whereExp(&amp;quot;id&amp;quot;,&amp;quot;&amp;lt;&amp;gt; 8 and id &amp;gt;5&amp;quot;)-&amp;gt;select();</code></pre> </li> <li>这里推荐:有快捷方式的用快捷方式,通过Ctrl+方法名得知,快捷方式绕过了很多拼装流程,速度更快;</li> </ul> <h1>15. 超多查询都不讲</h1> <p>&lt;div style=&quot;text-align:right;color:#666;font-size:20px;&quot;&gt;主讲老师 - 李炎恢&lt;/div&gt;</p> <ul> <li>警告:这里罗列了大量的快捷查询的示例、链式查询以及其它非常用的查询方法;</li> <li>介于TP6课程大家的反馈,我这里不再详细讲解每个方法的用法;</li> <li>但我会录入在讲义里,方便后续项目课程时候回头查阅;后续类似的知识点也这么砍;</li> </ul> <h3>1. 字符串条件(不讲)</h3> <ul> <li> <p><strong>whereRaw</strong> 可以直接写入多条件:</p> <pre><code class="language-php">// 多条件字符串 $user = Db::name(&amp;quot;user&amp;quot;)-&amp;gt;whereRaw(&amp;quot;age &amp;gt; 15 AND gender=&amp;quot;女&amp;quot;&amp;quot;)-&amp;gt;select();</code></pre> </li> <li> <p>包含变量的多条件查询:</p> <pre><code class="language-php">// 变量 $age = 15; $gender = &amp;quot;女&amp;quot;; // 预处理机制 $user = Db::name(&amp;quot;user&amp;quot;)-&amp;gt;whereRaw(&amp;quot;age&amp;gt;:age AND gender=:gender&amp;quot;, [ &amp;quot;age&amp;quot; =&amp;gt; $age, &amp;quot;gender&amp;quot; =&amp;gt; $gender ])-&amp;gt;select();</code></pre> </li> </ul> <h3>2. field()字段筛选(不讲)</h3> <ul> <li> <p>使用 <strong>field()</strong> 方法,可以指定要查询的字段;</p> <pre><code class="language-php">// 字段筛选 $user = Db::name(&amp;quot;user&amp;quot;)-&amp;gt;field(&amp;quot;id, age, gender&amp;quot;)-&amp;gt;select(); $user = Db::name(&amp;quot;user&amp;quot;)-&amp;gt;field([&amp;quot;id, age, gender&amp;quot;])-&amp;gt;select();</code></pre> </li> <li> <p>使用 <strong>field()</strong> 方法,给指定的字段设置别名;</p> <pre><code class="language-php">// 字段别名 $user = Db::name(&amp;quot;user&amp;quot;)-&amp;gt;field(&amp;quot;id, gender as sex&amp;quot;)-&amp;gt;select(); $user = Db::name(&amp;quot;user&amp;quot;)-&amp;gt;field([&amp;quot;id&amp;quot;, &amp;quot;gender&amp;quot;=&amp;gt;&amp;quot;sex&amp;quot;])-&amp;gt;select();</code></pre> </li> <li> <p>在 <strong>fieldRaw()</strong> 方法里,可以直接给字段设置 MySQL 函数;</p> <pre><code class="language-php">// 直接SQL函数 $user = Db::name(&amp;quot;user&amp;quot;)-&amp;gt;fieldRaw(&amp;quot;id, UPPER(details)&amp;quot;)-&amp;gt;select(); $user = Db::name(&amp;quot;user&amp;quot;)-&amp;gt;field(true)-&amp;gt;select(); // 推荐 return Db::getLastSql();</code></pre> </li> <li> <p>使用 <strong>withoutField()</strong> 方法中字段排除,可以屏蔽掉想要不显示的字段;</p> <pre><code class="language-php">// 排除字段 $user = Db::name(&amp;quot;user&amp;quot;)-&amp;gt;withoutField(&amp;quot;details&amp;quot;)-&amp;gt;select();</code></pre> </li> <li> <p>使用 <strong>field()</strong> 方法在新增时,验证字段的合法性;</p> <pre><code class="language-php">// 排除新增字段 Db::name(&amp;quot;user&amp;quot;)-&amp;gt;field(&amp;quot;name,age,gender&amp;quot;)-&amp;gt;insert($data);</code></pre> </li> </ul> <h3>3. <strong>常用链式方法</strong>(不讲)</h3> <ul> <li> <p>使用 <strong>alias()</strong> 方法,给数据库起一个别名;</p> <pre><code class="language-php">// 给数据库起个别名 Db::name(&amp;quot;user&amp;quot;)-&amp;gt;alias(&amp;quot;a&amp;quot;)-&amp;gt;select(); return Db::getLastSql(); // 起别名最主要是和另一张表进行关联,这里看手册好了,没表测试 alias(&amp;quot;a&amp;quot;)-&amp;gt;join()</code></pre> </li> <li> <p>使用 <strong>limit()</strong> 方法,限制获取输出数据的个数;</p> <pre><code class="language-php">// 显示前5条 $user = Db::name(&amp;quot;user&amp;quot;)-&amp;gt;limit(5)-&amp;gt;select();</code></pre> </li> <li> <p>分页模式,即传递两个参数,比如从第 3 条开始显示 5 条 limit(2,5);</p> <pre><code class="language-php">// 从第2个位置,也就是第3条开始,显示5条 $user = Db::name(&amp;quot;user&amp;quot;)-&amp;gt;limit(2,5)-&amp;gt;select(); // 查询第一页数据,1至10条 $user = Db::name(&amp;quot;user&amp;quot;)-&amp;gt;page(1,10)-&amp;gt;select(); </code></pre> </li> <li> <p>使用 <strong>order()</strong> 方法,可以指定排序方式,没有指定第二参数,默认 asc;</p> <pre><code class="language-php">// 按id倒序排列 $user = Db::name(&amp;quot;user&amp;quot;)-&amp;gt;order(&amp;quot;id&amp;quot;, &amp;quot;desc&amp;quot;)-&amp;gt;select();</code></pre> </li> <li> <p>支持数组的方式,对多个字段进行排序;</p> <pre><code class="language-php">// 按多个字段规则排序 $user = Db::name(&amp;quot;user&amp;quot;)-&amp;gt;order([&amp;quot;age&amp;quot;=&amp;gt;&amp;quot;asc&amp;quot;, &amp;quot;id&amp;quot;=&amp;gt;&amp;quot;desc&amp;quot;])-&amp;gt;select(); //支持 orderRaw() 方法,可以传入SQL函数,和前面各类Raw一样,不再赘述</code></pre> </li> <li> <p>使用 <strong>group()</strong> 方法,给性别不同的人进行 age 字段的总和统计;</p> <pre><code class="language-php">// 统计性别的年龄总和 $user = Db::name(&amp;quot;user&amp;quot;)-&amp;gt;fieldRaw(&amp;quot;gender, SUM(age)&amp;quot;) -&amp;gt;group(&amp;quot;gender&amp;quot;)-&amp;gt;select();</code></pre> </li> <li> <p>使用 <strong>group()</strong> 分组之后,再使用 <strong>having()</strong> 进行筛选;</p> <pre><code class="language-php">// 统计性别的年龄总和,筛选大于100的 $user = Db::name(&amp;quot;user&amp;quot;)-&amp;gt;fieldRaw(&amp;quot;gender, SUM(age)&amp;quot;) -&amp;gt;group(&amp;quot;gender&amp;quot;) -&amp;gt;having(&amp;quot;SUM(age) &amp;gt; 100&amp;quot;)-&amp;gt;select();</code></pre> </li> </ul> <h3>4. <strong>时间查询</strong>(不讲)</h3> <ul> <li> <p>可以使用 &gt;、&lt;、&gt;=、&lt;= 来筛选匹配时间的数据;</p> <pre><code class="language-php">// 传统时间筛选 $user = Db::name(&amp;quot;user&amp;quot;)-&amp;gt;where(&amp;quot;create_time&amp;quot;, &amp;quot;&amp;gt;&amp;quot;, &amp;quot;2022-1-1&amp;quot;)-&amp;gt;select(); $user = Db::name(&amp;quot;user&amp;quot;)-&amp;gt;where(&amp;quot;create_time&amp;quot;, &amp;quot;between&amp;quot;, [&amp;quot;2020-1-1&amp;quot;, &amp;quot;2023-1-1&amp;quot;])-&amp;gt;select(); </code></pre> </li> <li> <p>快捷方式 <strong>whereTime</strong>:</p> <pre><code class="language-php">// 使用快捷方式查询 $user = Db::name(&amp;quot;user&amp;quot;)-&amp;gt;whereTime(&amp;quot;create_time&amp;quot;, &amp;quot;&amp;gt;=&amp;quot;, &amp;quot;2022-1-1&amp;quot;)-&amp;gt;select(); // 默认是 &amp;gt; 可以省略 $user = Db::name(&amp;quot;user&amp;quot;)-&amp;gt;whereTime(&amp;quot;create_time&amp;quot;, &amp;quot;2022-1-1&amp;quot;)-&amp;gt;select();</code></pre> </li> <li> <p>区间查询快捷方式 <strong>whereBetweenTime</strong>:</p> <pre><code class="language-php">// 区间查询,包含 whereNotBetweenTime $user = Db::name(&amp;quot;user&amp;quot;)-&amp;gt;whereBetweenTime(&amp;quot;create_time&amp;quot;, &amp;quot;2020-1-1&amp;quot;, &amp;quot;2023-1-1&amp;quot;)-&amp;gt;select();</code></pre> </li> <li> <p>使用 <strong>whereYear</strong> 查询今年的数据、去年的数据和某一年的数据;</p> <pre><code class="language-php">// 查询今年 $user = Db::name(&amp;quot;user&amp;quot;)-&amp;gt;whereYear(&amp;quot;create_time&amp;quot;)-&amp;gt;select(); // 查询去年 $user = Db::name(&amp;quot;user&amp;quot;)-&amp;gt;whereYear(&amp;quot;create_time&amp;quot;, &amp;quot;last year&amp;quot;)-&amp;gt;select(); // 查询某一年 $user = Db::name(&amp;quot;user&amp;quot;)-&amp;gt;whereYear(&amp;quot;create_time&amp;quot;, &amp;quot;2019&amp;quot;)-&amp;gt;select();</code></pre> </li> <li> <p>使用 <strong>whereMonth</strong> 查询当月的数据、上月的数据和某一个月的数据;</p> <pre><code class="language-php">Db::name(&amp;quot;user&amp;quot;)-&amp;gt;whereMonth(&amp;quot;create_time&amp;quot;)-&amp;gt;select(); Db::name(&amp;quot;user&amp;quot;)-&amp;gt;whereMonth(&amp;quot;create_time&amp;quot;, &amp;quot;last month&amp;quot;)-&amp;gt;select(); Db::name(&amp;quot;user&amp;quot;)-&amp;gt;whereMonth(&amp;quot;create_time&amp;quot;, &amp;quot;2020-6&amp;quot;)-&amp;gt;select();</code></pre> </li> <li> <p>使用 <strong>whereDay</strong> 查询今天的数据、昨天的数据和某一个天的数据;</p> <pre><code class="language-php">Db::name(&amp;quot;user&amp;quot;)-&amp;gt;whereDay(&amp;quot;create_time&amp;quot;)-&amp;gt;select(); Db::name(&amp;quot;user&amp;quot;)-&amp;gt;whereDay(&amp;quot;create_time&amp;quot;, &amp;quot;last day&amp;quot;)-&amp;gt;select(); Db::name(&amp;quot;user&amp;quot;)-&amp;gt;whereDay(&amp;quot;create_time&amp;quot;, &amp;quot;2020-6-27&amp;quot;)-&amp;gt;select();</code></pre> </li> <li> <p>查询指定时间的数据,比如两小时内的;</p> <pre><code class="language-php">// 两小时内的 $user = Db::name(&amp;quot;user&amp;quot;)-&amp;gt;whereTime(&amp;quot;create_time&amp;quot;, &amp;quot;-2 hours&amp;quot;)-&amp;gt;select();</code></pre> </li> <li> <p>查询两个时间字段时间有效期的数据,比如活动开始到结束的期间;</p> </li> <li> <p>比如创建两个字段:start_time,end_time,注册后,分别写入对应时间表明它的有效期;</p> <pre><code class="language-php">// 直接这么写,不太好理解,看手册的另一种普通写法很容易理解 // 实战中,字段丰富的时候再演示 $user = Db::name(&amp;quot;user&amp;quot;)-&amp;gt;whereBetweenTimeField(&amp;quot;start_time&amp;quot;, &amp;quot;end_time&amp;quot;)-&amp;gt;select();</code></pre> </li> </ul> <h3>5. <strong>聚合查询</strong>(不讲)</h3> <ul> <li> <p>使用 <strong>count()</strong> 方法,可以求出所查询数据的数量;</p> <pre><code class="language-php">// 获取记录数 $user = Db::name(&amp;quot;user&amp;quot;)-&amp;gt;count();</code></pre> </li> <li> <p><strong>count()</strong> 可设置指定 id,比如有空值(Null)的 details,不会计算数量;</p> <pre><code class="language-php">// 值NULL不计数 $user = Db::name(&amp;quot;user&amp;quot;)-&amp;gt;count(&amp;quot;details&amp;quot;);</code></pre> </li> <li> <p>使用 <strong>max()</strong> 方法,求出所查询数据字段的最大值;</p> <pre><code class="language-php">// 求最大年龄 $user = Db::name(&amp;quot;user&amp;quot;)-&amp;gt;max(&amp;quot;age&amp;quot;);</code></pre> </li> <li> <p>如果 <strong>max()</strong> 方法,求出的值不是数值,则通过第二参数强制转换;</p> <pre><code class="language-php">// 如果最大值不是数值,false关闭强制转换 $user = Db::name(&amp;quot;user&amp;quot;)-&amp;gt;max(&amp;quot;name&amp;quot;, false);</code></pre> </li> <li> <p>使用 <strong>min()</strong> 方法,求出所查询数据字段的最小值,也可以强制转换;</p> <pre><code class="language-php">// 求最小值 $user = Db::name(&amp;quot;user&amp;quot;)-&amp;gt;min(&amp;quot;age&amp;quot;);</code></pre> </li> <li> <p>使用 <strong>avg()</strong> 方法,求出所查询数据字段的平均值;</p> <pre><code class="language-php">// 求平均值 $user = Db::name(&amp;quot;user&amp;quot;)-&amp;gt;avg(&amp;quot;age&amp;quot;);</code></pre> </li> <li> <p>使用 <strong>sum()</strong> 方法,求出所查询数据字段的总和;</p> <pre><code class="language-php">// 求总和 $user = Db::name(&amp;quot;user&amp;quot;)-&amp;gt;sum(&amp;quot;age&amp;quot;);</code></pre> </li> </ul> <h3>6. <strong>子查询</strong>(不讲)</h3> <ul> <li> <p>使用 <strong>fetchSql()</strong> 方法,传递参数true时,可以设置不执行 SQL,直接返回SQL语句;</p> <pre><code class="language-php">// 子查询语句 $user = Db::name(&amp;quot;user&amp;quot;)-&amp;gt;fetchSql(true)-&amp;gt;select();</code></pre> </li> <li> <p>使用 <strong>buildSql()</strong> 方法,也是返回 SQL 语句,不需要再执行 select(),且有括号;</p> <pre><code class="language-php">// 第二种子查询 $subQuery = Db::name(&amp;quot;user&amp;quot;)-&amp;gt;buildSql(true);</code></pre> </li> <li> <p>结合以上方法,我们实现一个子查询;</p> <pre><code class="language-php">// 子查询样式 $subQuery = Db::name(&amp;quot;user&amp;quot;)-&amp;gt;field(&amp;quot;id&amp;quot;)-&amp;gt;where(&amp;quot;age&amp;quot;,&amp;quot;&amp;gt;&amp;quot;, 18)-&amp;gt;buildSql(); $user = Db::name(&amp;quot;user&amp;quot;)-&amp;gt;whereExp(&amp;quot;id&amp;quot;, &amp;quot;IN &amp;quot;.$subQuery)-&amp;gt;select();</code></pre> </li> <li> <p>使用闭包的方式执行子查询;</p> <pre><code class="language-php">// 采用闭包构建子查询 $user = Db::name(&amp;quot;user&amp;quot;)-&amp;gt;where(&amp;quot;id&amp;quot;, &amp;quot;IN&amp;quot;, function ($query) { $query-&amp;gt;name(&amp;quot;user&amp;quot;)-&amp;gt;field(&amp;quot;id&amp;quot;)-&amp;gt;where(&amp;quot;age&amp;quot;,&amp;quot;&amp;gt;&amp;quot;, 18); })-&amp;gt;select();</code></pre> </li> </ul> <h3>7. <strong>原生查询</strong></h3> <ul> <li> <p>使用 <strong>query()</strong> 方法,进行原生 SQL 查询,适用于读取操作,SQL 错误返回 false;</p> <pre><code class="language-php">// 原生SQL $user = Db::query(&amp;quot;SELECT * FROM tp_user&amp;quot;);</code></pre> </li> <li> <p>使用 <strong>execute</strong> 方法,进行原生 SQL 更新写入等,SQL 错误返回 false;</p> <pre><code class="language-php">// 原生更新写入 $user = Db::execute(&amp;quot;update tp_user set details=&amp;quot;快快快来救我!&amp;quot; where id=5&amp;quot;);</code></pre> </li> </ul> <h3>8. <strong>列字段快捷查询</strong>(不讲)</h3> <ul> <li>之前用过诸如:whereIn、whereExp、whereLike等等快捷查询;</li> <li> <p>所有快捷查询列表的手册位置:数据库 -&gt; 查询构造器 -&gt; 高级查询中,找到快捷查询表格;</p> </li> <li> <p><strong>whereColumn()</strong> 方法,比较两个字段的值,符合的就筛选出来;</p> <pre><code class="language-php">// 字段比较,id大于age $user = Db::name(&amp;quot;user&amp;quot;)-&amp;gt;whereColumn(&amp;quot;id&amp;quot;, &amp;quot;&amp;gt;&amp;quot;, &amp;quot;age&amp;quot;)-&amp;gt;select(); // 如果是 等于判断 可以简化 -&amp;gt;whereColumn(&amp;quot;id&amp;quot;, &amp;quot;age&amp;quot;)</code></pre> </li> <li> <p><strong>whereFieldName()</strong> 方法,查询某个字段的值,注意 FileName 是字段名;</p> <pre><code class="language-php">// 获取所有性别为:男 $user = Db::name(&amp;quot;user&amp;quot;)-&amp;gt;whereGender(&amp;quot;男&amp;quot;)-&amp;gt;select(); // 获取名字叫王二狗的信息 $user = Db::name(&amp;quot;user&amp;quot;)-&amp;gt;whereName(&amp;quot;王二狗&amp;quot;)-&amp;gt;find();</code></pre> </li> <li> <p><strong>getByFieldName()</strong> 方法,查询某个字段的值,注意只能查询一条,不需要 <strong>find()</strong>;</p> <pre><code class="language-php">// 单条数据 $user = Db::name(&amp;quot;user&amp;quot;)-&amp;gt;getByName(&amp;quot;王二狗&amp;quot;);</code></pre> </li> <li> <p><strong>getFieldByFieldName()</strong> 方法,通过查询得到某个指定字段的单一值;</p> <pre><code class="language-php">// 查询单条并返回单列,找出王二狗的年龄 $user = Db::name(&amp;quot;user&amp;quot;)-&amp;gt;getFieldByName(&amp;quot;王二狗&amp;quot;, &amp;quot;age&amp;quot;);</code></pre> </li> </ul> <h3>9. <strong>条件查询</strong>(不讲)</h3> <ul> <li> <p><strong>when()</strong> 可以通过条件判断,执行闭包里的分支查询;</p> <pre><code class="language-php">// 条件判断 $user = Db::name(&amp;quot;user&amp;quot;)-&amp;gt;when(false, function ($query) { // 满足条件执行这段SQL $query-&amp;gt;where(&amp;quot;id&amp;quot;, &amp;quot;&amp;gt;&amp;quot;, 5); }, function ($query) { // 不满足条件执行这段SQL $query-&amp;gt;where(&amp;quot;id&amp;quot;, &amp;quot;&amp;lt;=&amp;quot;, 5); })-&amp;gt;select();</code></pre> </li> </ul> <h3>10. 事务(不讲)</h3> <ul> <li> <p>数据库的表引擎需要是 InnoDB 才可以使用,如果不是调整即可;</p> </li> <li> <p>事务处理,需要执行多个 SQL 查询,数据是关联恒定的;</p> </li> <li> <p>如果成功一条查询,改变了数据,而后一条失败,则前面的数据回滚;</p> </li> <li> <p>比如:银行取钱,银行ATM扣了1000,但入口被卡住,你没拿到,这时需要事务处理;</p> </li> <li> <p>系统提供了两种事务处理的方式,第一种是自动处理,出错自动回滚;</p> <pre><code class="language-php">// 出现异常回滚 Db::transaction(function () { Db::name(&amp;quot;user&amp;quot;)-&amp;gt;delete(12); Db::name(&amp;quot;user&amp;quot;)-&amp;gt;findOrFail(13); });</code></pre> </li> <li> <p>手动处理,基本和原生处理类似,可以自行输出错误信息;</p> <pre><code class="language-php">// 启动事务 Db::startTrans(); try { Db::name(&amp;quot;user&amp;quot;)-&amp;gt;delete(12); Db::name(&amp;quot;user&amp;quot;)-&amp;gt;findOrFail(13); //提交事务 Db::commit(); } catch (\Exception $e) { echo &amp;quot;执行SQL失败!&amp;quot;; // 回滚 Db::rollback(); }</code></pre> </li> </ul> <h3>11. 获取器(不讲)</h3> <ul> <li> <p>获取器的意思就是:将数据的字段进行转换处理再进行操作;</p> </li> <li> <p>比如在获取数据列表的时候,将获取到的详情字段全部大写;</p> <pre><code class="language-php">// 获取器改变字段值 $user = Db::name(&amp;quot;user&amp;quot;)-&amp;gt;withAttr(&amp;quot;details&amp;quot;, function ($value, $data) { // NULL 不处理 if ($value != null) { return strtoupper($value); } })-&amp;gt;select();</code></pre> </li> <li>withAttr也是支持JSON字段的,具体参考手册 查询构造器 -&gt; 获取器;</li> </ul> <h1>16. 关联索引查询</h1> <p>&lt;div style=&quot;text-align:right;color:#666;font-size:20px;&quot;&gt;主讲老师 - 李炎恢&lt;/div&gt;</p> <h3>1. <strong>索引关联</strong></h3> <ul> <li> <p><strong>where</strong> 方法的数组查询:</p> <pre><code class="language-php">// 性别男,年龄大于15岁,常规做法 $user = Db::name(&amp;quot;user&amp;quot;)-&amp;gt;where(&amp;quot;age&amp;quot;, &amp;quot;&amp;gt;&amp;quot;, 15) -&amp;gt;where(&amp;quot;gender&amp;quot;, &amp;quot;男&amp;quot;)-&amp;gt;select(); // 索引数组方式,二维数组,返回的SQL 是一条 AND 并列关系 $user = Db::name(&amp;quot;user&amp;quot;)-&amp;gt;where([ [&amp;quot;age&amp;quot;, &amp;quot;&amp;gt;&amp;quot;, &amp;quot;15&amp;quot;], [&amp;quot;gender&amp;quot;,&amp;quot;=&amp;quot;, &amp;quot;男&amp;quot;] ])-&amp;gt;select(); // 如果是等于,可以直接用关联数组,一维 $user = Db::name(&amp;quot;user&amp;quot;)-&amp;gt;where([ &amp;quot;age&amp;quot; =&amp;gt; 15, &amp;quot;gender&amp;quot; =&amp;gt; &amp;quot;男&amp;quot; ])-&amp;gt;select(); // 两种模式结合起来, $user = Db::name(&amp;quot;user&amp;quot;)-&amp;gt;where([ [&amp;quot;age&amp;quot;, &amp;quot;&amp;gt;&amp;quot;, &amp;quot;15&amp;quot;], &amp;quot;gender&amp;quot; =&amp;gt; &amp;quot;男&amp;quot; ])-&amp;gt;select(); // 搜索条件独立管理,这里=号写全 $map[] = [&amp;quot;age&amp;quot;, &amp;quot;&amp;gt;&amp;quot;, &amp;quot;15&amp;quot;]; $map[] = [&amp;quot;gender&amp;quot;,&amp;quot;=&amp;quot;, &amp;quot;男&amp;quot;]; $user = Db::name(&amp;quot;user&amp;quot;)-&amp;gt;where($map)-&amp;gt;select();</code></pre> </li> </ul> <h1>17. 拼装高级查询</h1> <p>&lt;div style=&quot;text-align:right;color:#666;font-size:20px;&quot;&gt;主讲老师 - 李炎恢&lt;/div&gt;</p> <h3>1. <strong>拼装查询</strong></h3> <ul> <li> <p>使用 <strong>|(OR)</strong> 或 <strong>&amp;(AND)</strong> 来实现 where 条件的高级查询,where 支持多个连缀;</p> <pre><code class="language-php">// or和and 拼装查询 $user = Db::name(&amp;quot;user&amp;quot;)-&amp;gt;where(&amp;quot;name|details&amp;quot;, &amp;quot;like&amp;quot;, &amp;quot;%王%&amp;quot;) -&amp;gt;where(&amp;quot;id&amp;amp;create_time&amp;quot;, &amp;quot;&amp;gt;&amp;quot;, 0) -&amp;gt;select(); // 拼装返回的SQL SELECT * FROM `tp_user` WHERE ( `name` LIKE &amp;quot;%王%&amp;quot; OR `details` LIKE &amp;quot;%王%&amp;quot; ) AND ( `id` &amp;gt; 0 AND `create_time` &amp;gt; &amp;quot;0&amp;quot; )</code></pre> </li> <li> <p>索引数组方式,可以在 where 进行多个字段进行查询;</p> <pre><code class="language-php">// 索引数组拼装 $user = Db::name(&amp;quot;user&amp;quot;)-&amp;gt;where([ [&amp;quot;id&amp;quot;, &amp;quot;&amp;gt;&amp;quot;, &amp;quot;5&amp;quot;], [&amp;quot;gender&amp;quot;, &amp;quot;=&amp;quot;, &amp;quot;女&amp;quot;], [&amp;quot;age&amp;quot;, &amp;quot;&amp;lt;=&amp;quot;, 15], [&amp;quot;details&amp;quot;, &amp;quot;like&amp;quot;, &amp;quot;%我%&amp;quot;] ])-&amp;gt;select(); // 拼装返回的SQL SELECT * FROM `tp_user` WHERE `id` &amp;gt; 5 AND `gender` = &amp;quot;女&amp;quot; AND `age` &amp;lt;= 15 AND `details` LIKE &amp;quot;%我%&amp;quot;</code></pre> </li> <li> <p>根据之前的课程中,条件字符串复杂组装,比如使用 exp 了,就使用 <strong>raw()</strong> 方法;</p> <pre><code class="language-php">// exp 拼装 $user = Db::name(&amp;quot;user&amp;quot;)-&amp;gt;where([ [&amp;quot;gender&amp;quot;, &amp;quot;=&amp;quot;, &amp;quot;男&amp;quot;], [&amp;quot;age&amp;quot;, &amp;quot;exp&amp;quot;, Db::raw(&amp;quot;&amp;gt;=10 AND id&amp;lt;5&amp;quot;)] ])-&amp;gt;select(); // 拼装返回的SQL SELECT * FROM `tp_user` WHERE `gender` = &amp;quot;男&amp;quot; AND ( `age` &amp;gt;=10 AND id&amp;lt;5 )</code></pre> </li> <li> <p>如果有多个where,并需要控制优先级,那么在可以在需要的部分加上中括号;</p> <pre><code class="language-php">// 下面的代码无法控制优先级 $user = Db::name(&amp;quot;user&amp;quot;)-&amp;gt;where([ [&amp;quot;gender&amp;quot;, &amp;quot;=&amp;quot;, &amp;quot;男&amp;quot;], [&amp;quot;age&amp;quot;, &amp;quot;exp&amp;quot;, Db::raw(&amp;quot;&amp;gt;=10 AND id&amp;lt;5&amp;quot;)] ])-&amp;gt;where(&amp;quot;details&amp;quot;, &amp;quot;like&amp;quot;, &amp;quot;%我%&amp;quot;)-&amp;gt;select(); // 外加一个中括号 -&amp;gt;where([[ ... ]]) // 拼装返回的SQL SELECT * FROM `tp_user` WHERE ( `gender` = &amp;quot;男&amp;quot; AND ( `age` &amp;gt;=10 AND id&amp;lt;5 ) ) AND `details` LIKE &amp;quot;%我%&amp;quot; // 推荐用变量代替 $map =[ [&amp;quot;gender&amp;quot;, &amp;quot;=&amp;quot;, &amp;quot;男&amp;quot;], [&amp;quot;age&amp;quot;, &amp;quot;exp&amp;quot;, Db::raw(&amp;quot;&amp;gt;=10 AND id&amp;lt;5&amp;quot;)] ]; -&amp;gt;where([$map])</code></pre> </li> <li> <p>如果,条件中有多次出现一个字段,并且需要 OR 来左右筛选,可以用 <strong>whereOr</strong>;</p> <pre><code class="language-php">// 多条件重复字段 OR 选项 $map1 = [ [&amp;quot;name&amp;quot;, &amp;quot;like&amp;quot;, &amp;quot;%王%&amp;quot;], [&amp;quot;details&amp;quot;, &amp;quot;=&amp;quot;, null] ]; $map2 = [ [&amp;quot;gender&amp;quot;, &amp;quot;=&amp;quot;, &amp;quot;女&amp;quot;], [&amp;quot;details&amp;quot;, &amp;quot;exp&amp;quot;, Db::raw(&amp;quot;IS NOT NULL&amp;quot;)] ]; $user = Db::name(&amp;quot;user&amp;quot;)-&amp;gt;whereOr([$map1, $map2])-&amp;gt;select(); // 拼装返回的SQL SELECT * FROM `tp_user` WHERE ( `name` LIKE &amp;quot;%王%&amp;quot; AND `details` IS NULL ) OR ( `gender` = &amp;quot;女&amp;quot; AND ( `details` IS NOT NULL ) )</code></pre> </li> </ul> <h1>18. <strong>模型的定义方式</strong></h1> <p>&lt;div style=&quot;text-align:right;color:#666;font-size:20px;&quot;&gt;主讲老师 - 李炎恢&lt;/div&gt;</p> <h3>1. <strong>定义模型</strong></h3> <ul> <li> <p>为了避免被前面课程中控制器的类名干扰,删除或改名都行:</p> <pre><code class="language-php">// UserBak.php,目前不存在任何地方的User.php了 class UserBak extends BaseController</code></pre> </li> <li> <p>定义一个和数据库表相匹配的模型,可在app应用目录下创建model文件夹;</p> <pre><code class="language-php">namespace app\model; use think\Model; class User extends Model { }</code></pre> </li> <li> <p>模型会自动对应数据表,并且有一套自己的命名规则;</p> </li> <li> <p>模型类需要去除表前缀(tp_),采用驼峰式命名,并且首字母大写;</p> <pre><code class="language-php">tp_user(表名) =&amp;gt; User tp_user_type(表名) =&amp;gt; UserType</code></pre> </li> <li> <p>在控制器段创建一个任意名称的类,当然有语义更好,但为了教学理解起名为:TestUser.php;</p> <pre><code class="language-php">namespace app\controller; use app\model\User; // 注意:类名不限制 class TestUser { public function index() { return json(User::select()); } }</code></pre> </li> </ul> <h3>2. <strong>模型设置</strong></h3> <ul> <li> <p>系统会自动识别 <strong>模型类名</strong> 对应 <strong>表名</strong>,User.php 对应 user 表(不含前缀);</p> </li> <li> <p>但如果你的模型类名不是按照规则对应表名,则需要通过成员字段去设置;</p> <pre><code class="language-php">class Abc extends Model { // 设置表名 protected $name = &amp;quot;user&amp;quot;; } // 使用$table时,指定表时需要完整的表名:tp_user</code></pre> </li> <li> <p>系统也会默认id为你的主键名,如果不是id,则需要设置;</p> <pre><code class="language-php">// 设置主键 protected $pk = &amp;quot;uid&amp;quot;;</code></pre> </li> <li> <p>模型支持初始化功能,需要设置静态方法,并只在第一次实例化的时候执行,且只执行一次;</p> <pre><code class="language-php">protected static function init() { echo &amp;quot;初始化&amp;quot;; }</code></pre> </li> </ul> <h1>19. <strong>模型的新增和删除</strong></h1> <p>&lt;div style=&quot;text-align:right;color:#666;font-size:20px;&quot;&gt;主讲老师 - 李炎恢&lt;/div&gt;</p> <h3>1. <strong>新增操作</strong></h3> <ul> <li> <p>用模型新增数据,首先要实例化模型,开发工具会补全use,非集成工具别忘了;</p> <pre><code class="language-php">use app\model\User; // 手册new User,这里括号是工具补全的,都可以 $user = new User();</code></pre> </li> <li> <p>使用实例化的方式添加一条数据,并使用 <strong>save()</strong> 方法进行保存;</p> </li> <li> <p>注意:使用模型时,会自动给时间字段 <strong>create_time</strong>,<strong>update_time</strong> 写入当前时间;</p> <pre><code class="language-php">$user = new User(); $user-&amp;gt;name = &amp;quot;李白&amp;quot;; $user-&amp;gt;age = 28; $user-&amp;gt;gender = &amp;quot;男&amp;quot;; $user-&amp;gt;details = &amp;quot;床前明月光,好诗!&amp;quot;; // 成功返回true,失败抛异常,其它看手册 $user-&amp;gt;save();</code></pre> </li> <li> <p>也可以通过 <strong>save()</strong> 传递数据数组的方式,来新增数据;</p> <pre><code class="language-php">$user-&amp;gt;save([ &amp;quot;name&amp;quot; =&amp;gt; &amp;quot;杜甫&amp;quot;, &amp;quot;age&amp;quot; =&amp;gt; 19, &amp;quot;gender&amp;quot; =&amp;gt; &amp;quot;男&amp;quot;, &amp;quot;details&amp;quot; =&amp;gt; &amp;quot;一行白鹭上青天,好诗!&amp;quot; ]);</code></pre> </li> <li> <p>使用 <strong>allowField()</strong> 方法,允许要写入的字段,其它字段就无法写入了;</p> <pre><code class="language-php">$user-&amp;gt;allowField([&amp;quot;name&amp;quot;,&amp;quot;age&amp;quot;,&amp;quot;gender&amp;quot;])-&amp;gt;save([ &amp;quot;name&amp;quot; =&amp;gt; &amp;quot;蒲松龄&amp;quot;, &amp;quot;age&amp;quot; =&amp;gt; 25, &amp;quot;gender&amp;quot; =&amp;gt; &amp;quot;男&amp;quot;, &amp;quot;details&amp;quot; =&amp;gt; &amp;quot;十里平湖霜满天,好诗!&amp;quot; ]);</code></pre> </li> <li> <p>模型新增也提供了 <strong>replace()</strong> 方法来实现 <strong>REPLACE into</strong> 新增;</p> <pre><code class="language-php">$user-&amp;gt;replace()-&amp;gt;save([ &amp;quot;id&amp;quot; =&amp;gt; 15, &amp;quot;name&amp;quot; =&amp;gt; &amp;quot;蒲松龄&amp;quot;, &amp;quot;age&amp;quot; =&amp;gt; 25, &amp;quot;gender&amp;quot; =&amp;gt; &amp;quot;男&amp;quot;, &amp;quot;details&amp;quot; =&amp;gt; &amp;quot;十里平湖霜满天,好诗!&amp;quot; ]);</code></pre> </li> <li> <p>当新增成功后,使用 <strong>$user-&gt;id</strong> ,可以获得自增 ID(主键需是 id);</p> <pre><code class="language-php">return $user-&amp;gt;id;</code></pre> </li> <li> <p>使用 saveAll()方法,可以批量新增数据,返回批量新增的数组;</p> <pre><code class="language-php">return $user-&amp;gt;saveAll([ [ &amp;quot;name&amp;quot; =&amp;gt; &amp;quot;赵六&amp;quot;, &amp;quot;age&amp;quot; =&amp;gt; 19, &amp;quot;gender&amp;quot;=&amp;gt; &amp;quot;男&amp;quot; ], [ &amp;quot;name&amp;quot; =&amp;gt; &amp;quot;钱七&amp;quot;, &amp;quot;age&amp;quot; =&amp;gt; 22, &amp;quot;gender&amp;quot;=&amp;gt; &amp;quot;男&amp;quot;, &amp;quot;details&amp;quot; =&amp;gt; &amp;quot;我很有钱,排行老七!&amp;quot; ] ]);</code></pre> </li> <li> <p>使用 <strong>::create()</strong> 静态方法,来创建要新增的数据;</p> <pre><code class="language-php">$user = User::create([ &amp;quot;name&amp;quot; =&amp;gt; &amp;quot;李逍遥&amp;quot;, &amp;quot;age&amp;quot; =&amp;gt; 18, &amp;quot;gender&amp;quot;=&amp;gt; &amp;quot;男&amp;quot;, &amp;quot;details&amp;quot; =&amp;gt; &amp;quot;我是一代主角!&amp;quot; ], [&amp;quot;name&amp;quot;, &amp;quot;age&amp;quot;, &amp;quot;gender&amp;quot;, &amp;quot;details&amp;quot;], false); //参数 1 是新增数据数组,必选 //参数 2 是允许写入的字段,可选 //参数 3 为是否 replace 写入,可选,默认 false 为 Insert 写入 return $user-&amp;gt;id;</code></pre> </li> </ul> <h3>2. <strong>删除操作</strong></h3> <ul> <li> <p>使用 find() 方法,通过主键 (id) 查询到想要删除的数据;</p> </li> <li> <p>然后再通过 delete()方法,将数据删除,返回布尔值;</p> <pre><code class="language-php">// 根据主键值,删除数据 $user = User::find(20); return $user-&amp;gt;delete();</code></pre> </li> <li> <p>也可以使用静态方法调用 destroy()方法,通过主键(id)删除数据;</p> <pre><code class="language-php">// 单条删除 return User::destroy(21); // 批量删除 return User::destroy([22, 33, 44]); // 条件删除 return User::where(&amp;quot;id&amp;quot;, &amp;quot;&amp;gt;&amp;quot;, 15)-&amp;gt;delete();</code></pre> </li> <li> <p>destroy() 方法,使用闭包的方式进行删除;</p> <pre><code class="language-php">// 闭包模式 User::destroy(function ($query) { $query-&amp;gt;where(&amp;quot;id&amp;quot;, &amp;quot;&amp;gt;&amp;quot;, 15); });</code></pre> </li> </ul> <h1>20. <strong>模型的更新操作</strong></h1> <p>&lt;div style=&quot;text-align:right;color:#666;font-size:20px;&quot;&gt;主讲老师 - 李炎恢&lt;/div&gt;</p> <h3>1. <strong>数据更新</strong></h3> <ul> <li> <p>使用 find()方法获取数据,然后通过 save()方法保存修改,返回布尔值;</p> <pre><code class="language-php">$user = User::find(19); $user-&amp;gt;details = &amp;quot;我是一代主角!&amp;quot;; return $user-&amp;gt;save();</code></pre> </li> <li> <p>通过 where()方法结合 find()方法的查询条件获取的数据,进行修改;</p> <pre><code class="language-php">$user = User::where(&amp;quot;name&amp;quot;, &amp;quot;李逍遥&amp;quot;)-&amp;gt;find(); $user-&amp;gt;details = &amp;quot;我想做二代主角!&amp;quot;; return $user-&amp;gt;save();</code></pre> </li> <li> <p>save()方法只会更新变化的数据,如果提交的修改数据没有变化,则不更新;</p> </li> <li> <p>但如果你想强制更新数据,即使数据一样,那么可以使用 force()方法;</p> <pre><code class="language-php">// 如何验证被强制了,查看update_time字段是否更新了 $user-&amp;gt;force()-&amp;gt;save();</code></pre> </li> <li> <p>Db::raw()执行 SQL 函数的方式,同样在这里有效;</p> <pre><code class="language-php">$user-&amp;gt;age = Db::raw(&amp;quot;age + 2&amp;quot;);</code></pre> </li> <li> <p>关于验证过滤,后续学习Request再说,手册中 模型 -&gt; 更新 里也有说明:</p> <pre><code class="language-php">$user-&amp;gt;allowField([&amp;quot;name&amp;quot;,&amp;quot;age&amp;quot;])-&amp;gt;save(...)</code></pre> </li> <li> <p>通过 saveAll()方法,可以批量修改数据,返回被修改的数据集合;</p> <pre><code class="language-php">$user = new User; return $user-&amp;gt;saveAll([ [&amp;quot;id&amp;quot;=&amp;gt;17, &amp;quot;gender&amp;quot;=&amp;gt;&amp;quot;女&amp;quot;], [&amp;quot;id&amp;quot;=&amp;gt;18, &amp;quot;gender&amp;quot;=&amp;gt;&amp;quot;女&amp;quot;], [&amp;quot;id&amp;quot;=&amp;gt;19, &amp;quot;gender&amp;quot;=&amp;gt;&amp;quot;女&amp;quot;], ]);</code></pre> </li> <li> <p>使用静态方法::update()更新,返回的是对象实例;</p> <pre><code class="language-php">return User::update([&amp;quot;id&amp;quot;=&amp;gt;17, &amp;quot;gender&amp;quot;=&amp;gt;&amp;quot;男&amp;quot;]); // ID放在后面,返回数据不含ID return User::update([&amp;quot;gender&amp;quot;=&amp;gt;&amp;quot;男&amp;quot;], [&amp;quot;id&amp;quot;=&amp;gt;18]); // 限制更新的内容,只允许gender被修改 return User::update([&amp;quot;gender&amp;quot;=&amp;gt;&amp;quot;男&amp;quot;, &amp;quot;name&amp;quot;=&amp;gt;&amp;quot;可笑的人&amp;quot;], [&amp;quot;id&amp;quot;=&amp;gt;19], [&amp;quot;gender&amp;quot;]);</code></pre> </li> </ul> <h1>21. <strong>模型的查询都一样</strong></h1> <p>&lt;div style=&quot;text-align:right;color:#666;font-size:20px;&quot;&gt;主讲老师 - 李炎恢&lt;/div&gt;</p> <h3>1. <strong>模型的查询</strong></h3> <ul> <li> <p>模型的绝大部分语法基本都来自于 <strong>Db::name()</strong> 的查询:</p> </li> <li> <p>在手册 模型 -&gt; 查询 中可以查阅,这里就演示几个常用的意思一下:</p> </li> <li> <p><strong>find()</strong> 单个 和 <strong>select()</strong> 多个;</p> <pre><code class="language-php">$user = User::find(1); $user = User::select(); $user = User::select([1, 3, 5]);</code></pre> </li> <li> <p>也可以使用 where()方法进行条件筛选查询数据;</p> <pre><code class="language-php">$user = User::where(&amp;quot;id&amp;quot;, &amp;quot;&amp;lt;&amp;quot;, 5)-&amp;gt;select();</code></pre> </li> <li> <p>模型方法也可以使用 where 等连缀查询,和数据库查询方式一样;</p> <pre><code class="language-php">$user = User::limit(3)-&amp;gt;order(&amp;quot;id&amp;quot;, &amp;quot;desc&amp;quot;)-&amp;gt;select();</code></pre> </li> <li> <p>模型支持聚合查询:max、min、sum、count、avg 等;</p> <pre><code class="language-php">$user = User::count();</code></pre> </li> <li> <p>模型也支持大量的快捷方式,这里演示一个:</p> <pre><code class="language-php">$user = User::whereLike(&amp;quot;name&amp;quot;, &amp;quot;%王%&amp;quot;)-&amp;gt;select();</code></pre> </li> </ul> <h1>22. <strong>模型的字段设置</strong></h1> <p>&lt;div style=&quot;text-align:right;color:#666;font-size:20px;&quot;&gt;主讲老师 - 李炎恢&lt;/div&gt;</p> <h3>1. <strong>字段设置</strong></h3> <ul> <li> <p>模型的数据字段和表字段是对应关系,默认会自动获取,包括字段的类型;</p> </li> <li> <p>自动获取会导致增加一次查询,如果在模型中配置字段信息,会减少内存开销;</p> </li> <li> <p>可以在模型设置$schema 字段,明确定义字段信息,字段需要对应表写完整;</p> </li> <li> <p>字段类型的定义可以使用PHP类型或者数据库的字段类型都可以,以便自动绑定类型;</p> <pre><code class="language-php">// 设置字段信息,需要写完整的数据表字段 protected $schema = [ &amp;quot;id&amp;quot; =&amp;gt; &amp;quot;int&amp;quot;, &amp;quot;name&amp;quot; =&amp;gt; &amp;quot;string&amp;quot;, ... ];</code></pre> </li> <li> <p>设置模型字段,只能对模型有效,对于 Db::name() 查询无法作用。</p> </li> <li> <p>要让模型和Db查询都支持字段类型设置,分三步:</p> <ul> <li> <p>把上面的$schema先注释掉;</p> </li> <li>在 config/database.php 开启缓存字段;</li> </ul> <pre><code class="language-php">// 开启字段缓存 &amp;quot;fields_cache&amp;quot; =&amp;gt; true,</code></pre> <ul> <li>在根目录命令行执行命令:</li> </ul> <pre><code>php think optimize:schema</code></pre> </li> </ul> <h3>2. <strong>废弃字段</strong></h3> <ul> <li> <p>由于历史遗留问题,我们不再想使用某些字段,可以在模型里设置;</p> </li> <li> <p>设置后,我们在查询和写入时将忽略这些字段;</p> <pre><code class="language-php">// 设置废弃字段 protected $disuse = [&amp;quot;age&amp;quot;, &amp;quot;details&amp;quot;];</code></pre> </li> </ul> <h3>3. <strong>只读字段</strong></h3> <ul> <li> <p>只读字段用来保护某些特殊的字段值不被更改,这个字段的值一旦写入,就无法更改;</p> <pre><code class="language-php">// 设置只读字段 protected $readonly = [&amp;quot;age&amp;quot;, &amp;quot;details&amp;quot;];</code></pre> </li> <li> <p>然后在控制器端进行修改测试:</p> <pre><code class="language-php">// 修改查看只读字段 return User::update([&amp;quot;id&amp;quot;=&amp;gt;19, &amp;quot;age&amp;quot;=&amp;gt;22, &amp;quot;name&amp;quot;=&amp;gt;&amp;quot;李逍遥2&amp;quot;, &amp;quot;details&amp;quot;=&amp;gt;&amp;quot;可笑&amp;quot;]);</code></pre> </li> </ul> <h1>23. <strong>获取器和修改器</strong></h1> <p>&lt;div style=&quot;text-align:right;color:#666;font-size:20px;&quot;&gt;主讲老师 - 李炎恢&lt;/div&gt;</p> <h3>1. <strong>获取器</strong></h3> <ul> <li> <p>获取器的作用是对模型实例的数据做出自动处理;</p> </li> <li> <p>一个获取器对应模型的一个特殊方法,该方法为 public;</p> </li> <li> <p>方法名的命名规范为:<strong>getFieldAttr</strong>();</p> </li> <li> <p>举个例子,数据库表示状态 status 字段采用的是数值;</p> </li> <li> <p>而页面上,我们需要输出 status 字段希望是中文,就可以使用获取器;</p> </li> <li> <p>在 User 模型端,我创建一个对外的方法,如下:</p> <pre><code class="language-php">// 获取器,改变字段的值 public function getStatusAttr($value) { $status = [-1=&amp;gt;&amp;quot;删除&amp;quot;, 0=&amp;gt;&amp;quot;冻结&amp;quot;, 1=&amp;gt;&amp;quot;正常&amp;quot;, 2=&amp;gt;&amp;quot;待审核&amp;quot;]; return $status[$value]; }</code></pre> </li> <li> <p>控制器端,正常输出数据:</p> <pre><code class="language-php">public function attr() { $user = User::select(); return json($user); }</code></pre> </li> <li> <p>如果你定义了获取器,并且想获取原始值,可以使用 getData()方法;</p> <pre><code class="language-php">$user = User::find(1); echo $user-&amp;gt;getData(&amp;quot;status&amp;quot;);</code></pre> </li> <li> <p>使用 withAttr 在控制器端实现动态获取器,比如让年龄+100岁;</p> <pre><code class="language-php">// 可以传入参数二 $data,获得所有数据,方便数据获取和判断 $user = User::select()-&amp;gt;withAttr(&amp;quot;age&amp;quot;, function($value) { return $value + 100; });</code></pre> </li> </ul> <h3>2. <strong>修改器</strong></h3> <ul> <li> <p>模型修改器的作用,就是对模型设置对象的值进行处理;</p> </li> <li> <p>比如,我们要新增数据的时候,对数据就行格式化、过滤、转换等处理;</p> </li> <li> <p>模型修改器的命名规则为:<strong>setFieldAttr</strong>;</p> </li> <li> <p>我们要设置一个新增,规定输入的年龄都自动+100岁,修改器如下:</p> <pre><code class="language-php">// 修改器,写入时改变字段的值 public function setAgeAttr($value) { return $value + 100; }</code></pre> <pre><code class="language-php">return User::create([ &amp;quot;name&amp;quot; =&amp;gt; &amp;quot;酒剑仙&amp;quot;, &amp;quot;age&amp;quot; =&amp;gt; 58, &amp;quot;gender&amp;quot;=&amp;gt; &amp;quot;男&amp;quot;, &amp;quot;details&amp;quot; =&amp;gt; &amp;quot;我是隐藏主角!&amp;quot; ]);</code></pre> </li> <li>除了新增,会调用修改器,修改更新也会触发修改器;</li> <li>模型修改器只对模型方法有效,调用数据库的方法是无效的,比如-&gt;insert();</li> </ul> <h1>24. <strong>搜索器和自动时间戳</strong></h1> <p>&lt;div style=&quot;text-align:right;color:#666;font-size:20px;&quot;&gt;主讲老师 - 李炎恢&lt;/div&gt;</p> <h3>1. <strong>搜索器</strong></h3> <ul> <li> <p>搜索器是用于封装字段(或搜索标识)的查询表达式,类似查询范围;</p> </li> <li> <p>一个搜索器对应模型的一个特殊方法,该方法为 public;</p> </li> <li> <p>方法名的命名规范为:<strong>searchFieldAttr()</strong>;</p> </li> <li> <p>举个例子,我们要封装一个 <strong>name</strong> 字段的模糊查询,然后封装一个时间限定查询;</p> </li> <li> <p>在 User 模型端,我创建两个对外的方法,如下:</p> <pre><code class="language-php">// 搜索器,模糊查找姓名 public function searchNameAttr($query, $value, $data) { $query-&amp;gt;where(&amp;quot;name&amp;quot;, &amp;quot;like&amp;quot;, &amp;quot;%&amp;quot;.$value.&amp;quot;%&amp;quot;); } // 搜索器,限定时间 public function searchCreateTimeAttr($query, $value, $data) { $query-&amp;gt;whereBetweenTime(&amp;quot;create_time&amp;quot;, $value[0], $value[1]); }</code></pre> </li> <li> <p>在控制器端,通过 withSearch()方法实现模型搜索器的调用;</p> <pre><code class="language-php">$user = User::withSearch([&amp;quot;name&amp;quot;, &amp;quot;create_time&amp;quot;],[ &amp;quot;name&amp;quot; =&amp;gt; &amp;quot;李&amp;quot;, &amp;quot;create_time&amp;quot; =&amp;gt; [&amp;quot;2023-10-19&amp;quot;, &amp;quot;2023-10-20 23:59:59&amp;quot;] ])-&amp;gt;select();</code></pre> </li> <li> <p>withSearch()中第一个数组参数,限定搜索器的字段,第二个则是表达式值;</p> </li> <li> <p>如果想在搜索器查询的基础上再增加查询条件,直接使用链式查询即可;</p> <pre><code class="language-php">User::withSearch(...)-&amp;gt;where(&amp;quot;gender&amp;quot;, &amp;quot;女&amp;quot;)-&amp;gt;select();</code></pre> </li> <li> <p>在获取器和修改器都有一个 <strong>$data</strong> 参数,它的作用是什么?</p> <pre><code class="language-php">// 搜索器,模糊查找姓名 public function searchNameAttr($query, $value, $data) { $query-&amp;gt;where(&amp;quot;name&amp;quot;, &amp;quot;like&amp;quot;, &amp;quot;%&amp;quot;.$value.&amp;quot;%&amp;quot;); // 按年龄排序 if (isset($data[&amp;quot;sort&amp;quot;])) { $query-&amp;gt;order($data[&amp;quot;sort&amp;quot;]); } }</code></pre> </li> </ul> <h3>2. <strong>自动时间戳</strong></h3> <ul> <li> <p>如果你想全局开启,在 database.php 中,设置为 true;</p> </li> <li> <p>此时,写入操作时,会自动对 <strong>create_time</strong> 和 <strong>update_time</strong> 进行写入;</p> <pre><code class="language-php">&amp;quot;auto_timestamp&amp;quot; =&amp;gt; true,</code></pre> </li> <li> <p>如果你只想设置某一个模型开启,需要设置特有字段;</p> <pre><code class="language-php">protected $autoWriteTimestamp = true;</code></pre> </li> <li> <p>自动时间戳只能在模型下有效,数据库方法不可以使用;</p> </li> <li> <p>如果创建和修改时间戳不是默认定义的,也可以自定义;</p> <pre><code class="language-php">protected $createTime = &amp;quot;create_at&amp;quot;; protected $updateTime = &amp;quot;update_at&amp;quot;;</code></pre> </li> <li> <p>如果业务中只需要 create_time 而不需要 update_time,可以关闭它;</p> <pre><code class="language-php">protected $updateTime = false;</code></pre> </li> <li> <p>也可以动态实现不修改 update_time,具体如下:</p> <pre><code class="language-php">$user-&amp;gt;isAutoWriteTimestamp(false)-&amp;gt;save();</code></pre> </li> </ul> <h1>25. <strong>软删除和事件</strong></h1> <p>&lt;div style=&quot;text-align:right;color:#666;font-size:20px;&quot;&gt;主讲老师 - 李炎恢&lt;/div&gt;</p> <h3>1. <strong>软删除</strong></h3> <ul> <li> <p>软删除也称为逻辑删除,只是给数据标记 “已删除” 的状态,不是真实的物理删除;</p> </li> <li> <p>为何要对数据进行软删除,因为真实的物理删除,删了就没了呀。</p> </li> <li> <p>在模型端设置软删除的功能,引入 <strong>SoftDelete</strong>,它是 <strong>trait</strong>;</p> <pre><code class="language-php">// 会自动引入SoftDelete use think\model\concern\SoftDelete; // 开启软删除,创建delete_time字段,并设置默认为 NULL use SoftDelete; protected $deleteTime = &amp;quot;delete_time&amp;quot;;</code></pre> </li> <li> <p>delete_time 默认设置的是 null,如果你想更改这个默认值,可以设置:</p> <pre><code class="language-php">protected $defaultSoftDelete = 0;</code></pre> </li> <li> <p>由于我们之前演示过字段缓存,会导致无法软删除,你可以删除字段缓存,或者重新更新下:</p> <pre><code class="language-php">php think optimize:schema</code></pre> </li> <li> <p>删除分为两种:destroy() 和 delete(),具体如下:</p> <pre><code class="language-php">// 软删除 User::destroy(1); // 真实删除 User::destroy(1,true); $user = User::find(1); // 软删除 $user-&amp;gt;delete(); // 真实删除 $user-&amp;gt;force()-&amp;gt;delete();</code></pre> </li> <li> <p>软删除后,数据库内的数据只是被标记了删除时间,而搜索数据时,会自动屏蔽这些数据;</p> </li> <li> <p>在开启软删除功能的前提下,使用 <strong>withTrashed()</strong> 方法取消屏蔽软删除的数据;</p> <pre><code class="language-php">User::withTrashed()-&amp;gt;select();</code></pre> </li> <li> <p>如果只想查询被软删除的数据,使用 onlyTrashed()方法即可;</p> <pre><code class="language-php">User::onlyTrashed()-&amp;gt;select()</code></pre> </li> <li> <p>如果想让某一条被软删除的数据恢复到正常数据,可以使用 restore()方法;</p> <pre><code class="language-php">$user = User::onlyTrashed()-&amp;gt;find(23); $user-&amp;gt;restore();</code></pre> </li> <li>如何要将软删除后的数据库真实的物理删除,需要先将它恢复,再真实删除;</li> </ul> <h3>2. 事件</h3> <ul> <li> <p>在手册 -&gt; 模型 -&gt; 模型事件中罗列了所有的模型,这里演示常用的意思一下;</p> </li> <li> <p>在模型端使用静态方法调用即可完成事件触发,比如执行了查询方法后调用事件:</p> <pre><code class="language-php">// 当执行了查询方法,则调用我 protected static function onAfterRead($user) { // $query是数据集,可用于数据判断 echo &amp;quot;执行了查询!&amp;quot;.$user-&amp;gt;id; }</code></pre> </li> </ul> <h1>26. 关联模型入门</h1> <p>&lt;div style=&quot;text-align:right;color:#666;font-size:20px;&quot;&gt;主讲老师 - 李炎恢&lt;/div&gt;</p> <h3>1. <strong>关联表</strong></h3> <ul> <li> <p>我们已经有了一张 <strong>tp_user</strong> 表,主键为:<strong>id</strong>;我们需要一个附属表,来进行关联;</p> </li> <li> <p>附属表:<strong>tp_profile</strong>,建立两个字段:<strong>user_id</strong> 和 <strong>hobby</strong>,外键是 <strong>user_id</strong>;</p> <p>&lt;img src=&quot;ThinkPHP8.x.assets/26-1.jpg&quot; style=&quot;zoom:60%;margin:0&quot; /&gt;</p> </li> </ul> <h3>2. <strong>关联查询</strong></h3> <ul> <li> <p>关联模型,顾名思义,就是将表与表之间进行关联和对象化,更高效的操作数据;</p> </li> <li> <p>创建 <strong>User</strong> 模型和 <strong>Profile</strong> 模型,均为空模型;如果已有User,改名UserBak备份起来;</p> <pre><code class="language-php">namespace app\model; use think\Model; class User extends Model {}</code></pre> <pre><code class="language-php">namespace app\model; use think\Model; class Profile extends Model {}</code></pre> </li> <li> <p><strong>User</strong> 模型端,需要关联 <strong>Profile</strong>,具体方式如下:</p> <pre><code class="language-php">class User extends Model { public function profile() { // 一对一关联, // 参数1:关联的表模型 // 参数2:默认为 user_id (外键) return $this-&amp;gt;hasOne(Profile::class); } }</code></pre> </li> <li> <p>创建一个控制器用于测试输出:Link.php;</p> <pre><code class="language-php">public function index() { // 主表 $user = User::find(19); // 访问关联从表 return json($user-&amp;gt;profile); }</code></pre> </li> </ul> <h1>27. 一对一关联查询</h1> <p>&lt;div style=&quot;text-align:right;color:#666;font-size:20px;&quot;&gt;主讲老师 - 李炎恢&lt;/div&gt;</p> <h3>1. <strong>hasOne 模式</strong></h3> <ul> <li> <p><strong>hasOne</strong> 模式,适合主表关联附表,具体设置方式如下:</p> <pre><code class="language-php">hasOne(&amp;quot;关联模型&amp;quot;,[&amp;quot;外键&amp;quot;,&amp;quot;主键&amp;quot;]); return $this-&amp;gt;hasOne(Profile::class,&amp;quot;user_id&amp;quot;, &amp;quot;id&amp;quot;); //关联模型(必须):关联的模型名或者类名 //外键:默认的外键规则是当前模型名(不含命名空间,下同)+_id ,例如 user_id //主键:当前模型主键,默认会自动获取也可以指定传入</code></pre> </li> <li> <p>在上一节课,我们了解了表与表关联后,实现的查询方案:</p> <pre><code class="language-php">// 主表 $user = User::find(19); // 访问关联从表 return json($user-&amp;gt;profile-&amp;gt;hobby);</code></pre> </li> <li> <p>使用 save()方法,可以设置关联修改,通过主表修改附表字段的值:</p> <pre><code class="language-php">$user = User::find(19); return $user-&amp;gt;profile-&amp;gt;save([&amp;quot;hobby&amp;quot;=&amp;gt;&amp;quot;和蛇妖玩耍!&amp;quot;]);</code></pre> </li> <li> <p>-&gt;<strong>profile</strong> 属性方式可以修改数据,-&gt;<strong>profile</strong>()方法方式可以新增数据:</p> <pre><code class="language-php">// 新增附表数据,先找到主表数据 $user = User::find(1); // 然后通过profile()方法实现新增 return $user-&amp;gt;profile()-&amp;gt;save([&amp;quot;hobby&amp;quot;=&amp;gt;&amp;quot;不喜欢吃青椒!&amp;quot;]);</code></pre> </li> </ul> <h3>2. <strong>belongsTo 模式</strong></h3> <ul> <li> <p>belongsTo 模式,适合附表关联主表,具体设置方式如下:</p> <pre><code class="language-php">// 注意:此时绑定需要Profile模型创建user()方法执行 belongsTo(&amp;quot;关联模型&amp;quot;,[&amp;quot;外键&amp;quot;,&amp;quot;关联主键&amp;quot;]); class Profile extends Model { public function user() { return $this-&amp;gt;belongsTo(User::class); } }</code></pre> </li> <li> <p>查询方式,和主附查询方式一致:</p> <pre><code class="language-php">// 附表 $profile = Profile::find(1); // 访问关联主表 return $profile-&amp;gt;user-&amp;gt;name;</code></pre> </li> <li> <p>使用 hasOne()也能模拟 belongsTo() 来进行查询,这样就可以不用在 Profile 模型进行设置:</p> <pre><code class="language-php">// hasWhere // 注意:参数1的profile是方法名,不是模型名 $user = User::hasWhere(&amp;quot;profile&amp;quot;, [&amp;quot;id&amp;quot;=&amp;gt;2])-&amp;gt;find(); return json($user); // 闭包方式 $user = User::hasWhere(&amp;quot;profile&amp;quot;, function ($query) { $query-&amp;gt;where(&amp;quot;id&amp;quot;, 2); })-&amp;gt;find(); return json($user);</code></pre> </li> </ul> <h1>28. 一对多关联查询</h1> <p>&lt;div style=&quot;text-align:right;color:#666;font-size:20px;&quot;&gt;主讲老师 - 李炎恢&lt;/div&gt;</p> <h3>1. <strong>hasMany 模式</strong></h3> <ul> <li> <p>hasMany 模式,适合主表关联附表,实现一对多查询,具体设置方式如下:</p> <pre><code class="language-php">// 由于是一对多,需要在附表添加多个相同user_id的数据测试 hasMany(&amp;quot;关联模型&amp;quot;,[&amp;quot;外键&amp;quot;,&amp;quot;主键&amp;quot;]); return $this-&amp;gt;hasMany(Profile::class,&amp;quot;user_id&amp;quot;, &amp;quot;id&amp;quot;);</code></pre> </li> <li> <p>查询方案和一对一相同:</p> <pre><code class="language-php">// 主表一对多 $user = User::find(1); return json($user-&amp;gt;profile);</code></pre> </li> <li> <p>使用-&gt;profile()方法模式,可以进一步进行数据的筛选;</p> <pre><code class="language-php">// 主表一对多 $user = User::find(1); // 进一步筛选数据,保留实际顺序的下标 $data = $user-&amp;gt;profile-&amp;gt;where(&amp;quot;id&amp;quot;, &amp;quot;&amp;gt;&amp;quot;, 10); // 进一步筛选数据,下标重新从0开始,需要连缀select() $data = $user-&amp;gt;profile()-&amp;gt;where(&amp;quot;id&amp;quot;, &amp;quot;&amp;gt;&amp;quot;, 10)-&amp;gt;select(); return json($data);</code></pre> </li> <li> <p>使用 has()方法,查询关联附表的主表内容,比如大于等于 2 条的主表记录;</p> <pre><code class="language-php">// 参数1:profile是方法名 $user = User::has(&amp;quot;profile&amp;quot;, &amp;quot;&amp;gt;=&amp;quot;, 2)-&amp;gt;select(); return json($user);</code></pre> </li> <li> <p>使用 hasWhere()方法,查询附表中,可见兴趣的主表记录;</p> <pre><code class="language-php">// 查询附表profile中visible为1的兴趣关联主表的记录 $user = User::hasWhere(&amp;quot;profile&amp;quot;, [&amp;quot;visible&amp;quot;=&amp;gt;1])-&amp;gt;select(); return json($user);</code></pre> </li> <li> <p>使用 save()和 saveAll()进行关联新增和批量关联新增,方法如下:</p> <pre><code class="language-php">// 主表数据 $user = User::find(24); // 新增附表关联数据 $user-&amp;gt;profile()-&amp;gt;save([&amp;quot;hobby&amp;quot;=&amp;gt;&amp;quot;测试喜欢1&amp;quot;, &amp;quot;visible&amp;quot;=&amp;gt;1]); // 批量新增 $user-&amp;gt;profile()-&amp;gt;saveAll([ [&amp;quot;hobby&amp;quot;=&amp;gt;&amp;quot;测试喜欢2&amp;quot;, &amp;quot;visible&amp;quot;=&amp;gt;1], [&amp;quot;hobby&amp;quot;=&amp;gt;&amp;quot;测试喜欢3&amp;quot;, &amp;quot;visible&amp;quot;=&amp;gt;1], ]);</code></pre> </li> <li> <p>使用 together()方法,可以删除主表内容时,将附表关联的内容全部删除;</p> <pre><code class="language-php">// 删除主数据,并清空关联附表数据 $user = User::with(&amp;quot;profile&amp;quot;)-&amp;gt;find(29); $user-&amp;gt;together([&amp;quot;profile&amp;quot;])-&amp;gt;delete();</code></pre> </li> <li> <p>特别注意:由于外键约束设置问题,默认情况下,关联操作可能会导致1451错误;</p> </li> <li> <p>解决方案:在 profile 表中 设置外键 删除和修改时 为:CASCADE即可,详细阅读如下:</p> <pre><code class="language-php">https://blog.csdn.net/qq_23994787/article/details/86063623</code></pre> </li> </ul> <h1>29. 模型预载入和统计</h1> <p>&lt;div style=&quot;text-align:right;color:#666;font-size:20px;&quot;&gt;主讲老师 - 李炎恢&lt;/div&gt;</p> <h3>1. <strong>预载入</strong></h3> <ul> <li> <p>在普通的关联查询下,我们循环数据列表会执行 n+1 次 SQL 查询;</p> <pre><code class="language-php">// 主表三条记录 $list = User::select([10, 11, 12]); // 遍历附表 foreach ($list as $user) { dump($user-&amp;gt;profile); }</code></pre> </li> <li> <p>上面继续采用普通关联查询的构建方式,打开 trace 调试工具,会得到四次查询;</p> </li> <li> <p>如果采用关联预载入的方式,将会减少到两次,也就是起步一次,循环一次;</p> <pre><code class="language-php">$list = User::with([&amp;quot;profile&amp;quot;])-&amp;gt;select([10, 11, 12, 17, 18, 19]); foreach ($list as $user) { dump($user-&amp;gt;profile); }</code></pre> <pre><code class="language-php">// 查看显示结构 $list = User::with([&amp;quot;profile&amp;quot;])-&amp;gt;select([1, 10, 22]); return json($list);</code></pre> </li> <li> <p>关联预载入减少了查询次数提高了性能,但是不支持多次调用;</p> </li> <li> <p>如果你有主表关联了多个附表,都想要进行预载入,可以传入多个模型方法即可;</p> <pre><code class="language-php">User::with([&amp;quot;profile&amp;quot;, &amp;quot;book&amp;quot;])</code></pre> </li> <li> <p>上面显示结构中,主表和附表的字段已经非常多了,需要对两个表字段进行筛略:</p> <pre><code class="language-php">// 注意1:withField对应另一个是withoutField // 注意2:关联字段一定要包含外键:user_id,否则空 $list = User::field(&amp;quot;id,age,gender,details&amp;quot;)-&amp;gt;with([&amp;quot;profile&amp;quot; =&amp;gt; function($query) { $query-&amp;gt;withField([&amp;quot;user_id, hobby&amp;quot;]); }])-&amp;gt;select([1, 10, 22]); return json($list); // 或者简单些 $list = User::with(&amp;quot;profile&amp;quot;)-&amp;gt;select(); // 直接字段,隐藏主表,加上profile隐藏附表,除了hidden,还有对应的visible方法 return json($list-&amp;gt;hidden([&amp;quot;status&amp;quot;, &amp;quot;profile.visible&amp;quot;]));</code></pre> </li> <li>还有一些 预载入缓存、延迟预载入,可以参考手册;</li> </ul> <h3>2. <strong>关联统计</strong></h3> <ul> <li> <p>使用 withCount()方法,可以统计主表关联附表的个数,输出用 profile_count;</p> <pre><code class="language-php">// 统计这三条数据关联的附表数据的个数 $list = User::withCount([&amp;quot;profile&amp;quot;])-&amp;gt;select([1, 10, 22]); foreach ($list as $user) { echo $user-&amp;gt;profile_count.&amp;quot;&amp;lt;br&amp;gt;&amp;quot;; }</code></pre> </li> <li> <p>关联统计的输出采用“关联方法名” <strong>_count</strong>,这种结构输出;</p> </li> <li> <p>不单单支持 Count,还有如下统计方法,均可支持;</p> </li> <li> <p><strong>withMax()</strong>、<strong>withMin()</strong>、<strong>withSum()</strong>、<strong>withAvg()</strong>等;</p> </li> <li> <p>除了 withCount()不需要指定字段,其它均需要指定统计字段;</p> <pre><code class="language-php">// 统计附表关联字段的累加和 $list = User::withSum([&amp;quot;profile&amp;quot;], &amp;quot;visible&amp;quot;)-&amp;gt;select([1, 10, 22]); foreach ($list as $user) { echo $user-&amp;gt;profile_sum.&amp;quot;&amp;lt;br&amp;gt;&amp;quot;; }</code></pre> </li> <li> <p>对于输出的属性,可以自定义:</p> <pre><code class="language-php">User::withSum([&amp;quot;profile&amp;quot;=&amp;gt;&amp;quot;p_s&amp;quot;], &amp;quot;visible&amp;quot;) $user-&amp;gt;p_s</code></pre> </li> </ul> <h1>30. 多对多关联查询</h1> <p>&lt;div style=&quot;text-align:right;color:#666;font-size:20px;&quot;&gt;主讲老师 - 李炎恢&lt;/div&gt;</p> <h3>1. <strong>建立三张表</strong></h3> <ul> <li> <p>复习一下一对一,一个用户对应一个用户档案资料,是一对一关联;</p> </li> <li> <p>复习一下一对多,一篇文章对应多个评论,是一对多关联;</p> </li> <li> <p>多对多怎么理解,分解来看,一个用户对应多个角色,而一个角色对应多个用户;</p> </li> <li> <p>那么这种对应关系,就是多对多关系,最经典的应用就是权限控制;</p> <p>&lt;img src=&quot;ThinkPHP8.x.assets/30-1.jpg&quot; style=&quot;zoom:65%;margin:0&quot; /&gt;</p> </li> <li> <p>tp_user:用户表;tp_role:角色表;tp_access:中间表;</p> </li> <li> <p>access 表包含了 user 和 role 表的关联 id,多对多模式;</p> <pre><code class="language-php">class User extends Model { public function role() { // belongsToMany(&amp;quot;关联模型&amp;quot;,&amp;quot;中间表&amp;quot;,[&amp;quot;外键&amp;quot;,&amp;quot;关联键&amp;quot;]); return $this-&amp;gt;belongsToMany(Role::class, Access::class); } }</code></pre> <pre><code class="language-php">class Role extends Model{}</code></pre> <pre><code class="language-php">// 这里继承的是Pivot,它本身也继承了Model // Pivoit是中间表基类,多对多专用模型 class Access extends Pivot{}</code></pre> </li> </ul> <h3>2. <strong>权限控制</strong></h3> <ul> <li> <p>在控制器段,我们查询一下id为1的用户,并关联查询它的权限:</p> <pre><code class="language-php">// 获取一个用户,张三 $user = User::find(1); // 获取这个用户所有角色 $role = $user-&amp;gt;role; return json($role);</code></pre> </li> <li> <p>当我们要给一个用户创建一个角色时,用到多对多关联新增;</p> <pre><code class="language-php">// 如果这个角色不存在,则会给角色表增加一条信息 // 并且,会在中间表关联角色和用户 $user-&amp;gt;role()-&amp;gt;save([&amp;quot;type&amp;quot;=&amp;gt;&amp;quot;测试管理专员&amp;quot;]); // 也支持批量 $user-&amp;gt;role()-&amp;gt;saveAll([[...],[...]]);</code></pre> </li> <li> <p>一般来说,上面的这种新增方式,用于初始化角色比较合适;</p> </li> <li> <p>但是,很多情况下,角色权限是初始化好的,只需要添加中间表,而不是角色表;</p> </li> <li> <p>那么,我们真正需要就是通过用户表新增到中间表关联即可;</p> <pre><code class="language-php">// 给张三添加一个已经存在的角色,直接传角色ID即可 $user-&amp;gt;role()-&amp;gt;save(1); // 或 $user-&amp;gt;role()-&amp;gt;save(Role::find(1)); $user-&amp;gt;role()-&amp;gt;saveAll([1,2,3]); // 或,如果有其它字段,可以通过中括号添加 $user-&amp;gt;role()-&amp;gt;attach(1); $user-&amp;gt;role()-&amp;gt;attach(2, [&amp;quot;details&amp;quot;=&amp;gt;&amp;quot;测试详情&amp;quot;]);</code></pre> </li> <li> <p>除了新增,还有直接删除中间表数据的方法:</p> <pre><code class="language-php">// 取消掉张三的所有,1,2,6,这里的值是角色的ID,不是中间表ID $user-&amp;gt;role()-&amp;gt;detach(1); $user-&amp;gt;role()-&amp;gt;detach([2, 6]);</code></pre> </li> </ul> <h1>31. 路由定义入门</h1> <p>&lt;div style=&quot;text-align:right;color:#666;font-size:20px;&quot;&gt;主讲老师 - 李炎恢&lt;/div&gt;</p> <h3>1. <strong>路由入门</strong></h3> <ul> <li> <p>路由的作用就是让 URL 地址更加的规范和优雅,或者说更加简洁;</p> </li> <li> <p>设置路由对 URL 的检测、验证等一系列操作提供了极大的便利性;</p> </li> <li> <p>路由是默认开启的,如果想要关闭路由,在 <strong>config/app.php</strong> 配置;</p> <pre><code class="language-php">// 是否启用路由 &amp;quot;with_route&amp;quot; =&amp;gt; true,</code></pre> </li> <li> <p>路由的配置文件在 <strong>config/route.php</strong> 中,定义文件在 <strong>route/app.php</strong>;</p> </li> <li> <p>我们还回到最初的 Index 控制器,创建一个 details 带 参数的方法;</p> <pre><code class="language-php">public function details($id) { return &amp;quot;details ID:&amp;quot;.$id; }</code></pre> <pre><code class="language-php">http://www.tp.com:8000/index/details/id/5</code></pre> </li> <li> <p>此时,我们在根目录 route 下的 app.php 里配置路由:</p> <pre><code class="language-php">// 参数1:url/参数 // 参数2:控制器/方法 Route::rule(&amp;quot;details/:id&amp;quot;, &amp;quot;Index/details&amp;quot;); // 访问地址 http://www.tp.com:8000/details/5</code></pre> </li> <li> <p>rule()方法是默认请求是 any,即任何请求类型均可,第三参数可以限制:</p> <pre><code class="language-php">Route::rule(&amp;quot;details/:id&amp;quot;, &amp;quot;Index/xxx&amp;quot;, &amp;quot;GET&amp;quot;); Route::rule(&amp;quot;details/:id&amp;quot;, &amp;quot;Index/xxx&amp;quot;, &amp;quot;POST&amp;quot;); Route::rule(&amp;quot;details/:id&amp;quot;, &amp;quot;Index/xxx&amp;quot;, &amp;quot;GET|POST&amp;quot;);</code></pre> </li> <li> <p>所有的请求方式均有快捷方式,比如 <strong>::get()</strong> 、<strong>::post()</strong> 等,具体查看手册:路由 -&gt; 路由定义;</p> <pre><code class="language-php">// 快捷方式,无须第三参数了 Route::get(...) Route::post(...) Route::delete(...)</code></pre> </li> <li> <p>在路由的规则表达式中,有多种地址的配置规则:</p> <pre><code class="language-php">// 静态路由 Route::rule(&amp;quot;test&amp;quot;, &amp;quot;Index/test&amp;quot;); // 带一个参数 Route::rule(&amp;quot;details/:id&amp;quot;, &amp;quot;Index/details&amp;quot;); // 带两个参数 Route::rule(&amp;quot;details/:id/:uid&amp;quot;, &amp;quot;Index/details&amp;quot;); // 带可选参数,一般在后面 Route::rule(&amp;quot;details/:id/[:uid]&amp;quot;, &amp;quot;Index/details&amp;quot;); // 全动态地址,不限定details,url可以是:abc/5/6,后面details也可以动态 Route::rule(&amp;quot;:details/:id/:uid&amp;quot;, &amp;quot;Index/details&amp;quot;); // 正则规则,完全匹配 Route::rule(&amp;quot;details/:id/:uid$&amp;quot;, &amp;quot;Index/details&amp;quot;);</code></pre> </li> </ul> <h3>2. <strong>强制路由</strong></h3> <ul> <li> <p>目前来说,路由访问模式和URL访问模式都可以使用,但我们强制路由访问;</p> </li> <li> <p>开始强制路由,需要在 route.php 里面进行配置:</p> <pre><code class="language-php">// 是否强制使用路由 &amp;quot;url_route_must&amp;quot; =&amp;gt; true,</code></pre> <pre><code class="language-php">// 首页也必须设置路由 Route::rule(&amp;quot;/&amp;quot;, &amp;quot;Index/index&amp;quot;);</code></pre> </li> </ul> <h1>32. 路由闭包.变量规则</h1> <p>&lt;div style=&quot;text-align:right;color:#666;font-size:20px;&quot;&gt;主讲老师 - 李炎恢&lt;/div&gt;</p> <h3>1. <strong>闭包</strong></h3> <ul> <li> <p>闭包支持我们可以通过 URL 直接执行,而不需要通过控制器和方法;</p> <pre><code class="language-php">// 闭包 Route::get(&amp;quot;think&amp;quot;, function () { return &amp;quot;hello, ThinkPHP8!&amp;quot;; });</code></pre> </li> <li> <p>闭包支持也可以传递参数和动态规则:</p> <pre><code class="language-php">// 带参数闭包,如果不带:version,那么地址:php?version=8 Route::get(&amp;quot;php/:version&amp;quot;, function ($version) { return &amp;quot;PHP&amp;quot;.$version; });</code></pre> </li> </ul> <h3>2. <strong>变量规则</strong></h3> <ul> <li> <p>系统默认的路由变量规则为\w+,即字母、数字、中文和下划线;</p> </li> <li> <p>如果你想更改默认的匹配规则,可以修改 <strong>config/route.php</strong> 配置;</p> <pre><code class="language-php">// 默认的路由变量规则 &amp;quot;default_route_pattern&amp;quot; =&amp;gt; &amp;quot;[\w\.]+&amp;quot;,</code></pre> </li> <li> <p>如果我们需要对于具体的变量进行单独的规则设置,则需要通过 <strong>pattern()</strong> 方法;</p> </li> <li> <p>将 details 方法里的 id 传值,严格限制必须只能是数字\d+;</p> <pre><code class="language-php">// 正则规则 \d+ 限定id为数字 Route::rule(&amp;quot;details/:id&amp;quot;, &amp;quot;Index/details&amp;quot;) -&amp;gt;pattern([&amp;quot;id&amp;quot;=&amp;gt;&amp;quot;\d+&amp;quot;]); // 多个参数 -&amp;gt;pattern([ &amp;quot;id&amp;quot; =&amp;gt; &amp;quot;\d+&amp;quot;, &amp;quot;uid&amp;quot; =&amp;gt; &amp;quot;\d+&amp;quot; ]);</code></pre> </li> <li> <p>如果让指定的参数统一限定为数字,比如id和uid,也就是全局设置,在app.php顶部设置:</p> <pre><code class="language-php">Route::pattern([ &amp;quot;id&amp;quot; =&amp;gt; &amp;quot;\d+&amp;quot;, &amp;quot;uid&amp;quot; =&amp;gt; &amp;quot;\d+&amp;quot; ]);</code></pre> </li> <li> <p>不喜欢斜杠怎么办?能换成减号吗?可以的:</p> <pre><code class="language-php">// 支持替换斜杠 Route::rule(&amp;quot;details-:id&amp;quot;, &amp;quot;Index/details&amp;quot;); // 支持组合变量&amp;lt;id&amp;gt;方式 Route::rule(&amp;quot;details-&amp;lt;id&amp;gt;&amp;quot;, &amp;quot;Index/details&amp;quot;);</code></pre> </li> </ul> <h1>33. 路由参数.域名.MISS</h1> <p>&lt;div style=&quot;text-align:right;color:#666;font-size:20px;&quot;&gt;主讲老师 - 李炎恢&lt;/div&gt;</p> <h3>1. <strong>参数</strong></h3> <ul> <li> <p>设置路由的时候,可以设置相关方法进行,从而实施匹配检测和行为执行;</p> </li> <li> <p>ext 方法作用是检测 URL 后缀,比如:我们强制所有 URL 后缀为.html;</p> <pre><code class="language-php">Route::rule(&amp;quot;test&amp;quot;, &amp;quot;Index/test&amp;quot;)-&amp;gt;ext(&amp;quot;html&amp;quot;); Route::rule(&amp;quot;test&amp;quot;, &amp;quot;Index/test&amp;quot;)-&amp;gt;ext(&amp;quot;html|shtml&amp;quot;);</code></pre> </li> <li> <p>https 方法作用是检测是否为 https 请求,结合 ext 强制 html 如下:</p> <pre><code class="language-php">Route::rule(&amp;quot;test&amp;quot;, &amp;quot;Index/test&amp;quot;)-&amp;gt;ext(&amp;quot;html&amp;quot;)-&amp;gt;https();</code></pre> </li> <li> <p>如果想让全局统一配置 URL 后缀的话,可以在 config/route.php 中设置;</p> </li> <li> <p>具体值可以是单个或多个后缀,也可以是空字符串(任意后缀),false 禁止后缀;</p> <pre><code class="language-php">// URL伪静态后缀 &amp;quot;url_html_suffix&amp;quot; =&amp;gt; &amp;quot;html&amp;quot;,</code></pre> </li> <li> <p>denyExt 方法作用是禁止某些后缀的使用,使用后直接报错;</p> <pre><code class="language-php">// 可以将url_html_suffix 设置为空测试 Route::rule(&amp;quot;test&amp;quot;, &amp;quot;Index/test&amp;quot;)-&amp;gt;denyExt(&amp;quot;jpg|gif|png&amp;quot;);</code></pre> </li> <li> <p>domain 方法作用是检测当前的域名是否匹配,完整域名和子域名均可;</p> <pre><code class="language-php">Route::rule(&amp;quot;test&amp;quot;, &amp;quot;Index/test&amp;quot;)-&amp;gt;domain(&amp;quot;localhost&amp;quot;); Route::rule(&amp;quot;test&amp;quot;, &amp;quot;Index/test&amp;quot;)-&amp;gt;domain(&amp;quot;new.tp.com&amp;quot;); Route::rule(&amp;quot;test&amp;quot;, &amp;quot;Index/test&amp;quot;)-&amp;gt;domain(&amp;quot;new&amp;quot;);</code></pre> </li> <li> <p>还有ajax/pjax/json检测、filter 额外参数检测、append追加额外参数、option统一管理检测,可参考手册;</p> <pre><code class="language-php">Route::rule(&amp;quot;test&amp;quot;, &amp;quot;Index/test&amp;quot;)-&amp;gt;option([ &amp;quot;ext&amp;quot; =&amp;gt; &amp;quot;html&amp;quot;, &amp;quot;https&amp;quot; =&amp;gt; false, &amp;quot;domain&amp;quot; =&amp;gt; &amp;quot;www.tp.com&amp;quot; ]);</code></pre> </li> </ul> <h3>2. <strong>域名</strong></h3> <ul> <li> <p>如果想限定的某个域名下生效的路由,比如 <strong>news.tp.com</strong> 可以通过域名闭包方式:</p> <pre><code class="language-php">Route::domain(&amp;quot;news.tp.com&amp;quot;, function () { Route::rule(&amp;quot;details/:id&amp;quot;, &amp;quot;Index/details&amp;quot;); }); // 或 Route::domain(&amp;quot;news&amp;quot;, function () { Route::rule(&amp;quot;details/:id&amp;quot;, &amp;quot;Index/details&amp;quot;); });</code></pre> </li> <li>路由域名也支持:ext、pattern、append 等路由参数方法的操作;</li> </ul> <h3>3. <strong>MISS</strong></h3> <ul> <li> <p>全局 MISS,类似开启强制路由功能,匹配不到相应规则时自动跳转到 MISS;</p> <pre><code class="language-php">Route::miss(&amp;quot;Error/miss&amp;quot;); // 闭包模式 Route::miss(function () { return &amp;quot;MISS 404&amp;quot;; });</code></pre> </li> </ul> <h1>34. 路由分组.URL生成</h1> <p>&lt;div style=&quot;text-align:right;color:#666;font-size:20px;&quot;&gt;主讲老师 - 李炎恢&lt;/div&gt;</p> <h3>1. <strong>分组</strong></h3> <ul> <li> <p>路由分组,即将相同前缀的路由合并分组,这样可以简化路由定义,提高匹配效率;</p> </li> <li> <p>使用 group()方法,来进行分组路由的注册;</p> <pre><code class="language-php">Route::group(&amp;quot;index&amp;quot;, function () { Route::rule(&amp;quot;:id&amp;quot;, &amp;quot;Index/details&amp;quot;); Route::rule(&amp;quot;:name&amp;quot;, &amp;quot;Index/hello&amp;quot;); })-&amp;gt;ext(&amp;quot;html&amp;quot;)-&amp;gt;pattern([&amp;quot;id&amp;quot;=&amp;gt;&amp;quot;\d+&amp;quot;]); // URL1: http://www.tp.com:8000/index/5.html // URL2: http://www.tp.com:8000/index/world.html</code></pre> </li> <li> <p>也可以省去第一参数,让分组路由更灵活一些;</p> <pre><code class="language-php">Route::group(function() { Route::rule(&amp;quot;test&amp;quot;, &amp;quot;Index/test&amp;quot;); Route::rule(&amp;quot;h/:name&amp;quot;, &amp;quot;Index/hello&amp;quot;); })-&amp;gt;ext(&amp;quot;html&amp;quot;); // URL1: http://www.tp.com:8000/test.html // URL2: http://www.tp.com:8000/h/world.html</code></pre> </li> <li> <p>使用 prefix()方法,可以省略掉分组地址里的控制器;</p> <pre><code class="language-php">Route::group(&amp;quot;index&amp;quot;, function () { Route::rule(&amp;quot;test&amp;quot;, &amp;quot;test&amp;quot;); Route::rule(&amp;quot;:name&amp;quot;, &amp;quot;hello&amp;quot;); })-&amp;gt;prefix(&amp;quot;Index/&amp;quot;)-&amp;gt;ext(&amp;quot;html&amp;quot;); // URL1: http://www.tp.com:8000/index/test.html // URL2: http://www.tp.com:8000/index/world.html</code></pre> </li> </ul> <h3>2. <strong>URL生成</strong></h3> <ul> <li> <p>使用 <strong>url()</strong> 助手函数来生成 定义好的路由地址,放在在控制器使用;</p> <pre><code class="language-php">// 静态不带参数的 Route::rule(&amp;quot;test&amp;quot;, &amp;quot;Index/test&amp;quot;)-&amp;gt;ext(&amp;quot;html&amp;quot;); // 控制器段获取url:/test.html return url(&amp;quot;Index/test&amp;quot;); // 动态带参数的 Route::rule(&amp;quot;details/:id&amp;quot;, &amp;quot;Index/details&amp;quot;)-&amp;gt;ext(&amp;quot;html&amp;quot;); // 控制器段获取url:/details/5.html return url(&amp;quot;Index/details&amp;quot;, [&amp;quot;id&amp;quot;=&amp;gt;5]); // url参数一和路由的rule的参数二是一致的,可以通过name方法复刻; Route::rule(&amp;quot;details/:id&amp;quot;, &amp;quot;Index/details&amp;quot;)-&amp;gt;name(&amp;quot;de&amp;quot;)-&amp;gt;ext(&amp;quot;html&amp;quot;); // 控制器段获取url:/details/5.html return url(&amp;quot;de&amp;quot;, [&amp;quot;id&amp;quot;=&amp;gt;5]); // 完整带域名的地址:http://www.tp.com:8000/details/5.html return url(&amp;quot;de&amp;quot;, [&amp;quot;id&amp;quot;=&amp;gt;5])-&amp;gt;domain(true); return url(&amp;quot;de&amp;quot;, [&amp;quot;id&amp;quot;=&amp;gt;5])-&amp;gt;domain(&amp;quot;www.tp.com&amp;quot;);</code></pre> </li> <li>在手册 -&gt; 路由 -&gt; URL 生成 有 <strong>Route::buildUrl()</strong> 源方法,只不过助手函数,更方便;</li> </ul> <h1>35. 资源路由</h1> <p>&lt;div style=&quot;text-align:right;color:#666;font-size:20px;&quot;&gt;主讲老师 - 李炎恢&lt;/div&gt;</p> <h3>1. <strong>创建资源</strong></h3> <ul> <li> <p>资源路由,采用固定的常用方法来实现简化 URL 的功能;</p> <pre><code class="language-php">Route::resource(&amp;quot;blog&amp;quot;, &amp;quot;Blog&amp;quot;);</code></pre> </li> <li> <p>系统提供了一个命令,方便开发者快速生成一个资源控制器;</p> <pre><code class="language-php">php think make:controller Blog</code></pre> </li> <li> <p>以上的两部操作,创建了一个控制器Blog类,并生成了增删改查操作的方法,而且还实现了全部路由:</p> <table> <thead> <tr> <th style="text-align: center;">标识</th> <th style="text-align: center;">请求类型</th> <th style="text-align: center;">路由规则</th> <th style="text-align: center;">操作方法</th> </tr> </thead> <tbody> <tr> <td style="text-align: center;">index</td> <td style="text-align: center;">GET</td> <td style="text-align: center;">blog</td> <td style="text-align: center;">index</td> </tr> <tr> <td style="text-align: center;">create</td> <td style="text-align: center;">GET</td> <td style="text-align: center;">blog/create</td> <td style="text-align: center;">create</td> </tr> <tr> <td style="text-align: center;">save</td> <td style="text-align: center;">POST</td> <td style="text-align: center;">blog</td> <td style="text-align: center;">save</td> </tr> <tr> <td style="text-align: center;">read</td> <td style="text-align: center;">GET</td> <td style="text-align: center;">blog/:id</td> <td style="text-align: center;">read</td> </tr> <tr> <td style="text-align: center;">edit</td> <td style="text-align: center;">GET</td> <td style="text-align: center;">blog/:id/edit</td> <td style="text-align: center;">edit</td> </tr> <tr> <td style="text-align: center;">update</td> <td style="text-align: center;">PUT</td> <td style="text-align: center;">blog/:id</td> <td style="text-align: center;">update</td> </tr> <tr> <td style="text-align: center;">delete</td> <td style="text-align: center;">DELETE</td> <td style="text-align: center;">blog/:id</td> <td style="text-align: center;">delete</td> </tr> </tbody> </table> </li> </ul> <h3>2. <strong>地址URL</strong></h3> <ul> <li> <p>资源路由注册好后,所有地址都是全自动生成,具体如下:</p> <pre><code class="language-php">http://www.tp.com:8000/blog //GET 访问的是index方法,用于显示数据 http://www.tp.com:8000/blog/create //GET 访问的是create方法,新增数据的表单页面 http://www.tp.com:8000/blog/5 //GET 访问的是read方法,读取指定id的一条数据 http://www.tp.com:8000/blog/5/edit //GET 访问的是edit方法,读取指定id数据并显示修改表单</code></pre> <pre><code class="language-php">http://www.tp.com:8000/blog //POST 访问的是save方法,用于接收表单提交的新增数据 http://www.tp.com:8000/blog/5 //PUT 访问的是update方法,用于接收表单提交的修改数据 http://www.tp.com:8000/blog/5 //DELETE 访问的是delete方法,用于接收数据删除信息</code></pre> </li> <li> <p>默认的参数采用 id 名称,如果你想别的,比如:blog_id;</p> <pre><code class="language-php">//相应的 delete($blog_id) ...-&amp;gt;vars([&amp;quot;blog&amp;quot;=&amp;gt;&amp;quot;blog_id&amp;quot;]); </code></pre> </li> <li> <p>也可以通过 <strong>only()</strong> 方法限定系统提供的资源方法:</p> <pre><code class="language-php">// 只允许指定的这些操作 ...-&amp;gt;only([&amp;quot;index&amp;quot;,&amp;quot;save&amp;quot;,&amp;quot;create&amp;quot;]);</code></pre> </li> <li> <p>还可以通过 <strong>except()</strong> 方法排除系统提供的资源方法:</p> <pre><code class="language-php">// only相反操作 ...-&amp;gt;except([&amp;quot;read&amp;quot;,&amp;quot;delete&amp;quot;,&amp;quot;update&amp;quot;])</code></pre> </li> <li> <p>使用 <strong>rest()</strong> 方法,更改系统给予的默认方法,1.请求方式;2.地址;3.操作;</p> <pre><code class="language-php">Route::rest(&amp;quot;create&amp;quot;, [&amp;quot;GET&amp;quot;, &amp;quot;/add&amp;quot;, &amp;quot;add&amp;quot;]); // 批量 Route::rest([ &amp;quot;save&amp;quot; =&amp;gt; [&amp;quot;POST&amp;quot;, &amp;quot;&amp;quot;, &amp;quot;store&amp;quot;], &amp;quot;update&amp;quot; =&amp;gt; [&amp;quot;PUT&amp;quot;, &amp;quot;/:id&amp;quot;, &amp;quot;save&amp;quot;], &amp;quot;delete&amp;quot; =&amp;gt; [&amp;quot;DELETE&amp;quot;, &amp;quot;/:id&amp;quot;, &amp;quot;destory&amp;quot;], ]);</code></pre> </li> <li>支持嵌套资源路由,类似于一对多关联的感觉,实战中用到再操作,详情查看手册:</li> </ul> <h1>36. 视图.变量.渲染</h1> <p>&lt;div style=&quot;text-align:right;color:#666;font-size:20px;&quot;&gt;主讲老师 - 李炎恢&lt;/div&gt;</p> <h3>1. <strong>视图操作</strong></h3> <ul> <li> <p>首先,为了方便后续课程学习,先把路由给关闭了;并创建一个用于测试视图的控制器:</p> <pre><code class="language-php">// 是否启用路由 &amp;quot;with_route&amp;quot; =&amp;gt; false, // 视图控制器 class ViewPage extends BaseController { public function index() { return &amp;quot;view&amp;quot;; } }</code></pre> </li> <li> <p>由于我们不用模板引擎,直接使用php原生,就需要使用 <strong>engine()</strong> 方法,载入 test 模板;</p> <pre><code class="language-php">// 载入原生php模板 return View::engine(&amp;quot;php&amp;quot;)-&amp;gt;fetch(&amp;quot;test&amp;quot;); // 模板地址为:view/view_page/test.html // 或修改配置文件,将Think改为php就可以使用助手函数 return view(&amp;quot;test&amp;quot;);</code></pre> </li> <li> <p>如果希望模板后缀为 <strong>.php</strong>,方便 php + html5 混编,在 <strong>config/view</strong> 设置:</p> <pre><code class="language-php">// 模板后缀 &amp;quot;view_suffix&amp;quot; =&amp;gt; &amp;quot;php&amp;quot;,</code></pre> </li> <li> <p>在 fetch() 方法的第二参数,通过数组方式给模板传递变量:</p> <pre><code class="language-php">return View::engine(&amp;quot;php&amp;quot;)-&amp;gt;fetch(&amp;quot;test&amp;quot;, [ &amp;quot;name&amp;quot; =&amp;gt; &amp;quot;ThinkPHP8&amp;quot; ]); // 或 return view(&amp;quot;test&amp;quot;,[ &amp;quot;name&amp;quot; =&amp;gt; &amp;quot;ThinkPHP8&amp;quot; ]);</code></pre> </li> </ul> <h3>2. <strong>表单提交</strong></h3> <ul> <li> <p>先载入一个表单页面:</p> <pre><code class="language-php">return View::engine(&amp;quot;php&amp;quot;)-&amp;gt;fetch(&amp;quot;input&amp;quot;);</code></pre> </li> <li> <p>创建一个表单:</p> <pre><code class="language-html">&amp;lt;form action=&amp;quot;/view_page/save&amp;quot; method=&amp;quot;post&amp;quot;&amp;gt; &amp;lt;input type=&amp;quot;text&amp;quot; name=&amp;quot;username&amp;quot;&amp;gt; &amp;lt;input type=&amp;quot;submit&amp;quot; value=&amp;quot;提交&amp;quot;&amp;gt;&amp;lt;/input&amp;gt; &amp;lt;/form&amp;gt;</code></pre> </li> <li> <p>接受数据:</p> <pre><code class="language-php">public function save() { return $this-&amp;gt;request-&amp;gt;post(&amp;quot;username&amp;quot;); }</code></pre> </li> </ul> <h1>37. 请求对象.变量.信息</h1> <p>&lt;div style=&quot;text-align:right;color:#666;font-size:20px;&quot;&gt;主讲老师 - 李炎恢&lt;/div&gt;</p> <h3>1. <strong>请求对象</strong></h3> <ul> <li> <p>上一节课中表单提交时,我们接受数据使用了 <strong>$this-&gt;request-&gt;post()</strong> 方法,这哪里来的?</p> </li> <li> <p>因为我们的控制器继承了 <strong>BaseController</strong> 追踪进去,可以看到 <strong>$request</strong> 成员字段;</p> </li> <li> <p>关于这个知识点的源知识点,可以参考:手册 -&gt; 架构 -&gt; 容器和依赖注入,TP6讲过,8不讲了;</p> </li> <li> <p>在没有继承 BaseController 时,我们需要自己手动注入请求:</p> <pre><code class="language-php">namespace app\controller; use think\Request; class Rely { protected $request; // 依赖注入 public function __construct(Request $request) { $this-&amp;gt;request = $request; } public function index() { halt($this-&amp;gt;request-&amp;gt;get()); } } // 上面的请求方式比较原始,过于麻烦,不推荐了</code></pre> </li> <li> <p>第二种方式:<strong>门面Facade</strong>,它相关的知识点在手册 -&gt; 架构 -&gt; 门面:</p> <pre><code class="language-php">namespace app\controller; use think\facade\Request; class Rely { public function index() { halt(Request::get()); } }</code></pre> </li> <li> <p>第三种方式:继承 <strong>BaseController</strong>,其实就是第一种,只不过被封装到基类中去了:</p> <pre><code class="language-php">namespace app\controller; use app\BaseController; class Rely extends BaseController { public function index() { halt($this-&amp;gt;request-&amp;gt;get()); } }</code></pre> </li> <li> <p>第四种方式:终极方法 <strong>request()</strong> 助手函数:</p> <pre><code class="language-php">halt(request()-&amp;gt;get());</code></pre> </li> </ul> <h3>2. <strong>请求信息</strong></h3> <ul> <li> <p>在手册 请求 -&gt; 请求信息 里有全部的请求方法模块,这里列举几个意思一下:</p> <table> <thead> <tr> <th style="text-align: center;">方法</th> <th style="text-align: left;">含义</th> </tr> </thead> <tbody> <tr> <td style="text-align: center;">host</td> <td style="text-align: left;">当前访问域名或者IP</td> </tr> <tr> <td style="text-align: center;">port</td> <td style="text-align: left;">当前访问的端口</td> </tr> <tr> <td style="text-align: center;">url</td> <td style="text-align: left;">当前完整URL</td> </tr> <tr> <td style="text-align: center;">root</td> <td style="text-align: left;">URL访问根地址</td> </tr> <tr> <td style="text-align: center;">method</td> <td style="text-align: left;">当前请求类型</td> </tr> </tbody> </table> </li> <li> <p>我们三种方法演示一遍,最终选一种你喜欢的即可:</p> <pre><code class="language-php">// 当前url echo $this-&amp;gt;request-&amp;gt;url(); echo Request::url(); echo request()-&amp;gt;url(); // 请求方法 echo request()-&amp;gt;method(); // 更多的对照手册自行测试即可</code></pre> </li> </ul> <h3>3. <strong>请求变量</strong></h3> <ul> <li> <p>Request 对象支持全局变量的检测、获取和安全过滤,支持$_GET、$_POST...等;</p> </li> <li> <p>使用 <strong>has()</strong> 方法,可以检测全局变量是否已经设置:</p> <pre><code class="language-php">// 判断是否有GET模式下id的值 echo request()-&amp;gt;has(&amp;quot;id&amp;quot;, &amp;quot;get&amp;quot;);</code></pre> </li> <li> <p>更多方法,参看手册 请求 -&gt; 输入变量, 这里意思几个:</p> <table> <thead> <tr> <th style="text-align: center;">方法</th> <th>描述</th> </tr> </thead> <tbody> <tr> <td style="text-align: center;">param</td> <td>获取当前请求变量</td> </tr> <tr> <td style="text-align: center;">get</td> <td>获取 $_GET 变量</td> </tr> <tr> <td style="text-align: center;">post</td> <td>获取 $_POST 变量</td> </tr> <tr> <td style="text-align: center;">put</td> <td>获取 PUT 变量</td> </tr> <tr> <td style="text-align: center;">delete</td> <td>获取 DELETE 变量</td> </tr> <tr> <td style="text-align: center;">session</td> <td>获取 SESSION 变量</td> </tr> </tbody> </table> </li> <li> <p><strong>param()</strong> 方法是框架推荐的方法,可以自动识别诸如 get、post等数据信息;</p> <pre><code class="language-php">// url: http://www.tp.com:8000/rely/index?id=5 // 可以获取 get 模式 id 的值 echo request()-&amp;gt;param(&amp;quot;id&amp;quot;); echo request()-&amp;gt;get(&amp;quot;id&amp;quot;); // url: http://www.tp.com:8000/rely/index/id/5 // 此时,只能是param获取 echo request()-&amp;gt;param(&amp;quot;id&amp;quot;);</code></pre> <pre><code class="language-php">// 默认值 request()-&amp;gt;param(&amp;quot;name&amp;quot;) // null,实际上页面也转行成空,判断null也成立 request()-&amp;gt;param(&amp;quot;name&amp;quot;, &amp;quot;&amp;quot;) // 空字符串 request()-&amp;gt;param(&amp;quot;name&amp;quot;, &amp;quot;无名氏&amp;quot;); // 无名氏</code></pre> </li> <li> <p>可在 <strong>app\Request.php</strong> 配置过滤器:</p> <pre><code class="language-php">http://www.tp.com:8000/rely/index?name=我&amp;lt;b&amp;gt;你&amp;lt;/b&amp;gt; // 将特殊字符转换HTML实体 protected $filter = [&amp;quot;htmlspecialchars&amp;quot;]; // 如果不想要全局过滤器,可以直接局部 request()-&amp;gt;param(&amp;quot;name&amp;quot;, &amp;quot;&amp;quot;, &amp;quot;htmlspecialchars&amp;quot;); // 设置了全局过滤器,但某个不想用 request()-&amp;gt;param(&amp;quot;name&amp;quot;, &amp;quot;&amp;quot;, null) // 使用变量修饰符,可以将参数强制转换成指定的类型; // /s(字符串)、/d(整型)、/b(布尔)、/a(数组)、/f(浮点); request()-&amp;gt;param(&amp;quot;id/d&amp;quot;);</code></pre> </li> <li> <p><strong>only()</strong>、<strong>except()</strong> 设置允许和排查可接受的变量:</p> <pre><code class="language-php">// 允许id和name变量 request()-&amp;gt;only([&amp;quot;id&amp;quot;,&amp;quot;name&amp;quot;]); // 默认值设置 request()-&amp;gt;only([&amp;quot;id&amp;quot;=&amp;gt;1,&amp;quot;name&amp;quot;=&amp;gt;&amp;quot;默认值&amp;quot;]); // 参数二可设置GET还是POST等 request()-&amp;gt;only([&amp;quot;id&amp;quot;,&amp;quot;name&amp;quot;], &amp;quot;GET&amp;quot;);</code></pre> </li> <li> <p>以上所有,都封装到助手函数 <strong>input()</strong> 里了:</p> <pre><code class="language-php">input(&amp;quot;?get.id&amp;quot;); //判断 get 下的 id 是否存在 input(&amp;quot;?post.name&amp;quot;); //判断 post 下的 name 是否存在 input(&amp;quot;param.name&amp;quot;); //获取 param 下的 name 值 input(&amp;quot;param.name&amp;quot;, &amp;quot;默认值&amp;quot;); //默认值 input(&amp;quot;param.name&amp;quot;, &amp;quot;&amp;quot;, &amp;quot;htmlspecialchars&amp;quot;); //过滤器 input(&amp;quot;param.id/d&amp;quot;); //设置强制转换</code></pre> </li> </ul> <h1>38. 请求类型.输出.重定向</h1> <p>&lt;div style=&quot;text-align:right;color:#666;font-size:20px;&quot;&gt;主讲老师 - 李炎恢&lt;/div&gt;</p> <h3>1. <strong>请求类型</strong></h3> <ul> <li> <p><strong>Request</strong> 对象提供了一个方法 <strong>method()</strong> 来获取当前请求类型,也提供了判断当前的请求类型:</p> <table> <thead> <tr> <th style="text-align: center;">方法</th> <th style="text-align: left;">说明</th> </tr> </thead> <tbody> <tr> <td style="text-align: center;">method</td> <td style="text-align: left;">获取当前请求类型</td> </tr> <tr> <td style="text-align: center;">isGet</td> <td style="text-align: left;">判断是否GET请求</td> </tr> <tr> <td style="text-align: center;">isPost</td> <td style="text-align: left;">判断是否POST请求</td> </tr> <tr> <td style="text-align: center;">isPut</td> <td style="text-align: left;">判断是否PUT请求</td> </tr> <tr> <td style="text-align: center;">isDelete</td> <td style="text-align: left;">判断是否DELETE请求</td> </tr> <tr> <td style="text-align: center;">isAjax</td> <td style="text-align: left;">判断是否AJAX请求</td> </tr> </tbody> </table> </li> <li> <p>使用请求类型伪装,可以提交 PUT、DELETE 类型:</p> <pre><code class="language-php">// 载入表单模板 public function create() { return View::engine(&amp;quot;php&amp;quot;)-&amp;gt;fetch(&amp;quot;create&amp;quot;); } // 表单 &amp;lt;form action=&amp;quot;/rely&amp;quot; method=&amp;quot;post&amp;quot;&amp;gt; &amp;lt;input type=&amp;quot;text&amp;quot; name=&amp;quot;name&amp;quot;&amp;gt; &amp;lt;input type=&amp;quot;hidden&amp;quot; name=&amp;quot;_method&amp;quot; value=&amp;quot;PUT&amp;quot;&amp;gt; &amp;lt;input type=&amp;quot;submit&amp;quot; value=&amp;quot;提交&amp;quot;&amp;gt; &amp;lt;/form&amp;gt; // 判断是否PUT请求 if (request()-&amp;gt;isPut()) { echo input(&amp;quot;put.name&amp;quot;); } // 直接ajax、pjax伪装,在url后续添加?_ajax=1即可,结合前段时再研究</code></pre> </li> </ul> <h3>2. <strong>响应输出</strong></h3> <ul> <li> <p>响应输出,有好几种:包括 <strong>return</strong>、<strong>json()</strong> 和 <strong>view()</strong> 等等;</p> </li> <li> <p>默认输出方式是以 html 格式输出,如果你发起 json 请求,则输出 json;</p> </li> <li> <p>而背后是 response 对象,可以用 <strong>response()</strong> 输出达到相同的效果;</p> <pre><code class="language-php">$data = &amp;quot;Hello,TP8!&amp;quot;; // 等同于 return $data; return response($data);</code></pre> </li> <li> <p>response()方法可以设置第二参数,状态码,或调用 code()方法;</p> <pre><code class="language-php">// 参数二,发送状态码 return response($data, 201); //或 return response($data)-&amp;gt;code(201); // json()和view()均支持状态码</code></pre> </li> </ul> <h3>3. <strong>重定向</strong></h3> <ul> <li> <p>使用 redirect()方法可以实现页面重定向,需要 return 执行;</p> <pre><code class="language-php">// 首页 return redirect(&amp;quot;/&amp;quot;); // 访问路由页面,外加状态码 return redirect(&amp;quot;details/5&amp;quot;, 303); // 访问url生成的地址 return redirect(url(&amp;quot;Index/index&amp;quot;));</code></pre> </li> <li>还支持session跳转和记住上一次地址的跳转,实战时再研究;</li> </ul> <h1>39. Session和Cookie</h1> <p>&lt;div style=&quot;text-align:right;color:#666;font-size:20px;&quot;&gt;主讲老师 - 李炎恢&lt;/div&gt;</p> <h3>1. <strong>Session</strong></h3> <ul> <li> <p>TP8不支持原生 $_ SESSION 的获取方式,也不支持 session_开头的函数,默认是关闭的;</p> </li> <li> <p>在使用 Session 之前,需要开启初始化,在中间件文件 middleware.php;</p> <pre><code class="language-php">// 去掉注释,开始Session \think\middleware\SessionInit::class</code></pre> </li> <li> <p>使用 <strong>::set()</strong> 和 <strong>::get()</strong> 方法去设置 Session 的存取:</p> <pre><code class="language-php">// 设置session use Session::set(&amp;quot;user&amp;quot;, &amp;quot;Mr.Lee&amp;quot;); // 获取session use echo Session::get(&amp;quot;user&amp;quot;); // 获取不存在的session时,参数二默认值 echo Session::get(&amp;quot;abc&amp;quot;, &amp;quot;不存在&amp;quot;); // 获取全部session,数组形式 dump(Session::all());</code></pre> </li> <li> <p><strong>::has()</strong> 判断是否赋值,<strong>::delete()</strong> 删除,<strong>::pull()</strong> 取值后删除,<strong>::clear()</strong> 清空整个 session;</p> <pre><code class="language-php">// 判断是否存在 Session::has(&amp;quot;user&amp;quot;); // 删除 Session::delete(&amp;quot;user&amp;quot;); // 取值后删除,不存在返回null Session::pull(&amp;quot;user&amp;quot;); // 清空所有 Session::clear(&amp;quot;&amp;quot;);</code></pre> </li> <li> <p>Request 对象可以直接对Session进行存取,自行查看手册,这里再罗列常用的助手函数:</p> <pre><code class="language-php">//赋值 session(&amp;quot;user&amp;quot;, &amp;quot;Mr.Wang&amp;quot;); //has 判断 session(&amp;quot;?user&amp;quot;); //delete 删除 session(&amp;quot;user&amp;quot;, null); //清理全部 session(null); //输出 echo session(&amp;quot;user&amp;quot;);</code></pre> </li> </ul> <h3>2. <strong>Cookie</strong></h3> <ul> <li> <p>Cookie 是客户端存储,默认情况下是开启初始化的,在 config/cookie.php;</p> <pre><code class="language-php">// 设置cookie user value 过期时间,不设过期时间,则为临时关闭浏览器后自动删除 Cookie::set(&amp;quot;user&amp;quot;, &amp;quot;Mr.Lee&amp;quot;, 3600); // 获取cookie,注意,会慢一拍 echo Cookie::get(&amp;quot;user&amp;quot;); // 获取全部cookie dump(Cookie::get()); // 永久保持 Cookie::forever(&amp;quot;user&amp;quot;, &amp;quot;Mr.Lee&amp;quot;);</code></pre> </li> <li> <p><strong>::has()</strong> 判断是否存在,<strong>::delete()</strong> 删除 cookie;</p> <pre><code class="language-php">Cookie::has(&amp;quot;user&amp;quot;); Cookie::delete(&amp;quot;user&amp;quot;);</code></pre> </li> <li> <p>助手函数,更加方便操作:</p> <pre><code class="language-php">echo cookie(&amp;quot;user&amp;quot;); //输出 cookie(&amp;quot;user&amp;quot;, &amp;quot;Mr.Lee&amp;quot;, 3600); //设置 cookie(&amp;quot;user&amp;quot;, null); //删除</code></pre> </li> </ul> <h1>40. 缓存功能</h1> <p>&lt;div style=&quot;text-align:right;color:#666;font-size:20px;&quot;&gt;主讲老师 - 李炎恢&lt;/div&gt;</p> <h3>1. <strong>常规方法</strong></h3> <ul> <li> <p>系统内置了很多类型的缓存,除了 File,其它均需要结合相关产品;</p> </li> <li> <p>我们这里主要演示 File 文本缓存,其它的需要学习相关产品,比如Redis将单独出;</p> </li> <li> <p>配置文件 cache.php 进行缓存配置,默认生成在 runtime/cache 目录;</p> <pre><code class="language-php">// 生成缓存,和cookie一样的设置,但注意,过期时间不设,将是永久,和cookie有区别 Cache::set(&amp;quot;user&amp;quot;, &amp;quot;Mr.Lee&amp;quot;, 3600); // 读取缓存,无数据返回null echo Cache::get(&amp;quot;user&amp;quot;); // 判断是否存在 echo Cache::has(&amp;quot;user&amp;quot;); // 删除缓存 Cache::delete(&amp;quot;user&amp;quot;); // 先获取,再删掉,没有值返回null Cache::pull(&amp;quot;user&amp;quot;); // 清空缓存 Cache::clear();</code></pre> </li> <li> <p><strong>::inc()</strong> 和 <strong>::dec()</strong> 实现缓存数据的自增和自减操作:</p> <pre><code class="language-php">// 创建数值缓存 Cache::set(&amp;quot;num&amp;quot;, 1); // 默认自增+1 Cache::inc(&amp;quot;num&amp;quot;); // 参数二自增值 Cache::inc(&amp;quot;num&amp;quot;, 3); echo Cache::get(&amp;quot;num&amp;quot;);</code></pre> </li> <li> <p><strong>::push()</strong> 实现缓存的数组数据追加的功能:</p> <pre><code class="language-php">// 数组缓存 Cache::set(&amp;quot;arr&amp;quot;, [1, 2, 3]); // 追加数据 Cache::push(&amp;quot;arr&amp;quot;, 4); halt(Cache::get(&amp;quot;arr&amp;quot;));</code></pre> </li> </ul> <h3>2. <strong>助手函数</strong></h3> <ul> <li> <p>最常用的创建和读取缓存的助手函数:</p> <pre><code class="language-php">//设置缓存 cache(&amp;quot;user&amp;quot;, &amp;quot;Mr.Lee&amp;quot;, 3600); //输出缓存 echo cache(&amp;quot;user&amp;quot;); //删除指定缓存 cache(&amp;quot;user&amp;quot;, null);</code></pre> </li> </ul> <h1>41. 验证器的使用</h1> <p>&lt;div style=&quot;text-align:right;color:#666;font-size:20px;&quot;&gt;主讲老师 - 李炎恢&lt;/div&gt;</p> <h3>1. <strong>定义方式</strong></h3> <ul> <li> <p>验证器的使用,我们必须先定义它,系统提供了一条命令直接生成想要的类;</p> <pre><code class="language-php">// 生成一个 validate 文件夹,并生成 User.php 验证类; // 自动生成了两个属性:$rule 表示定义规则,$message 表示错误提示信息; php think make:validate User</code></pre> <pre><code class="language-php">// 规则 protected $rule = [ &amp;quot;name&amp;quot; =&amp;gt; &amp;quot;require|max:20&amp;quot;, //不得为空,不得大于 20 位 &amp;quot;price&amp;quot; =&amp;gt; &amp;quot;number|between:1,100&amp;quot;, //必须是数值,1-100 之间 &amp;quot;email&amp;quot; =&amp;gt; &amp;quot;email&amp;quot; //邮箱格式要正确 ]; // 提示,不设置则默认错误提示 protected $message = [ &amp;quot;name.require&amp;quot; =&amp;gt; &amp;quot;姓名不得为空&amp;quot;, &amp;quot;name.max&amp;quot; =&amp;gt; &amp;quot;姓名不得大于 20 位&amp;quot;, &amp;quot;price.number&amp;quot; =&amp;gt; &amp;quot;价格必须是数字&amp;quot;, &amp;quot;price.between&amp;quot; =&amp;gt; &amp;quot;价格必须 1-100 之间&amp;quot;, &amp;quot;email.email&amp;quot; =&amp;gt; &amp;quot;邮箱的格式错误&amp;quot; ];</code></pre> </li> <li> <p>验证器定义好了之后,我们需要进行调用测试,创建一个 Verify.php 控制器;</p> <pre><code class="language-php">public function vali() { try { validate(User::class)-&amp;gt;check([ // 可以将姓名设置空,或大于20位 // 将邮箱写错,来测试 &amp;quot;name&amp;quot; =&amp;gt; &amp;quot;Mr.Lee&amp;quot;, &amp;quot;email&amp;quot; =&amp;gt; &amp;quot;123163.com&amp;quot; ]); } catch (ValidateException $e) { dump($e-&amp;gt;getError()); } }</code></pre> </li> <li> <p>默认情况下,出现一个错误就会停止后面字段的验证,我们也可以设置批量验证;</p> <pre><code class="language-php">validate(User::class)-&amp;gt;batch(true)...</code></pre> </li> <li> <p>手册提供了大量内置的规则,查看 手册 -&gt; 验证 -&gt; 内置规则,但我们也可以自定义规则:</p> <pre><code class="language-php">// 过滤:李炎恢 这三个字 protected $rule = [ &amp;quot;name&amp;quot; =&amp;gt; &amp;quot;require|max:20|checkName:李炎恢&amp;quot; ] // 自定义规则checkName protected function checkName($value, $rule) { // 判断不等返回true,否则返回错误提示 return $value != $rule ? true : &amp;quot;名字是违禁词!&amp;quot;; } // 规则函数五个参数 protected function checkName($value, $rule, $data, $field, $title) { dump($data); //所有数据信息 dump($field); //当前字段名 dump($title); //字段描述,没有就是字段名 } // 设置字段描述 protected $rule = [ &amp;quot;name|用户名&amp;quot; ]</code></pre> </li> </ul> <h3>2. <strong>规则.错误信息</strong></h3> <ul> <li> <p>当规则体量较大时,可以采用数组的方式,让规则的可读性变高;</p> <pre><code class="language-php">// 只不过,体量小时,反而感觉乱 protected $rule = [ &amp;quot;name&amp;quot; =&amp;gt; [ &amp;quot;require&amp;quot;, &amp;quot;max&amp;quot; =&amp;gt; 20, &amp;quot;checkName&amp;quot; =&amp;gt; &amp;quot;李炎恢&amp;quot; ], &amp;quot;email&amp;quot; =&amp;gt; &amp;quot;email&amp;quot; ];</code></pre> </li> <li> <p>较少的验证时,或想只在控制器独立验证,不想创建验证类,也是支持的;</p> <pre><code class="language-php">// 规则 $validate = Validate::rule([ &amp;quot;name&amp;quot; =&amp;gt; &amp;quot;require|max:20&amp;quot;, &amp;quot;email&amp;quot; =&amp;gt; &amp;quot;email&amp;quot; ]); // 验证 $result = $validate-&amp;gt;check([ &amp;quot;name&amp;quot; =&amp;gt; &amp;quot;李炎恢&amp;quot;, &amp;quot;email&amp;quot; =&amp;gt; &amp;quot;123@163.com&amp;quot; ]); // 判断 if (!$result) { dump($validate-&amp;gt;getError()); }</code></pre> </li> </ul> <h1>42. 验证场景.内置规则</h1> <p>&lt;div style=&quot;text-align:right;color:#666;font-size:20px;&quot;&gt;主讲老师 - 李炎恢&lt;/div&gt;</p> <h3>1. <strong>验证场景</strong></h3> <ul> <li> <p>验证场景设置,即特定的场景下是否进行验证,独立验证不存在场景验证;</p> </li> <li> <p>举一个简单的例子,新增数据需要验证用户名,而修改更新时不验证用户名;</p> </li> <li> <p>可以在验证类 User.php 中,设置一个$scene 属性,用来限定场景验证;</p> <pre><code class="language-php">// 验证场景 protected $scene = [ &amp;quot;insert&amp;quot; =&amp;gt; [&amp;quot;name&amp;quot;, &amp;quot;email&amp;quot;], // 新增验证name和email &amp;quot;edit&amp;quot; =&amp;gt; [&amp;quot;email&amp;quot;] // 修改验证email ];</code></pre> </li> <li> <p>在控制器端,验证时,根据不同的验证手段,绑定相关场景进行验证即可;</p> <pre><code class="language-php">validate(User::class)-&amp;gt;scene(&amp;quot;edit&amp;quot;)</code></pre> </li> <li> <p>在验证类端,可以设置一个公共方法对场景的细节进行定义,方法名为 scene+场景;</p> <pre><code class="language-php">// 除了only,还支持移出remove规则和append增加规则,请查看手册 public function sceneEdit() { return $this-&amp;gt;only([&amp;quot;email&amp;quot;]); }</code></pre> </li> </ul> <h3>2. <strong>内置规则</strong></h3> <ul> <li> <p>验证器提供了大量的内置规则:格式验证、长度区间、字段比较以及其它等验证;</p> </li> <li> <p>格式验证类:(更多可查看手册 验证 -&gt; 验证规则)</p> <pre><code class="language-php">// 规则 $validate = Validate::rule([ &amp;quot;id&amp;quot; =&amp;gt; &amp;quot;number&amp;quot;, ]); // 验证 $result = $validate-&amp;gt;check([ &amp;quot;id&amp;quot; =&amp;gt; &amp;quot;abc&amp;quot;, ]); // 判断 if (!$result) { dump($validate-&amp;gt;getError()); }</code></pre> </li> <li> <p>可以使用静态 <strong>facade</strong> 模式单一验证来快捷对字段数据进行判断:</p> <pre><code class="language-php">// 格式为Validate::is+Rule,返回 true 或 false dump(Validate::isNumber(10));</code></pre> </li> </ul> <h1>43. Token表单令牌</h1> <p>&lt;div style=&quot;text-align:right;color:#666;font-size:20px;&quot;&gt;主讲老师 - 李炎恢&lt;/div&gt;</p> <h3>1. <strong>设置Token</strong></h3> <ul> <li> <p>表单令牌就是在表单中增加一个隐藏字段,随机生成一串字符,确定不是伪造;</p> </li> <li> <p>这种随机产生的字符和服务器的 session(开启)进行对比,通过则是合法表单;</p> <pre><code class="language-php">// 随机生成一个Token,并交给模板 public function index() { return view(&amp;quot;index&amp;quot;, [ &amp;quot;token&amp;quot; =&amp;gt; $this-&amp;gt;request-&amp;gt;buildToken(&amp;quot;__token__&amp;quot;, &amp;quot;sha1&amp;quot;) ]); }</code></pre> <pre><code class="language-php">// 表单插入一个隐藏域,value是token &amp;lt;input type=&amp;quot;hidden&amp;quot; name=&amp;quot;__token__&amp;quot; value=&amp;quot;&amp;lt;?php echo $token;?&amp;gt;&amp;quot;&amp;gt; // 至于Aajx提交,不方便测试,等实战时再演练,具体参看 手册 -&amp;gt; 验证 -&amp;gt; 表单令牌</code></pre> <pre><code class="language-php">public function save() { // 可以看到 token 一并写入了session echo $this-&amp;gt;request-&amp;gt;post(&amp;quot;__token__&amp;quot;).&amp;quot;&amp;lt;br&amp;gt;&amp;quot;; echo session(&amp;quot;__token__&amp;quot;); }</code></pre> </li> </ul> <h3>2. <strong>验证Token</strong></h3> <ul> <li> <p>一般来说提交跳转有两种形式:路由模式和常规模式,先看下常规模式;</p> <pre><code class="language-php">// 验证__token__是否通过 $check = $this-&amp;gt;request-&amp;gt;checkToken(&amp;quot;__token__&amp;quot;); // 不通过,这里手动抛出指定异常即可 if ($check === false) { throw new ValidateException(&amp;quot;无效令牌!&amp;quot;); }</code></pre> </li> <li> <p>路由模式,需要开启路由,并设置路由:</p> <pre><code class="language-php">// Token测试 Route::rule(&amp;quot;v/i&amp;quot;, &amp;quot;Verify/index&amp;quot;); Route::rule(&amp;quot;v/s&amp;quot;, &amp;quot;Verify/save&amp;quot;)-&amp;gt;token();</code></pre> </li> <li> <p>当然也支持验证器模式,具体如下:</p> <pre><code class="language-php">protected $rule = [ 'name' =&amp;gt; 'require|max:25|token' }</code></pre> </li> </ul> <h1>44. 上传文件</h1> <p>&lt;div style=&quot;text-align:right;color:#666;font-size:20px;&quot;&gt;主讲老师 - 李炎恢&lt;/div&gt;</p> <h3>1. <strong>文件上传</strong></h3> <ul> <li> <p>如果要实现上传功能,首先需要建立一个上传表单:</p> <pre><code class="language-php">// 载入模板 public function up() { return View::engine(&amp;quot;php&amp;quot;)-&amp;gt;fetch(&amp;quot;up&amp;quot;); } // 接受上传数据 public function save() {} </code></pre> <pre><code class="language-html">&amp;lt;form action=&amp;quot;/file/save&amp;quot; enctype=&amp;quot;multipart/form-data&amp;quot; method=&amp;quot;post&amp;quot;&amp;gt; &amp;lt;input type=&amp;quot;file&amp;quot; name=&amp;quot;image&amp;quot;&amp;gt; &amp;lt;input type=&amp;quot;submit&amp;quot; value=&amp;quot;上传&amp;quot;&amp;gt; &amp;lt;/form&amp;gt;</code></pre> </li> <li> <p>使用 <strong>Request::file()</strong> 或 <strong>request()-&gt;file</strong> 来获取上传数据:</p> <pre><code class="language-php">// 获取上传数据 halt(Request::file(&amp;quot;image&amp;quot;)); // 或 halt(request()-&amp;gt;file(&amp;quot;image&amp;quot;)); // 上传到本地服务器,参数1是设置的分类目录 $saveName = Filesystem::putFile(&amp;quot;topic&amp;quot;, $file); halt($saveName); // 生成的规则还支持另外两种方式:md5 和 sha1; Filesystem::putFile(&amp;quot;topic&amp;quot;, $file, &amp;quot;sha1&amp;quot;);</code></pre> </li> <li> <p>在 <strong>config/filesystem.php</strong> 里可以修改上次规则和目录;</p> </li> <li> <p>如果要批量上传,表单改成数组形式即可:</p> <pre><code class="language-html">&amp;lt;form action=&amp;quot;/verify/upload&amp;quot; method=&amp;quot;post&amp;quot; enctype=&amp;quot;multipart/form-data&amp;quot;&amp;gt; &amp;lt;input type=&amp;quot;file&amp;quot; name=&amp;quot;image[]&amp;quot;&amp;gt; &amp;lt;input type=&amp;quot;file&amp;quot; name=&amp;quot;image[]&amp;quot;&amp;gt; &amp;lt;input type=&amp;quot;file&amp;quot; name=&amp;quot;image[]&amp;quot;&amp;gt; &amp;lt;input type=&amp;quot;submit&amp;quot; value=&amp;quot;上传&amp;quot;&amp;gt; &amp;lt;/form&amp;gt;</code></pre> <pre><code class="language-php">// 获取表单上传数据 $files = Request::file(&amp;quot;image&amp;quot;); // 批量 $saveNames = []; foreach ($files as $file) { $saveNames[] = Filesystem::putFile(&amp;quot;topic&amp;quot;, $file); } halt($saveNames);</code></pre> </li> </ul> <h3>2. <strong>上传验证</strong></h3> <ul> <li> <p>如果要对上传的内容进行验证,比如后缀、大小等,直接用验证器:</p> </li> <li> <p>手册上本身给出的例子是批量上传验证,我这里写一个单一上传验证;</p> <pre><code class="language-php">// 获取表单上传数据 $file = Request::file(&amp;quot;image&amp;quot;); // 独立验证规则,也可以写到验证类里 $validate = Validate::rule([ // 10240000 等于 1.28MB &amp;quot;image&amp;quot; =&amp;gt; &amp;quot;file|fileExt:jpg,png,gif|fileSize:10240000&amp;quot; ]); // 验证上传 $result = $validate-&amp;gt;check([ &amp;quot;image&amp;quot; =&amp;gt; $file ]); // 判断 if ($result) { $saveName = Filesystem::putFile(&amp;quot;topic&amp;quot;, $file); halt($saveName); } else { dump($validate-&amp;gt;getError()); }</code></pre> </li> </ul> <h1>45. 验证码</h1> <p>&lt;div style=&quot;text-align:right;color:#666;font-size:20px;&quot;&gt;主讲老师 - 李炎恢&lt;/div&gt;</p> <h3>1. <strong>生成验证码</strong></h3> <ul> <li> <p>验证码功能不是系统内置的功能了,需要通过 composer 引入进来;</p> <pre><code class="language-php">// 安装后使用需要开启 session composer require topthink/think-captcha</code></pre> </li> <li> <p>引入进来之后,我们在模版中,验证一下验证码是否能正常显示;</p> <p>```php+HTML &lt;div&gt;&lt;?php echo captcha_img() ?&gt;&lt;/div&gt; &lt;div&gt;&lt;img src=&quot;{:captcha_src()}&quot; alt=&quot;captcha&quot; /&gt;&lt;/div&gt;</p> <pre><code></code></pre> </li> <li> <p>验证码不显示图片原因是伪静态问题,无法加在404错误:</p> <ul> <li>开启路由即可;</li> <li>避免麻烦,可以取消强制路由;</li> </ul> <pre><code class="language-php">// 强制路由时,需要设置访问路由,非强制不需要 //Route::rule(&amp;quot;v/c&amp;quot;, &amp;quot;Verify/code&amp;quot;);</code></pre> </li> <li> <p>手动验证码,需要手动设置点击刷新:</p> <p>```php+HTML &lt;div&gt;&lt;img src=&quot;&lt;?php echo captcha_src() ?&gt;&quot; alt=&quot;&quot; onclick='this.src=&quot;/captcha.html?&quot;+Math.random();'&gt;&lt;/div&gt;</p> <pre><code></code></pre> </li> <li> <p>在 <strong>config/captcha.php</strong> 文件中, 可以配置验证码的各种参数:</p> <pre><code class="language-php">//验证码位数 'length' =&amp;gt; 4, // 是否使用中文验证码 'useZh' =&amp;gt; true, // 是否使用算术验证码 'math' =&amp;gt; false,</code></pre> </li> <li>手册提供了自建验证码,具体参看:手册 -&gt; 扩展库 -&gt; 验证码;</li> </ul> <h3>2. <strong>验证码验证</strong></h3> <ul> <li> <p>直接利用验证器功能,对验证码进行验证即可;</p> <pre><code class="language-php">// 获取表单值 $code = $this-&amp;gt;request-&amp;gt;param(&amp;quot;code&amp;quot;); // 规则 $validate = Validate::rule([ &amp;quot;captcha|验证码&amp;quot; =&amp;gt; &amp;quot;require|captcha&amp;quot; ]); // 验证 $result = $validate-&amp;gt;check([ &amp;quot;captcha&amp;quot; =&amp;gt; $code ]); // 判断 if (!$result) { dump($validate-&amp;gt;getError()); }</code></pre> </li> <li> <p>手册上提供了继承基类后依赖注入的方法,就是将规则和验证合二为一:</p> <pre><code class="language-php">// 通过依赖入驻,需要继承BaseController $this-&amp;gt;validate([ &amp;quot;captcha&amp;quot; =&amp;gt; $code ], [ &amp;quot;captcha|验证码&amp;quot; =&amp;gt; &amp;quot;require|captcha&amp;quot; ]);</code></pre> </li> <li> <p>极简方案 -&gt; 助手函数:</p> <pre><code class="language-php">// 助手函数 if (!captcha_check(input(&amp;quot;post.code&amp;quot;))) { // 抛异常 throw new ValidateException(&amp;quot;验证码错误&amp;quot;); //return &amp;quot;验证码错误!&amp;quot;; }</code></pre> </li> </ul> <h1>46. 图像处理</h1> <p>&lt;div style=&quot;text-align:right;color:#666;font-size:20px;&quot;&gt;主讲老师 - 李炎恢&lt;/div&gt;</p> <h3>1. <strong>生成图像</strong></h3> <ul> <li> <p>图像处理功能不是系统内置的功能了,需要通过 composer 引入进来;</p> <pre><code class="language-php">composer require topthink/think-image</code></pre> </li> <li> <p>为了更方便的测试,我们在 <strong>public/Image.png</strong> 放置一张图片,这样不用考虑 url 了;</p> <pre><code class="language-php">$image = Image::open(&amp;quot;image.png&amp;quot;); //图片宽度 echo $image-&amp;gt;width(); //图片高度 echo $image-&amp;gt;height(); //图片类型 echo $image-&amp;gt;type(); //图片 mime echo $image-&amp;gt;mime(); //图片大小 dump($image-&amp;gt;size());</code></pre> </li> <li> <p>使用 <strong>crop()</strong> 方法可以裁剪图片,并使用 save() 方法保存到指定路径;</p> <pre><code class="language-php">// 裁剪图片,默认从左上角裁,并保存到指定位置 $image-&amp;gt;crop(550, 400)-&amp;gt;save(&amp;quot;crop1.png&amp;quot;);</code></pre> </li> <li> <p>使用 <strong>thumb()</strong> 方法,可以生成缩略图,配合 save() 把缩略图保存下来;</p> <pre><code class="language-php">// 生成缩略图 $image-&amp;gt;thumb(550, 400)-&amp;gt;save(&amp;quot;thumb1.png&amp;quot;);</code></pre> <pre><code class="language-php">// 手册上并没有Image这个组件功能,应该是没更新,PHP8.2会报错,修改源码 // 256行,添加 (int) $img = imagecreatetruecolor((int)$width, (int)$height); // 269行,添加 (int),如果设置参数3,x,y,w,h都需要 (int) imagecopyresampled($img, $this-&amp;gt;im, 0, 0, $x, $y, (int)$width, (int)$height, $w, $h);</code></pre> </li> </ul> <h3>2. <strong>图像参数</strong></h3> <ul> <li> <p><strong>thumb()</strong> 方法拥有第三个参数,可以追踪进去查看;</p> <pre><code class="language-php">/* 缩略图相关常量定义 */ const THUMB_SCALING = 1; //常量,标识缩略图等比例缩放类型 const THUMB_FILLED = 2; //常量,标识缩略图缩放后填充类型 const THUMB_CENTER = 3; //常量,标识缩略图居中裁剪类型 const THUMB_NORTHWEST = 4; //常量,标识缩略图左上角裁剪类型 const THUMB_SOUTHEAST = 5; //常量,标识缩略图右下角裁剪类型 const THUMB_FIXED = 6; //常量,标识缩略图固定尺寸缩放类型</code></pre> <pre><code class="language-php">$image-&amp;gt;thumb(550, 400, 3)-&amp;gt;save(&amp;quot;thumb1.png&amp;quot;);</code></pre> </li> <li> <p>使用 rotate()方法,可以旋转图片,默认是 90 度,参数可以设置;</p> <pre><code class="language-php">$image-&amp;gt;rotate(180)-&amp;gt;save(&amp;quot;rotate1.png&amp;quot;);</code></pre> </li> <li> <p>save('路径',['类型','质量','是否隔行扫描']),追踪到方法查看;</p> <pre><code class="language-php">save($pathname, $type = null, $quality = 80, $interlace = true)</code></pre> </li> <li> <p>water()方法,可以给图片增加一个图片水印,默认位置为右下角,可看源码常量;</p> <pre><code class="language-php">// 加水印 $image-&amp;gt;water(&amp;quot;Logo.png&amp;quot;)-&amp;gt;save(&amp;quot;water1.png&amp;quot;);</code></pre> </li> <li> <p>text()方法,可以给图片增加一个文字水印;</p> <pre><code class="language-php">$image-&amp;gt;text('Mr.Lee',getcwd().'/1.ttf',20,'#ffffff')-&amp;gt;save('text1.png');</code></pre> </li> </ul> <h1>47. 分页处理</h1> <p>&lt;div style=&quot;text-align:right;color:#666;font-size:20px;&quot;&gt;主讲老师 - 李炎恢&lt;/div&gt;</p> <h3>1. <strong>简易分页</strong></h3> <ul> <li> <p>不管是数据库操作还是模型操作,都使用 paginate()方法来实现;</p> <pre><code class="language-php">// 数据集 $list = User::paginate(3); // 单独分页 $page = $list-&amp;gt;render(); return view(&amp;quot;index&amp;quot;, [ &amp;quot;list&amp;quot; =&amp;gt; $list, &amp;quot;page&amp;quot; =&amp;gt; $page ]);</code></pre> <p>```php+HTML &lt;table border=&quot;1&quot;&gt; &lt;tr&gt; &lt;th&gt;id&lt;/th&gt; &lt;th&gt;姓名&lt;/th&gt; &lt;th&gt;年龄&lt;/th&gt; &lt;th&gt;性别&lt;/th&gt; &lt;/tr&gt; &lt;?php foreach ($list as $user) {?&gt; &lt;tr&gt; &lt;td&gt;&lt;?=$user[&quot;id&quot;]?&gt;&lt;/td&gt; &lt;td&gt;&lt;?=$user[&quot;name&quot;]?&gt;&lt;/td&gt; &lt;td&gt;&lt;?=$user[&quot;age&quot;]?&gt;&lt;/td&gt; &lt;td&gt;&lt;?=$user[&quot;gender&quot;]?&gt;&lt;/td&gt; &lt;/tr&gt; &lt;?php }?&gt; &lt;/table&gt;</p> <p>&lt;div&gt;&lt;?=$page?&gt;&lt;/div&gt;</p> <pre><code></code></pre> </li> <li> <p>可以通过浏览器的源码检查,或者使用输出html实体的方式来了解 page 构造,方便设计 css;</p> <p>```php+HTML &lt;div&gt;&lt;?=htmlentities($page)?&gt;&lt;/div&gt;</p> <pre><code></code></pre> </li> <li> <p><strong>paginate()</strong> 可以限定总记录数,比如,限定总记录数只有 10 条的页码;</p> <pre><code class="language-php">-&amp;gt;paginate(5, 10);</code></pre> </li> <li> <p>可以设置分页的页码为简洁分页,就是没有 1,2,3,4 这种,只有上下页;</p> <pre><code class="language-php">-&amp;gt;paginate(5, true);</code></pre> </li> </ul> <h3>2. <strong>分页参数</strong></h3> <ul> <li> <p>如果想自行制作个性化分页,或获取分页中的各种参数,这里也提供了:</p> <table> <thead> <tr> <th style="text-align: center;">参数</th> <th style="text-align: center;">描述</th> </tr> </thead> <tbody> <tr> <td style="text-align: center;">list_rows</td> <td style="text-align: center;">每页数量</td> </tr> <tr> <td style="text-align: center;">page</td> <td style="text-align: center;">当前页</td> </tr> <tr> <td style="text-align: center;">path</td> <td style="text-align: center;">url路径</td> </tr> <tr> <td style="text-align: center;">query</td> <td style="text-align: center;">url额外参数</td> </tr> <tr> <td style="text-align: center;">fragment</td> <td style="text-align: center;">url锚点</td> </tr> <tr> <td style="text-align: center;">var_page</td> <td style="text-align: center;">分页变量</td> </tr> </tbody> </table> <pre><code class="language-php">$list = User::paginate([ &amp;quot;list_rows&amp;quot; =&amp;gt; 3, &amp;quot;var_page&amp;quot; =&amp;gt; &amp;quot;p&amp;quot;, ]);</code></pre> </li> <li> <p>分页提供了 <strong>total()</strong> 方法,来获取所有总记录:</p> <pre><code class="language-php">// 获取总记录 $total = $list-&amp;gt;total();</code></pre> </li> </ul> <h3>3. <strong>其它分页</strong></h3> <ul> <li> <p>重写 <strong>Paginate</strong> 类,复制 <strong>Bootstrap</strong> 类,开启重写:</p> <pre><code class="language-php">// 路径:vendor/topthink/think-orm/src/paginator/driver/Bootstrap.php // 开启:app/common/Bootstrap.php, provider.php return [ 'think\Paginator' =&amp;gt; 'app\common\Bootstrap' ]; // 复制后,修改上一页和下一页中文即可 protected function getPreviousButton(string $text = '上一页'): string</code></pre> </li> <li>手册 提供了 大数据分页 :<strong>PaginateX()</strong> 方法,用于百万级提高性能的。嗯!</li> </ul> <h1>48. 中间件入门</h1> <p>&lt;div style=&quot;text-align:right;color:#666;font-size:20px;&quot;&gt;主讲老师 - 李炎恢&lt;/div&gt;</p> <h3>1. <strong>定义中间件</strong></h3> <ul> <li> <p>中间件的主要用于拦截和过滤 HTTP 请求,并进行相应处理;</p> </li> <li> <p>这些请求的功能可以是 URL 重定向、权限验证等等;</p> </li> <li> <p>为了进一步了解中间件的用法,我们首先定义一个基础的中间件;</p> </li> <li> <p>可以通过命令行模式,在应用目录下生成一个中间件文件和文件夹;</p> <pre><code class="language-php">php think make:middleware Check</code></pre> <pre><code class="language-php">public function handle($request, \Closure $next) { // 拦截请求 if ($request-&amp;gt;param(&amp;quot;name&amp;quot;) == &amp;quot;index&amp;quot;) { return redirect(&amp;quot;../&amp;quot;); } // 继续往执行 return $next($request); }</code></pre> </li> <li> <p>然后将这个中间件进行注册,在应用目录下创建 middleware.php 中间件配置;</p> <pre><code class="language-php">// 注册中间件 app\middleware\Check::class</code></pre> </li> <li>中间件的入口执行方法必须是:handle()方法,第一参数请求,第二参数是闭包;</li> <li>业务代码判断请求的 name 如果等于 index,就拦截住,执行中间件,跳转到首页;</li> <li>但如果请求的 name 是 lee,那需要继续往下执行才行,不能被拦死;</li> <li>那么就需要$next($request)把这个请求去调用回调函数;</li> <li>中间件 handle()方法规定需要返回 response 对象,才能正常使用;</li> <li>而$next($request)执行后,就是返回的 response 对象;</li> <li>为了测试拦截后,无法继续执行,可以 return response()助手函数测试;</li> </ul> <h3>2. <strong>前后置中间件</strong></h3> <ul> <li> <p>将$next($request)放在方法底部的方式,属于前置中间件;</p> </li> <li> <p>前置中间件就是请求阶段来进行拦截验证,比如登录判断、跳转、权限等;</p> </li> <li> <p>而后置中间件就是请求完毕之后再进行验证,比如写入日志等等;</p> <pre><code class="language-php">public function handle($request, \Closure $next) { //中间件代码,前置 return $next($request); }</code></pre> <pre><code class="language-php">public function handle($request, \Closure $next) { $response = $next($request); //中间件代码,后置 return $response; }</code></pre> <pre><code class="language-php">// 先执行内容,再执行中间件 $response = $next($request); // 拦截请求 if ($request-&amp;gt;param(&amp;quot;name&amp;quot;) == &amp;quot;index&amp;quot;) { return redirect(&amp;quot;../&amp;quot;); } return $response;</code></pre> </li> </ul> <h1>49. 中间件操作</h1> <p>&lt;div style=&quot;text-align:right;color:#666;font-size:20px;&quot;&gt;主讲老师 - 李炎恢&lt;/div&gt;</p> <h3>1. <strong>路由中间件</strong></h3> <ul> <li> <p>创建一个给路由使用的中间件,判断路由的 ID 值实现相应的验证;</p> <pre><code class="language-php">php think make:middleware Auth</code></pre> </li> <li> <p>路由方法提供了一个 <strong>middleware()</strong> 方法,让指定的路由采用指定的中间件;</p> <pre><code class="language-php">// 限定这个路由采用了中间件 Route::rule('/', 'Index/index')-&amp;gt;middleware(\app\middleware\Auth::class);</code></pre> <pre><code class="language-php">// 导入后,可以省略 use app\middleware\Auth; use app\middleware\Check; // 路由采用多个中间件 Route::rule('/', 'Index/index')-&amp;gt;middleware([Auth::class, Check::class]);</code></pre> </li> <li> <p>也可以在 config/middleware.php 配置文件加中,配置别名支持;</p> <pre><code class="language-php">// 别名或分组 'alias' =&amp;gt; [ &amp;quot;Auth&amp;quot; =&amp;gt; \app\middleware\Auth::class, &amp;quot;Check&amp;quot; =&amp;gt; \app\middleware\Check::class, ],</code></pre> <pre><code class="language-php">// 当然,Route::group() 路由分组也支持 Route::rule('/', 'Index/index')-&amp;gt;middleware([&amp;quot;Auth&amp;quot;, &amp;quot;Check&amp;quot;]);</code></pre> </li> </ul> <h3>2. <strong>控制器中间件</strong></h3> <ul> <li> <p>如果不用路由,怎么用局部化的中间件呢?当然也可以直接在控制器上定义;</p> <pre><code class="language-php">// 这里是别名方式,和路由一样,另外两种均支持 protected $middleware = [&amp;quot;Auth&amp;quot;, &amp;quot;Check&amp;quot;];</code></pre> </li> <li> <p>默认是控制器全体方法有效,如果需要限制,还是 <strong>only</strong> 和 <strong>except</strong>;</p> <pre><code class="language-php">protected $middleware = [ &amp;quot;Auth&amp;quot; =&amp;gt; [&amp;quot;only&amp;quot; =&amp;gt; [&amp;quot;hello&amp;quot;]], &amp;quot;Check&amp;quot; =&amp;gt; [&amp;quot;only&amp;quot; =&amp;gt; [&amp;quot;index&amp;quot;]] ];</code></pre> </li> </ul> <h1>50. 助手函数和工具库</h1> <p>&lt;div style=&quot;text-align:right;color:#666;font-size:20px;&quot;&gt;主讲老师 - 李炎恢&lt;/div&gt;</p> <h3>1. <strong>助手函数</strong></h3> <ul> <li> <p>前面,我们已经学习了不少实用的助手函数,这里再总结一些:手册 -&gt; 附录 -&gt; 助手函数</p> <table> <thead> <tr> <th>助手函数</th> <th>说明</th> </tr> </thead> <tbody> <tr> <td>env</td> <td>支持 Env:: 模式,环境变量</td> </tr> <tr> <td>config</td> <td>支持 Config:: 模式,配置信息</td> </tr> <tr> <td>app_path</td> <td>一组六个,自行参考手册,当前应用目录</td> </tr> </tbody> </table> <pre><code class="language-php">// 获取所有环境变量信息 halt(env()); // 获取HOST return env(&amp;quot;DB_HOST&amp;quot;); // 获取所有配置信息 halt(config()); // 获取默认应用名 return config(&amp;quot;app.default_app&amp;quot;); // 当前应用目录 return app_path();</code></pre> </li> </ul> <h3>2. <strong>助手工具库</strong></h3> <ul> <li> <p>实用助手工具库,需要安装扩展:手册 -&gt; 扩展库 -&gt; think助手工具库</p> <pre><code class="language-php">composer require topthink/think-helper</code></pre> <pre><code class="language-php">// 将字母转换为小写 return Str::lower(&amp;quot;ABCDEFG&amp;quot;);</code></pre> </li> </ul>

页面列表

ITEM_HTML