Laravel学习(一)

原文地址:https://blog.csdn.net/zdw19861127/article/details/75394365

介绍

Laravel 是一套简洁、优雅的PHP Web开发框架(PHP Web Framework)。它可以让你从面条一样杂乱的代码中解脱出来;它可以帮你构建一个完美的网络APP,而且每行代码都可以简洁、富于表达力。

请求周期

Laravel 采用了单一入口模式,应用的所有请求入口都是 public/index.php 文件。

  1. 注册类文件自动加载器:Laravel通过composer进行依赖管理,并在bootstrap/autoload.php中注册了Composer Auto Loader (PSR-4),应用中类的命名空间将被映射到类文件实际路径,不再需要开发者手动导入各种类文件,而由自动加载器自行导入。因此,Laravel允许你在应用中定义的类可以自由放置在Composer Auto Loader能自动加载的任何目录下,但大多数时候还是建议放置在app目录下或app的某个子目录下
  2. 创建服务容器:从 bootstrap/app.php 文件中取得 Laravel 应用实例 $app (服务容器)
  3. 创建 HTTP / Console 内核:传入的请求会被发送给 HTTP 内核或者 console 内核进行处理,HTTP 内核继承自 Illuminate\Foundation\Http\Kernel 类。它定义了一个 bootstrappers 数组,数组中的类在请求真正执行前进行前置执行,这些引导程序配置了错误处理,日志记录,检测应用程序环境,以及其他在请求被处理前需要完成的工作;HTTP 内核同时定义了一个 HTTP 中间件列表,所有的请求必须在处理前通过这些中间件处理 HTTP session 的读写,判断应用是否在维护模式, 验证 CSRF token 等等
  4. 载入服务提供者至容器:在内核引导启动的过程中最重要的动作之一就是载入服务提供者到你的应用,服务提供者负责引导启动框架的全部各种组件,例如数据库、队列、验证器以及路由组件。因为这些组件引导和配置了框架的各种功能,所以服务提供者是整个 Laravel 启动过程中最为重要的部分,所有的服务提供者都配置在 config/app.php 文件中的 providers 数组中。首先,所有提供者的 register 方法会被调用;一旦所有提供者注册完成,接下来,boot 方法将会被调用
  5. 分发请求:一旦应用完成引导和所有服务提供者都注册完成,Request 将会移交给路由进行分发。路由将分发请求给一个路由或控制器,同时运行路由指定的中间件

服务容器和服务提供者

服务容器是 Laravel 管理类依赖和运行依赖注入的有力工具,在类中可通过 $this->app 来访问容器,在类之外通过 $app 来访问容器;服务提供者是 Laravel 应用程序引导启动的中心,关系到服务提供者自身、事件监听器、路由以及中间件的启动运行。应用程序中注册的路由通过RouteServiceProvider实例来加载;事件监听器在EventServiceProvider类中进行注册;中间件又称路由中间件,在app/Http/Kernel.php类文件中注册,调用时与路由进行绑定。在新创建的应用中,AppServiceProvider 文件中方法实现都是空的,这个提供者是你添加应用专属的引导和服务的最佳位置,当然,对于大型应用你可能希望创建几个服务提供者,每个都具有粒度更精细的引导。服务提供者在 config/app.php 配置文件中的providers数组中进行注册

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<?php

namespace App\Providers;

use Foo\Bar;
use Illuminate\Support\ServiceProvider;

class RiakServiceProvider extends ServiceProvider
{
/**
* 在容器中注册绑定
*
* @return void
*/
public function register()
{
$this->app->singleton(Bar::class, function ($app) {
return new Bar(config('riak'));
});
}
}

依赖注入

