Lavavel 一直 秉承着优雅的原则,很好的支持了 composer,实现了更丰富的扩展,社区文档活跃,相较于TP,基于组件式的框架,所以比较臃肿,但是Lavavel 更庞大,安全性也更高 ,更适合开发大中型项目,被称为“巨匠型开发框架”。
在路由文件中我们可以写入很多的处理逻辑,但是当逻辑越来越多单纯的使用路由文件来编写就会使得路由文件越来越大,并且负责的职责也会越来越多。对于面向对象的设计来说是很不合理的,所这里会给予一个控制器组织这些行为。控制器能将相关的请求处理逻辑组成一个单独的类,控制器被存放在 app/Http/Controllers 目录。
1. 基础控制器
控制器都会放在 app\Http\Controllers 目录下面,在其中已经存在了一个 Controller.php 文件,我们可以在其中创建一个 index 方法,通过路由来执行该方法 :
Controller 文件:app\Http\Controllers\Controller.php
<?php namespace App\Http\Controllers; # ...... class Controller extends BaseController { # ...... public function index() { return '我是控制器'; } }
路由文件:routes\web.php
<?php use Illuminate\Support\Facades\Route; use App\Http\Controllers\Controller; Route::get('index',[Controller::class,'index']);
这个就是控制器,只是一般我们把这个控制器作为父类控制器来使用,接下来就要自力更生创建和使用自定义的控制器了。
2. 自定义控制器
首先可以施展我们的 cv 大法来创建自己的控制器。直接复制 Controller.php 文件到当前目录更名,也可以到子目录,记得修改子目录下的控制器的命名空间。例如,复制 Controller.php 控制器更名为 HelloController.php
HelloController 控制器:app\Http\Controllers\HelloController.php
<?php namespace App\Http\Controllers; class HelloController extends Controller { public function index() { return '我是 HelloController 控制器'; } }
路由 :
use App\Http\Controllers\HelloController; Route::get('hello', ,[HelloController::class,'index']);
3. 单行为控制器
以上创建的控制器都是最基础的控制器,加下来我们再来看几个特殊的控制器。首先就是单行为控制器,那么什么是单行为控制器呢?单行为控制器是 一个只处理单个行为的控制器,那么他和普通控制器的区别和特点主要是什么呢?
注意:并不是说单行为控制器中不能创建其他方法或者不能访问,而是作为单一行为控制器其特点是只实现一个功能,体现面向对象的单一职责。
SingleBeController控制器:
app\Http\Controllers\Admin\SingleBeController.php
<?php namespace App\Http\Controllers\Admin; use App\Http\Controllers\Controller; use Illuminate\Http\Request; class SingleBeController extends Controller { # 默认生成的方法 public function __invoke(Request $request) { return '单行为控制器';# 编写其中的唯一存在的方法 } }
路由 :
Route::get('sbc', 'Admin\SingleBeController@__invoke');
如果仅仅是这样的话那么就没有必要使用单一行为控制器了,这时候我们可以这样来创建路由:
Route::get('sbc', 'Admin\SingleBeController');
通过上 URL 来访问能够得到同样的结果,也就是说 单行为控制器只需要 控制器名称 即可默然访问到 __invoke 方法,而这个控制器也只用来实现一个方法。
4.资源控制器
除了单行为控制器之外还有一个 资源控制器,其特点是该控制器符合 restful 规范的控制器,并且可以典型的「CURD (增删改查)」路由分配给控制器。
ResourceController 控制器:app\Http\Controllers\Admin\ResourceController.php
<?php namespace App\Http\Controllers\Admin; class ResourceController extends Controller { # 其他代码省略 测试使用 public function index() { return '资源控制器的 index 方法'; } public function store(Request $request) { return '资源控制器的 store 方法'; } public function show($id) { return '资源控制器的 show 方法'; } }
路由: 这里需要注意的是调用的方法不再是 get 等之类的,而需要通过 resource 创建
use app\Http\Controllers\Admin\ResourceController; Route::resource('resource', ResourceController::class);
通过不同的方式以及改变访问时添加的参数来进行访问,我们会发现访问到的会是不同的方法 。 单行为控制器主要体现单一职责,一个类只实现一个方法。而资源控制器则是规范了开发的方法并且为预先为我们创建了一系列路由,可以快速访问,提升开发效率。
5.控制器中间件
在路由文件中分配给控制器的路由
给控制器使用的中间件也可以直接通过路由来给定到某个控制器,这里我们需要在路由的后面借助 middleware 方法来实现,例如 :
Route::get('midd', [IndexController::class,'index'])->middleware('first');# 分配 first 中间件给 IndexController 控制器使用
在控制器的构造函数中指定中间件
在控制器的构造函数中指定中间件更为方便。在控制器的构造函数中使用 middleware 方法,可以轻松地将中间件分配给控制器的操作,例如 :
<?php namespace App\Http\Controllers\Admin; use App\Http\Controllers\Controller; use Illuminate\Http\Request; class IndexController extends Controller { public function __construct() { $this->middleware('first');# 对当前控制器下所有的方法都使用该中间件, 如果使用多个中间件可以使用数组 } public function index() { return 'IndexController 下的 index'; } public function hello() { return 'IndexController 下的 hello'; } }
如果需要限定中间件分配的方法,还可以在 middleware 方法链式调用 only 或者 except 方法 :
$this->middleware('first')->only('index');# 只对该方法生效 # 或者 $this->middleware('first')->except('index');# 除了该方法,其他方法都生效
这样就能限定中间件生效的方法了。
6. 依赖注入
只要不是由内部生产(比如初始化、构造函数 __construct 中通过自行手动 new 的),而是由外部以参数或其他形式注入的,都属于 依赖注入(DI)。
要通过依赖注入获取当前 HTTP 请求实例,你应该在控制器上引入 Illuminate\Http\Request 类。传入的请求实例将会由服务容器自动注入。
# 这里使用依赖注入方式 public function login(Request $request) { $user = $request->input();# 获取到的是一个数组, dd($user); }
设置的数据通过 request 请求对象成功获取到了。那么为什么依赖注入可以实现数据的获取而自己创建实例则无法获取呢?那么就要具体的看看什么是依赖注入了。
<?php # 车类 - 给人类使用 class Car { public $color; public $type; } # 人类 - 调用车类 class Person { # 1.依赖注入方式 public function drive(Car $car) { $color = $car->color; $type = $car->type; echo "开 $color 的 $type "; } # --------------------------------- # 2.手动创建方式 public function drive() { $car = new Car(); $color = $car->color; $type = $car->type; echo "开 $color 的 $type "; } } # 1.依赖注入 $car = new Car();# 创建车类对象并对原有属性赋值 $car->color = '白色'; $car->type = '小轿车'; (new Person())->drive($car);# 传递被修改过的对象 # 结果:开 白色 的 小轿车 # 2.手动创建 (new Person())->drive();# 在人类中创建车类对象,不再外部传递 # 结果:开 的
从上面的结果来看,我们可以看出新创建的对象无法和其他对象共有同一属性值,所以如果我们需要使用之前保存在对象中的内容就需要通过注入的方式传递对象而不能重新创建。
7. 门面静态调用
要通过门面调用请求数据,你应该在控制器上引入 use Illuminate\Support\Facades\Request 类
<?php namespace App\Http\Controllers\Admin; use App\Http\Controllers\Controller; use Illuminate\Support\Facades\Request;# 这里是需要重点注意的地方,和依赖注入所引用的不是同一个 class IndexController extends Controller { public function login() { $user = Request::input(); dump($user); } }
同样可以获取到数据
8. 助手函数
Laravel 框架为我们提供了很多助手函数方便我们直接使用,request 函数就是其中之一,它可以帮助我们快速的获取到 request 对象。
<?php namespace App\Http\Controllers\Admin; class IndexController extends Controller { public function login() { $user = \request()->input(); dump($user); } }
通过助手函数不需要引入什么类,直接通过 request() 函数调用即可。
请求方法
既然框架给我们提供了一个请求对象,那么在其中也会给我们提供一系列已经准备好的方法给我们来使用,方便我们操作。首先来看看我们上面已经接触到的输入数据的获取。
获取输入
(1)input
上面已经接触到了 input 方法,从结果可以看出 其返回值是一个包含所有数据的键值对数组 - 获取所有数据 ,那么能不能传递键到 input 中直接获取需要的值呢?
$name = \request()->input('name'); dump($name);
j结果我们是可以直接传递 key 从而获取对应的值的。
(2)all 和 input 方法比较类似的还有一个 all 方法,其作用也是获取所有数据,其不同点就在于 获取单个数据的时候,其返回的结果还是数组 。
$user = \request()->all(); dump($user);
(3)only 与 except 有时候我们可能 不需要的这么多的数据,只需要其中的几个即可 ,Laravel 框架的请求对象也很贴心的给我们创建了 only 与 except 两个方法来实现 :
$name = \request()->only('name');# 只获取的数据,多个数据可以通过数组传递 dump($name); $name = \request()->except('name');# 只获取的数据,多个数据可以通过数组传递 dump($name);
结果分别是 : array:1 [ "name" => "jack" ] array:1 [ "password" => "123456" ] 另外还有一种 通过属性直接获取的方式,我们可以看看 :
$name = \request()->name; dump($name);