Laravel 8 笔记
记一下笔记
入门
安装
composer create-project laravel/laravel my_super_powerfull_laravel_app
cd my_super_powerfull_laravel_app
php artisan serve
配置
环境配置
环境配置使用.env文件,其中所有的值都被解析为字符串,然后存放在全局变量$_ENV里面,不要提交到版本管理器。
带空格的值需要用双引号。
可以用env函数来检索
'debug'=>env('APP_DEBUG',false),//第二个参数表示默认值
获取当前环境
就是.env里面APP_ENV定义的环境。可以用门面方法。
use Illuminate\Support\Facades\App;
$environment = App::environment();
enviroment方法接收1个参数,判断当前环境是否为接收到的值。如果是则返回true。
if (App::environment('local')) {
// 当前环境是 local
}
if (App::environment(['local', 'staging'])) {
// 当前环境是 local 或者 staging...
}
- 环境名可以在服务中重新定义
获取配置
任何时候都可以用config函数来获取,可以用小数点,还可以指定默认值。
$value = config('app.timezone');
// 如果配置值不存在,返回一个默认值
$value = config('app.timezone', 'Asia/Seoul');
修改配置,要用数组
config(['app.timezone' => 'America/Chicago']);
缓存配置
生产环境应该用php artisan config:cache
来将所有配置合并到一个缓存文件,以便程序快速访问。
本地开发环境不要用,因为使用后,更改配置不会生效。如果要用的话,那就应该只在配置文件里面调用env函数,不要在其他地方调用env函数。因为缓存了配置后,就不会加载.env文件的内容了。
调试模式Debug
config/app.php里面的debug,配置调试模式是否开启。默认情况下,会以.env文件中的APP_DEBUG设置为准。开发环境打开,生产环境关闭,否则会泄露服务器以及应用配置信息。
维护模式
请求生命周期
入口
入口public/index.php
,之后从bootstrap/app.php
中检索应用程序实例
HTTP和Console内核
先关注HTTP内核
- HTTP内核从
Illuminate\Foundation\HTTP\kernel
扩展而来。这个内核定义了一个,执行请求前需要运行的引导程序数组。这些引导程序用来配置异常处理、配置日志、检测应用程序环境。通常不需要在意这些配置 - 中间件列表,所有请求先经过中间件,再到应用程序。此处确定程序是否处于维护模式,校验csfr等。
服务Service Provider
内核会加载config/app.php
里面providers
数组里面定义的服务。
Laravel会遍历这个数组,实例化每一个服务,实例化后调用register
方法。注册了所有服务后,会调用其boot
方法。
服务负责引导框架的组件,如数据库、队列、验证和路由组件。Laravel的主要功能都来自服务。
路由Route
App\providers\RouteServiceProvider
提供路由服务,它会加载routes
目录中包含的路由文件。
框架启动完成,所有服务均已注册完毕后,路由服务将接管请求,并将其分发到对应的路径、控制器、或者路由相关中间件。
要过滤或检查请求内容,用中间件就很方便。比如,Laravel有个中间件,来判断用户是否有权限。如果没有,页面会跳转到登陆页;如果有权限,请求会进入应用程序去进一步处理。
有些中间件默认分配到所有路由里面,比如HTTP内核中$middleware
变量中定义的那些;有些只会对部分路由生效。
经过了前置中间件的请求,会进入到路由或者控制器,控制器返回的响应还会经过后置中间件,才会发送到用户端。
完结
路由或者控制器返回的响应,还会经过后置中间件,以便检查或者修改响应数据。最后,HTTP内核的handle
方法会返回响应,index.php调用send方把响应发送到用户浏览器。
至此,为一个生命周期。
服务很重要
应用实例创建,服务注册完毕,应用启动完成,处理用户请求。就这么简单。
应用默认的服务都在app\Provicers文件夹里面。
刚开始AppServiceProvider基本是空的,你可以自己添加要启动的服务。
基础功能
路由
基本路由
//返回字符串
Route::get('/greeting', function () {
return 'Hello World';
});
//返回视图
Route::get('/greeting', function () {
return view('greeting',['title'=>'欢迎页面']);
});
//分配控制器
use App\Http\Controllers\UserController;
Route::get('/user', [UserController::class, 'index']);
//限定方法
Route::get($uri, $callback);
Route::post($uri, $callback);
Route::put($uri, $callback);
Route::patch($uri, $callback);
Route::delete($uri, $callback);
Route::options($uri, $callback);
//匹配多个方法
Route::match(['get', 'post'], '/', function () {
//
});
//不限制请求方法
Route::any('/', function () {
//
});
//依赖注入
use Illuminate\Http\Request;
Route::get('/users', function (Request $request) {
// ...
});
CSFR
指向 POST, PUT, PATCH, 或 DELETE 路由的 HTML 表单都应该包含一个 CSRF 令牌字段,否则,这个请求将被拒绝。
<form method="POST" action="/profile">
@csrf
...
</form>
重定向
Route::redirect('/here', '/there');
Route::redirect('/here', '/there', 301);
Route::permanentRedirect('/here', '/there');
返回视图
Route::view('/welcome', 'welcome');
Route::view('/welcome', 'welcome', ['name' => 'Taylor']);
- 参数不能使用view, data, status, 和 headers。
路由参数
Route::get('/user/{id}', function ($id) {
return 'User '.$id;
});
//多个参数
Route::get('/posts/{post}/comments/{comment}', function ($postId, $commentId) {
//
});
//依赖注入,在依赖关系后,列出参数
use Illuminate\Http\Request;
Route::get('/user/{id}', function (Request $request, $id) {
return 'User '.$id;
});
//可选参数,在参数后面加上?,但是要保证有默认值
Route::get('/user/{name?}', function ($name = null) {
return $name;
});
Route::get('/user/{name?}', function ($name = 'John') {
return $name;
});
//正则约束
Route::get('/user/{name}', function ($name) {
//
})->where('name', '[A-Za-z]+');
Route::get('/user/{id}', function ($id) {
//
})->where('id', '[0-9]+');
Route::get('/user/{id}/{name}', function ($id, $name) {
//
})->where(['id' => '[0-9]+', 'name' => '[a-z]+']);
//正则约束助手函数
Route::get('/user/{id}/{name}', function ($id, $name) {
//
})->whereNumber('id')->whereAlpha('name');
Route::get('/user/{name}', function ($name) {
//
})->whereAlphaNumeric('name');
Route::get('/user/{id}', function ($id) {
//
})->whereUuid('id');
- 如果传入参数与约束不匹配,则返回404
路由参数全局约束
在App\Providers\RouteServiceProvider@boot
中定义。
public function boot()
{
Route::pattern('id', '[0-9]+');
}
之后,在相同名称的参数上都会应用这些约束条件。
Route::get('/user/{id}', function ($id) {
// 只有在 id 为数字时才执行...
});
路由命名
必须全局唯一。
Route::get(
'/user/profile',
[UserProfileController::class, 'show']
)->name('profile');
生成url
命名后,就可以在route 和 redirect中使用路由的名字了。额外参数会以查询字符串的形式添加到url。
$url = route('profile', ['id' => 1, 'photos' => 'yes']);
检查当前路由
比如在中间件检查:
public function handle($request, Closure $next)
{
if ($request->route()->named('profile')) {
//
}
return $next($request);
}
路由组
批量分配中间件
定义组之前,指定中间件。
Route::middleware(['first', 'second'])->group(function () {
Route::get('/', function () {
// Uses first & second middleware...
});
Route::get('/user/profile', function () {
// Uses first & second middleware...
});
});
子域路由
最好在定义根路由之前定义子域路由,以免先匹配到根路由。
Route::domain('{account}.example.com')->group(function () {
Route::get('user/{id}', function ($account, $id) {
//
});
});
路由前缀
Route::prefix('admin')->group(function () {
Route::get('/users', function () {
// Matches The "/admin/users" URL
});
});
路由命名前缀
Route::name('admin.')->group(function () {
Route::get('/users', function () {
// Route assigned name "admin.users"...
})->name('users');
});
路由和模型绑定
数据库模型
本作品采用 知识共享署名-相同方式共享 4.0 国际许可协议 进行许可。