Laravel 实现依赖注入方式有两种:自动注入和主动注册。自动注入通过参数类型提示由服务容器自动注入实现;主动注册则需开发人员通过绑定机制来实现,即绑定服务提供者或类(参考: https://laravel.com/docs/5.5/container )。

  1. 绑定服务提供者或类:这种方式对依赖注入的实现可以非常灵活多样
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<?php

use Illuminate\Support\Facades\Storage;
use App\Http\Controllers\PhotoController;
use App\Http\Controllers\VideoController;
use Illuminate\Contracts\Filesystem\Filesystem;

$this->app->when(PhotoController::class)
->needs(Filesystem::class)
->give(function () {
return Storage::disk('local');
});

$this->app->when(VideoController::class)
->needs(Filesystem::class)
->give(function () {
return Storage::disk('s3');
});
  1. 参数类型声明:通过对类的构造器参数类型、类的方法参数类型、闭包的参数类型给出提示来实现
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
<?php

namespace App\Http\Controllers;

use App\Users\Repository as UserRepository;

class UserController extends Controller
{
/**
* user repository 实例。
*/
protected $users;

/**
* 控制器构造方法。
*
* @param UserRepository $users
* @return void
*/
public function __construct(UserRepository $users)
{
$this->users = $users;
}

/**
* 储存一个新用户。
*
* @param Request $request
* @return Response
*/
public function store(Request $request)
{
$name = $request->input('name');

//
}
}
  1. 路由参数依赖:下边的示例使用 Illuminate\Http\Request 类型提示的同时还获取到路由参数id
1
2
3
4
<?php
// routes/web.php

Route::put('user/{id}', 'UserController@update');
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<?php
// app/Http/Controllers/UserController

namespace App\Http\Controllers;

use Illuminate\Http\Request;

class UserController extends Controller
{
/**
* 更新指定的用户。
*
* @param Request $request
* @param string $id
* @return Response
*/
public function update(Request $request, $id)
{
//
}
}

Artisan Console

Laravel利用PHP的CLI构建了强大的Console工具artisan,artisan几乎能够创建任何你想要的模板类以及管理配置你的应用,在开发和运维管理中扮演着极其重要的角色,artisan是Laravel开发不可或缺的工具。在Laravel根目录下运行:PHP artisan list可查看所有命令列表。用好artisan能极大地简化开发工作,并减少错误发生的可能;另外,还可以编写自己的命令。下面列举部分比较常用的命令:

  • 启用维护模式:php artisan down –message=’Upgrading Database’ –retry=60
  • 关闭维护模式:php artisan up
  • 生成路由缓存:php artisan route:cache
  • 清除路由缓存:php artisan route:clear
  • 数据库迁移 Migrations:php artisan make:migration create_users_table –create=users
  • 创建资源控制器:php artisan make:controller PhotoController –resource –model=Photo
  • 创建模型及迁移:php artisan make:model User -m

表单验证机制

表单验证在web开发中是不可或缺的,其重要性也不言而喻,也算是每个web框架的标配部件了。Laravel表单验证拥有标准且庞大的规则集,通过规则调用来完成数据验证,多个规则组合调用须以“|”符号连接,一旦验证失败将自动回退并可自动绑定视图。

下例中,附加bail规则至title属性,在第一次验证required失败后将立即停止验证;“.”语法符号在Laravel中通常表示嵌套包含关系,这个在其他语言或框架语法中也比较常见

1
2
3
4
5
6
7
8
9
<?php

use Illuminate\Http\Request;

$this->validate(Request::all(), [
'title' => 'bail|required|unique:posts|max:255',
'author.name' => 'required',
'author.description' => 'required',
]);

Laravel验证规则参考 https://laravel.com/docs/5.5/validation ;另外,在Laravel开发中还可采用如下扩展规则:

  • 自定义FormRequest (须继承自 Illuminate\Foundation\Http\FormRequest )
  • Validator::make()手动创建validator实例
  • 创建validator实例验证后钩子
  • 按条件增加规则
  • 数组验证
  • 自定义验证规则

事件机制

Laravel事件机制是一种很好的应用解耦方式,因为一个事件可以拥有多个互不依赖的监听器。事件类 (Event) 类通常保存在 app/Events 目录下,而它们的监听类 (Listener) 类被保存在 app/Listeners 目录下,使用 Artisan 命令来生成事件和监听器时他们会被自动创建。

  1. 注册事件和监听器:EventServiceProvider的 listen 属性数组用于事件(键)到对应的监听器(值)的注册,然后运行 php artisan event:generate将自动生成EventServiceProvider中所注册的事件(类)模板和监听器模板,然后在此基础之上进行修改来实现完整事件和监听器定义;另外,你也可以在 EventServiceProvider 类的 boot 方法中通过注册闭包事件来实现

  2. 定义事件(类):事件(类)就是一个包含与事件相关信息数据的容器,不包含其它逻辑

  3. 定义监听器:事件监听器在 handle 方法中接受了事件实例作为参数

  4. 停止事件传播:在监听器的 handle 方法中返回 false 来停止事件传播到其他的监听器

  5. 触发事件:调用 event 辅助函数可触发事件,事件将被分发到它所有已经注册的监听器上

  6. 队列化事件监听器:如果监听器中需要实现一些耗时的任务,比如发送邮件或者进行 HTTP 请求,那把它放到队列中处理是非常有用的。在使用队列化监听器,须在服务器或者本地环境中配置队列并开启一个队列监听器,还要增加 ShouldQueue 接口到你的监听器类;如果你想要自定义队列的连接和名称,你可以在监听器类中定义 $connection 和 $queue 属性;如果队列监听器任务执行次数超过在工作队列中定义的最大尝试次数,监听器的 failed 方法将会被自动调用

  7. 事件订阅者:事件订阅者允许在单个类中定义多个事件处理器,还应该定义一个 subscribe 方法,这个方法接受一个事件分发器的实例,通过调用事件分发器的 listen 方法来注册事件监听器,然后在 EventServiceProvider 类的 $subscribe 属性中注册订阅者

Eloquent 模型

Eloquent ORM 以ActiveRecord形式来和数据库进行交互,拥有全部的数据表操作定义,单个模型实例对应数据表中的一行

1
2
3
4
5
6
<?php

$flights = App\Flight::where('active', 1)
->orderBy('name', 'desc')
->take(10)
->get();

config/database.php中包含了模型的相关配置项。Eloquent 模型约定:

  • 数据表名:模型以单数形式命名(CamelCase),对应的数据表为蛇形复数名(snake_cases),模型的$table属性也可用来指定自定义的数据表名称
  • 主键:模型默认以id为主键且假定id是一个递增的整数值,也可以通过incrementing = false
  • 时间戳:模型会默认在你的数据库表有 created_at 和 updated_at 字段,设置dateFormat 属性用于在模型中设置自己的时间戳格式
  • 数据库连接:模型默认会使用应用程序中配置的数据库连接,如果你想为模型指定不同的连接,可以使用 $connection 属性自定义
  • 批量赋值:当用户通过 HTTP 请求传入了非预期的参数,并借助这些参数 create 方法更改了数据库中你并不打算要更改的字段,这时就会出现批量赋值(Mass-Assignment)漏洞,所以你需要先在模型上定义一个 guarded(黑名单,禁止批量赋值字段名数组)
  • 模型软删除:如果模型有一个非空值 deleted_at,代表模型已经被软删除了。要在模型上启动软删除,则必须在模型上使用Illuminate\Database\Eloquent\SoftDeletes trait 并添加 deleted_at 字段到你的模型 $dates 属性上和数据表中,通过调用trashed方法可查询模型是否被软删除
  • 查询作用域:Laravel允许对模型设定全局作用域和本地作用域(包括动态范围),全局作用域允许我们为模型的所有查询添加条件约束(定义一个实现 Illuminate\Database\Eloquent\Scope 接口的类),而本地作用域允许我们在模型中定义通用的约束集合(模型方法前加上一个 scope 前缀)。作用域总是返回查询构建器
  • 隐藏和显示属性:模型visible 属性用于显示属性和关联的输出,另外makeVisible()还可用来临时修改可见性。当你要对关联进行隐藏时,需使用关联的方法名称,而不是它的动态属性名称
  • 访问器和修改器:访问器(getFooAttribute)和修改器(setFooAttribute)可以让你修改 Eloquent 模型中的属性或者设置它们的值,比如你想要使用 Laravel 加密器来加密一个被保存在数据库中的值,当你从 Eloquent 模型访问该属性时该值将被自动解密。访问器和修改器要遵循cameCase命名规范,修改器会设置值到 Eloquent 模型内部的 $attributes 属性上
  • 追加属性:在转换模型到数组或JSON时,你希望添加一个在数据库中没有对应字段的属性,首先你需要为这个值定义一个 访问器,然后添加该属性到改模型的 appends 属性中
  • 属性类型转换:$casts 属性数组在模型中提供了将属性转换为常见的数据类型的方法,且键是那些需要被转换的属性名称,值则是代表字段要转换的类型。支持的转换的类型有:integer、real、float、double、string、boolean、object、array、collection、date、datetime、timestamp
  • 序列化: Laravel模型及关联可递归序列化成数组或JSON
  • 关联(方法)与动态属性:在 Eloquent 模型中,关联被定义成方法(methods),也可以作为强大的查询语句构造器。Eloquent 模型支持多种类型的关联:一对一、一对多、多对多、远层一对多、多态关联、多态多对多关联
  • 模型事件: Laravel为模型定义的事件包括creating, created, updating, updated, saving, saved, deleting, deleted, restoring, restored。 模型上定义一个 $events 属性

Laravel的Restful风格

一般认为Restful风格的资源定义不包含操作,但是在Laravel中操作(动词)也可作为一种资源来定义。下图是对Laravel中资源控制器操作原理的描述,可以看到,create、edit就直接出现在了URI中,它们是一种合法的资源。对于create和edit这两种资源的访问都采用GET方法来实现,第一眼看到顿感奇怪,后来尝试通过artisan console生成资源控制器,并注意到其对create、edit给出注释“ Show the form for ”字样,方知它们只是用来展现表单而非提交表单的。

扩展开发

我们知道,Laravel本身是基于Composer管理的一个包,遵循Composer的相关规范,可以通过Composer来添加所依赖的其他Composer包,因此在做应用的扩展开发时,可以开发Composer包然后引入项目中即可;另外也可开发基于Laravel的专属扩展包。下面所讲的就是Laravel的专属扩展开发,最好的方式是使用 contracts ,而不是 facades,因为你开发的包并不能访问所有 Laravel 提供的测试辅助函数,模拟 contracts 要比模拟 facade 简单很多。

作者

Chenmobuys

发布于

2019-08-01

更新于

2020-10-14

许可协议