composer create-project laravel/laravel example-app
composer global require laravel/installer
laravel new example-app
如果之前已经安装过,可以运行 composer global update
将其升级到最新版本,最终需要确保 laravel 版本号是 ^4.0 版本,你可以通过 laravel -V 命令查看
Laravel 框架的所有配置文件都存放在 config 目录下 .env 文件中所有变量都会被解析为字符串,因此创建了一些保留值以便从 env() 函数返回更广泛的类型:
.env值 | env()值 |
---|---|
true | (bool)true |
(true) | (bool)true |
false | (bool)false |
(false) | (bool)false |
empty | (string)'' |
(empty) | (string)'' |
null | (null)null |
(null) | (null)null |
如果你需要定义一个包含空格的环境变量值,可以通过将字符串放到双引号中来实现:
APP_NAME="My Application"
应用每次接受请求时,.env 中列出的所有配置及其对应值都会被载入到 PHP 超全局变量 $_ENV 中,然后你就可以在应用中通过辅助函数 env() 来获取这些配置值。实际上,如果你去查看 Laravel 的配置文件,就会发现很多地方已经在使用这个辅助函数了,一般在config文件夹下的配置文件调用env()函数,而在其他地方使用config()函数代替,这样更加规范。如果在部署过程中执行 php artisan config:cache
命令,需要确保只在配置文件中调用了 env 方法。一旦配置文件被缓存后,.env 文件将不能被加载,所有对 env 函数的调用都会返回 null
'debug' => env('APP_DEBUG', false) //访问值
$value = config('app.timezone','Asia/Shanghai'); //访问值
config(['app.timezone'=>'PRC']); //传递数组设置值
当前应用环境由 .env 文件中的 APP_ENV 变量决定,你可以通过 App 门面上的 environment() 方法来访问其值:
use Illuminate\Support\Facades\App;
$environment = App::environment();
你也可以向 environment() 方法传递参数来判断当前环境是否匹配给定值,如果需要的话你甚至可以传递多个值。如果当前环境与给定值匹配,该方法返回 true:
if (App::environment('local')) {
// 环境是local
}
if (App::environment('local', 'staging')) {
// 环境是 local 或者 staging
}
Broadcasting
目录包含了应用所需的所有广播频道类,这些类通过 php artisan make:channel
命令生成。
Console
目录包含应用所有自定义的 Artisan 命令,这些命令类可以使用 php artisan make:command
命令生成。该目录下还有 Console/Kernel 类,在这里可以注册自定义的 Artisan 命令以及定义调度任务。
Events
目录用于存放事件类,事件类用于告知应用其他部分某个事件发生情况并提供灵活的、解耦的处理机制,可以通过 php artisan event:generate
和 php artisan make:event
命令创建。
Exceptions
目录包含应用的异常处理器,同时还是处理应用抛出的任何异常的好地方。如果你想要自定义异常如何记录或渲染,需要编辑该目录下的 Handler 类。
Http
目录包含了控制器、中间件以及表单请求等,几乎所有通过 Web 进入应用的请求处理都在这里进行。
Jobs
目录用于存放队列任务,应用中的任务可以被推送到队列,也可以在当前请求生命周期内同步执行。同步执行的任务有时也被看作命令,因为它们实现了命令模式,可以通过执行 php artisan make:job
命令生成。
Listeners
目录包含处理事件的类(事件监听器),事件监听器接收一个事件并提供对该事件发生后的响应逻辑,可以通过执行 php artisan event:generate
和 php artisan make:listener
命令创建。
Mail
目录包含应用所有邮件相关类,邮件对象允许你在一个地方封装构建邮件所需的所有业务逻辑,然后使用 Mail::send 方法发送邮件,可以通过执行 php artisan make:mail
命令生成。
Models
目录包含了所有的 Eloquent 模型类文件。可以通过执行 php artisan make:model
命令创建模型类。
Notifications
目录包含应用发送的所有通知,比如事件发生通知。Laravel 的通知功能将通知发送和通知驱动解耦,你可以通过邮件,也可以通过 Slack、短信或者数据库发送通知,通过执行 make:notification 命令连带创建。
Policies
目录包含了应用所有的授权策略类,策略用于判断某个用户是否有权限去访问指定资源,你可以通过执行 php artisan make:policy
命令生成策略类来创建。
Providers
目录包含应用的所有服务提供者。服务提供者在应用启动过程中绑定服务到容器、注册事件以及执行其他任务为即将到来的请求处理做好准备工作。
Rules
目录包含应用的自定义验证规则对象,这些规则用于在单个对象中封装复杂的验证逻辑,可以通过 php artisan make:rule
生成。
View
目录包含应用的自定义组件Components目录,可以通过 php artisan make:component
生成,其还会生成resource/views/components目录。
最基本的 Laravel 路由只接收一个 URI 和一个闭包,并以此为基础提供一个非常简单优雅 的路由定义方法:
Route::get('/hello', function(){
return 'hello world!';
});
我们可以通过路由器注册路由来响应任何 HTTP 请求动作:
Route::get($uri, $callback);
Route::post($uri, $callback);
Route::put($uri, $callback);
Route::patch($uri, $callback);
Route::delete($uri, $callback);
Route::options($uri, $callback);
有时候还需要注册一个路由响应多个 HTTP 请求动作 —— 这可以通过 match 方法来实现。或者,可以使用 any 方法注册一个路由来响应所有 HTTP 请求动作:
Route::match(['get', 'post'], '/foo', function () {
return 'This is a request from get or post';
});
Route::any('/bar', function () {
return 'This is a request from any HTTP verb';
});
如果你需要定义一个重定向到其他 URI 的路由,可以使用 Route::redirect 方法,该方法非常方便,以至于你不需要再定义额外的路由或控制器来执行简单的重定向逻辑:
Route::redirect('/here', '/there'); //返回302暂时
其中 here 表示原路由,there 表示重定向之后的路由。默认情况下,Route::redirect 返回 302 状态码,你可以使用可选的第三个参数来自定义这个状态码:
Route::redirect('/here', '/there', 301); //返回301永久
你还可以使用 Route::permanentRedirect 方法来返回 301 状态码(permanent永久的):
Route::permanentRedirect('/here', '/there');
如果你的路由需要返回一个视图,可以使用 Route::view 方法,和 redirect 方法类似,这个方法也很方便,以至于你不需要在额外定义一个路由或控制器。view 方法接收一个 URI 作为第一个参数,以及一个视图名称作为第二个参数,此外,你还可以提供一个数组数据传递到该视图方法作为可选的第三个参数,该数组数据可用于视图中的数据渲染:
Route::view('/welcome', 'welcome');
Route::view('/welcome', 'welcome', ['name' => '学院君']);
有时我们需要在路由中获取 URI 请求参数。例如,如果要从 URL 中获取用户ID,需要通过如下方式定义路由参数:
Route::get('user/{id}', function ($id) { return 'User ' . $id; });
这样我们在浏览器中访问 http://127.0.0.1:8000/user/1,就会得到以下输出:
User 1
可以根据需要在路由中定义多个路由参数:
Route::get('posts/{post}/comments/{comment}', function ($postId, $commentId) {
return $postId . '-' . $commentId;
});
根据上面的示例,路由参数需要通过花括号 {} 进行包裹并且是拼音字母,这些参数在路由被执行时会被传递到路由的闭包。路由参数名称不能包含 - 字符,如果需要的话可以使用 _ 替代,比如如果某个路由参数定义成 {post-id} 则访问路由会报错,应该修改成 {post_id} 才行。路由参数被注入到路由回调/控制器取决于它们的顺序,与回调/控制器名称无关。
有必选参数就有可选参数,这可以通过在参数名后加一个 ? 标记来实现,这种情况下需要给相应的变量指定默认值,当对应的路由参数为空时,使用默认值:
Route::get('user/{name?}', function ($name = 'John') {
return $name;
});
这时如果定义的路由是下面这个的话,访问 http://127.0.0.1:8000/user 会返回 John
Route::get('user/{name}', function ($name) {
// $name 必须是字母且不能为空
})->where('name', '[A-Za-z]+');
Route::get('user/{id}', function ($id) {
// $id 必须是数字
})->where('id', '[0-9]+');
Route::get('user/{id}/{name}', function ($id, $name) {
// 同时指定 id 和 name 的数据格式
})->where(['id' => '[0-9]+', 'name' => '[a-z]+']);
如果想要路由参数在全局范围内被给定正则表达式约束,可以使用 pattern 方法。需要在 RouteServiceProvider 类的 boot 方法中定义这种约束模式:
/**
* 定义路由模型绑定,模式过滤器等
*
* @param \Illuminate\Routing\Router $router
* @return void
* @translator http://laravelacademy.org
*/
public function boot()
{
Route::pattern('id', '[0-9]+');
}
路由命名为生成 URL 或重定向提供了方便,实现起来也很简单,在路由定义之后使用 name 方法链的方式来定义该路由的名称:
Route::get('user/profile', function () {
// 通过路由名称生成 URL
return 'my url: ' . route('profile');
})->name('profile');
//还可以为控制器动作指定路由名称:
Route::get('user/profile', [UserProfileController::class, 'show'])->name('profile');
//这样我们就可以通过以下方式定义重定向:
Route::get('redirect', function() {
// 通过路由名称进行重定向
return redirect()->route('profile');
});
// 生成URL
$url = route('profile');
// 生成重定向
return redirect()->route('profile');
如果命名路由定义了参数,可以将该参数作为第二个参数传递给 route 函数。给定的路由参数将会自动插入到 URL 中:
Route::get('user/{id}/profile', function ($id) {
return route('profile', ['id' => 1]);
})->name('profile');
如果通过数组传入额外参数,这些键/值对将会自动添加到生成的 URL 查询字符串:
Route::get('user/{id}/profile', function ($id) {
//
})->name('profile');
$url = route('profile', ['id' => 1, 'photos' => 'yes', 'name' => 'jojo']);
// /user/1/profile?photos=yes&name=jojo
如果你想要判断当前请求是否被路由到给定命名路由,可以使用 Route 实例上的 named 方法,例如,你可以从路由中间件中检查当前路由名称:
/**
* 处理输入请求
*
* @param \Illuminate\Http\Request $request
* @param \Closure $next
* @return mixed
*/
public function handle($request, Closure $next)
{
if ($request->route()->named('profile')) {
//
}
return $next($request);
}
要给某个路由分组中定义的所有路由分配中间件,可以在定义分组之前使用 middleware 方法。中间件将会按照数组中定义的顺序依次执行:
Route::middleware(['first', 'second'])->group(function () {
Route::get('/', function () {
// Uses first & second Middleware
});
Route::get('user/profile', function () {
// Uses first & second Middleware
});
});
路由分组还可以被用于处理子域名路由,子域名可以像 URI 一样被分配给路由参数,从而允许捕获子域名的部分用于路由或者控制器,子域名可以在定义分组之前调用 domain 方法来指定:
Route::domain('{account}.blog.test')->group(function () {
Route::get('user/{id}', function ($account, $id) {
return 'This is ' . $account . ' page of User ' . $id;
});
});
prefix 方法可以用来为分组中每个路由添加一个给定 URI 前缀,例如,你可以为分组中所有路由 URI 添加 admin 前缀 :
Route::prefix('admin')->group(function () {
Route::get('users', function () {
// Matches The "/admin/users" URL
});
});
name 方法可通过传入字符串为分组中的每个路由名称设置前缀,例如,你可能想要在所有分组路由的名称前添加 admin 前缀,由于给定字符串和指定路由名称前缀字符串完全一样,所以需要在前缀字符串末尾后加上 . 字符:
Route::name('admin.')->group(function () {
Route::get('users', function () {
// 新的路由名称为 "admin.users"...
})->name('users');
});
Laravel 会自动解析定义在路由或控制器动作(变量名匹配路由片段)中的 Eloquent 模型类型声明,例如(我们将这个路由定义在 routes/api.php 文件中):
Route::get('users/{user}', function (\App\Models\User $user) {
return $user;
});
Route::get('users/{user}', [TestController::class,'show']);
// show 方法中的参数必须为 App\Models\User $user 才算隐式绑定成功
在这个例子中,由于类型声明了 Eloquent 模型 App\Models\User,对应的变量名 $user 会匹配路由片段中的 {user},这样,Laravel 会自动注入与请求 URI 中传入的 ID 对应的用户模型实例。如果匹配模型实例在数据库中不存在,会自动生成 404 响应。默认键为id,有时候你可能希望使用 id 之外的其它字段(如name)来解析 Eloquent 模型,这可以通过在路由参数定义中指定字段来实现。
Route::get('users/{user:name}', function (\App\Models\User $user) {
return $user;
});
使用自定义键的隐式绑定作为嵌套路由参数时,Laravel 会自动将这个查询限定为先使用默认约定规则判定从属关系(基于父模型上的关联关系名称)再通过父模型获取嵌套子模型实例。在这个示例中,会假定 User 模型有一个名为 posts 的关联关系(路由参数名的复数)用于获取 Post 模型实例。
use App\Models\Post;
use App\Models\User;
Route::get('api/users/{user}/posts/{post:slug}', function (User $user, Post $post) {
return $post;
});
如果你想要在模型绑定中使用数据表的其它字段而不是 id 字段,可以重写 Eloquent 模型类的 getRouteKeyName 方法,这里需要注意的点是如果该字段不是唯一键,则会返回结果集的第一条记录,以 User 模型为例,可以在该模型类中添加这个方法 :
/**
* Get the route key for the model.
*
* @return string
*/
public function getRouteKeyName()
{
return 'name';
}
有隐式绑定,就有显式绑定。要注册显式绑定,可以使用路由器的 model 方法来为给定参数指定绑定类。你需要在 RouteServiceProvider 类的 boot 方法中定义显式模型绑定:
/**
* Define your route model bindings, pattern filters, etc.
*
* @return void
*/
public function boot()
{
Route::model('user', App\Models\User::class);
}
如果你想要使用自定义的解析逻辑,可以在 RouteServiceProvider 类的 boot 方法中使用 Route::bind 方法,传递到 bind 方法的闭包会获取到 URI 请求参数中的值,并且返回你想要在该路由中注入的类实例
/**
* Define your route model bindings, pattern filters, etc.
*
* @return void
*/
public function boot()
{
Route::bind('user', function ($value) {
return App\Models\User::where('name', $value)->firstOrFail();
});
// ...
}
此外,你还可以在 Eloquent 模型中覆盖 resolveRouteBinding 方法,这个方法会获取 URI 片段中的值并返回应该被注入的路由模型类实例:
/**
* Retrieve the model for a bound value.
*
* @param mixed $value
* @param string|null $field
* @return \Illuminate\Database\Eloquent\Model|null
*/
public function resolveRouteBinding($value, $field = null)
{
return $this->where('name', $value)->firstOrFail();
}
使用 Route::fallback 方法可以定义一个当所有其他路由都未能匹配请求 URL 时所执行的路由。通常,未处理请求会通过 Laravel 的异常处理器自动渲染一个「404」页面,不过,如果你在 routes/web.php 文件中定义了 fallback 路由的话,所有 web 中间件组中的路由都会应用此路由作为兜底,兜底路由应该总是放到应用注册的所有路由的最后。当然,如果需要的话,你还可以添加额外的中间件到此路由:
Route::fallback(function () {
//
});
开始之前,你需要定义符合应用需求的频率限制器配置,通常,这可以在应用自带的 RouteServiceProvider 中完成,频率限制器通过 RateLimiter 门面的 for 方法定义,该方法接收频率限制器名称和一个返回限制配置(会应用到频率限制器分配到的路由)的闭包作为参数:
use Illuminate\Cache\RateLimiting\Limit;
use Illuminate\Support\Facades\RateLimiter;
RateLimiter::for('global', function (Request $request) {
return Limit::perMinute(1000);
});
访问频率限制器可以通过 throttle 中间件应用到路由或者路由群组。throttle 中间件接收频率限制器的名称作为参数,然后再将其通过中间件的形式应用到路由即可:
Route::middleware(['throttle:uploads'])->group(function () {
Route::post('/audio', function () {
//
});
Route::post('/video', function () {
//
});
});
HTML 表单不支持 PUT、PATCH 或者 DELETE 请求方法,因此,在 HTML 表单中调用 PUT、PATCH 或 DELETE 路由时,需要添加一个隐藏的 _method 字段,其值被用作该表单的 HTTP 请求方法:
<form action="/foo/bar" method="POST">
<input type="hidden" name="_method" value="PUT">
<input type="hidden" name="_token" value="{{ csrf_token() }}">
</form>
可以直接使用 Blade 指令 @method 来生成 _method 字段:
<form action="/foo/bar" method="POST">
@method('PUT')
@csrf
</form>
你可以使用 Route 门面上的 current、currentRouteName 和 currentRouteAction 方法来访问处理当前输入请求的路由信息:
// 获取当前路由实例
$route = Route::current();
// 获取当前路由名称
$name = Route::currentRouteName();
// 获取当前路由action属性
$action = Route::currentRouteAction();