快速上手 Laravel 的 100 个小技巧

鉴权

Laravel 小技巧

给大家提供一些 Laravel 使用的小技巧, 当然你有任何想法欢迎 PR !

Github 地址

摘要

控制器

单行为控制器

当你的控制器仅有一个方法的时候,不妨尝试下 __invoke() 方法来,让当前控制器变身为 “invokable” 控制器。

想要了解单行为控制器的好处以及用法请参考:

单行为控制器的简单使用:

定义路由,如下:

Route::get('user/{id}', 'ShowProfile');

通过命令创建单行为控制器:

php artisan make:controller ShowProfile --invokable

修改控制器代码,如下:

class ShowProfile extends Controller
{
    public function __invoke($id)
    {
        return view('user.profile', [
            'user' => User::findOrFail($id)
        ]);
    }
}

重定向到指定控制器的指定方法

你可以通过 redirect() 重定向到某个路由或者某个链接,但是当你希望重定向到一个特定方法,并且需要携带一些参数的时候,action 方法可以帮你实现,代码如下:

return redirect()->action('SomeController@method', ['param' => $value]);

接口操作成功而无返回的简单处理

当你在接口执行了某些逻辑,但是不需要返回内容的时候,你可以直接返回 204 状态码。 在 Laravel 中这很容易实现:

Tips: 204 状态码说明

public function reorder(Request $request)
{
    foreach ($request->input('rows', []) as $row) {
        Country::find($row['id'])->update(['position' => $row['position']]);
    }

    return response()->noContent();
}

模型

Eloquent 的日期筛选

Laravel 的 Eloquent Orm 提供了 whereDay(), whereMonth(), whereYear(), whereDate()whereTime() 供你对日期进行筛选。简单例子:

$products = Product::whereDate('created_at', '2018-01-31')->get();
$products = Product::whereMonth('created_at', '12')->get();
$products = Product::whereDay('created_at', '31')->get();
$products = Product::whereYear('created_at', date('Y'))->get();
$products = Product::whereTime('created_at', '=', '14:13:58')->get();

Inter 类型数据的便捷操作 Increments(增加) 和 decrements(减少)

你如果仅仅是操作数字类型字段的增加(减少),你可以尝试下 increment()decrement()) 方法:


Post::find($post_id)->increment('view_count');
User::find($user_id)->increment('points', 50);

获取设置当前用户登录的信息

你可以使用 make:observer 来创建一个观察者,然后通过修改模型事件 creating() 来设定当前用户的信息,代码如下 :
详细使用可以查阅 Laravel 中的模型事件与 Observer

class PostObserver
{
    public function creating(Post $post)
    {
        $post->user_id = auth()->id();
    }
}

软删除后的数据批量恢复

当使用软删除删除数据之后,你可以通过以下方法批量恢复删除的数据:

Post::withTrashed()->where('author_id', 1)->restore();

特定模型字段的返回

默认的 Model::all() 会返回所有字段,不管你是否有需要,当然你也可以通过给 all() 传递参数来指定返回的列。如下:

$users = User::all(['id', 'name', 'email']);

失败或者成功的查询

findOrFail() 方法,可以在查询没有符合条件数据的时候直接抛出异常。

$user = User::where('email', 'povilas@laraveldaily.com')->firstOrFail();

数据返回的列名称的自定义

在 Eloquent 查询中使用 select 可以设置查询的字段,然后你可以通过 “as” 给字段重命名为你想要的名称:

$users = DB::table('users')->select('name', 'email as user_email')->get();

查询结果的 Map 处理

由于 Eloquent 中,get 方法将返回 Collection 类型的数据,所以在通过 get 方法获取数据之后,你可以直接通过 map() 方法来处理:

$users = User::where('role_id', 1)->get()->map(function (User $user) {
    $user->some_column = some_function($user);
    return $user;
});

不使用 timestamps 相关字段

默认的,laravel 会在 migration 以及 model 中添加 timestamps 相关字段(created_at,updated_at),如果你不想使用他,你可以在migrate 中移除相关字段,或者在 model 中设置 timestamps属性,将该属性设置为 false 即可实现:

class Company extends Model
{
    public $timestamps = false;
}

修改默认时间字段

当你想要在已存在的数据库中使用 Laraevl 的 Eloquent Orm的时候,你的时间字段又不同于 Laravel 默认字段,这时候怎么处理呢?你可以通过给以下常量重新赋值来设置当前使用的时间戳字段:

class Role extends Model
{
    const CREATED_AT = 'create_time';
    const UPDATED_AT = 'update_time';
}

快速通过 created_at 排序

在此之前你是这样实现的:

User::orderBy('created_at', 'desc')->get();

当然,你也可以使用更简单的方式:

User::latest()->get();

默认 latest() 会通过 created_at 进行排序。

这里还有个反方法可以用: oldest() 将会通过 created_at 字段进行升序排序。

User::oldest()->get();

当然你也可以通过传递参数来执行想要进行排序的字段,如下:

$lastUpdatedUser = User::newest('updated_at')->first();

创建记录时的自增

当你在创建记录的时候,你同时希望对某个字段进行自增操作的时候,你可以在 boot() 方法中注册 creating 方法来实现。举个例子,现在你有个 “position” 字段,你希望在你完成新增操作的时候同时对该字段 +1 ,实现代码如下:

class Country extends Model {
    protected static function boot()
    {
        parent::boot();

        Country::creating(function($model) {
            $model->position = Country::max('position') + 1;
        });
    }
}

使用 whereRaw() 使查询效率更快

使用 whereRaw() 方法,通常可以使查询效率更高。例如你想获取 30+ 天未登录的用户,你可以通过以下实现:

User::where('active', 1)
    ->whereRaw('TIMESTAMPDIFF(DAY, created_at, updated_at) > ?', 30)
    ->get();

多个作用域

你可以同时创建多个作用域,当然可以在一个查询中使用多个作用域。

模型中定义:

public function scopeActive($query) {
    return $query->where('active', 1);
}

public function scopeRegisteredWithinDays($query, $days) {
    return $query->where('created_at', '>=', now()->subDays($days));
}

controller 中使用:

$users = User::registeredWithinDays(30)->active()->get();

Carbon自动转换

如果你想使用 whereDate() 查询今天的记录,你可以通过直接 now() 而无需进行 ->toDateString(),因为他会自动转换。

// Instead of
$todayUsers = User::whereDate('created_at', now()->toDateString())->get();
// 不需要转换 now()
$todayUsers = User::whereDate('created_at', now())->get();

通过首字符分组

你可以通过任意你想实现的方式进行分组,下面是通过对姓名首字符的分组方法:

$users = User::all()->groupBy(function($item) {
    return $item->name[0];
});

限制数据列的更新

如果你希望设置一个不可更新的列,你可以通过以下方式实现:

class User extends Model
{
    public function setEmailAttribute($value)
    {
        if ($this->email) {
            return;
        }

        $this->attributes['email'] = $value;
    }
}

查询多个

Eloquent 方法 find() 可以通过传递数组参数实现多个记录的查询:

// Will return Eloquent Model
$user = User::find(1);
// Will return Eloquent Collection
$users = User::find([1,2,3]);

使用 UUID 替代 自增列

如果你不想在数据表中使用自增列要怎么办?下面叫你如何实现

数据迁移:

Schema::create('users', function (Blueprint $table) {
    // $table->increments('id');
    $table->uuid('id')->unique();
});

模型:

class User extends Model
{
    public $incrementing = false;
    protected $keyType = 'string';

    protected static function boot()
    {
        parent::boot();

        User::creating(function ($model) {
            $model->setId();
        });
    }

    public function setId()
    {
        $this->attributes['id'] = Str::uuid();
    }
}

模型关联

可排序的模型关联

你可以在你的关联中使用 orderBy对关联进行排序:

public function products()
{
    return $this->hasMany(Product::class);
}

public function productsByName()
{
    return $this->hasMany(Product::class)->orderBy('name');
}

有条件的模型关联

如果你在使用模型关联的时候经常需要额外的进行 where 查询,你可以直接通过对关联进行条件查询,实现方式如下:

Model:

public function comments()
{
    return $this->hasMany(Comment::class);
}

public function approved_comments()
{
    return $this->hasMany(Comment::class)->where('approved', 1);
}

对结果的筛选:havingRaw()

你可以在各种地方使用 RAW DB 查询,包括 groupBy()havingRaw() 后面:

Product::groupBy('category_id')->havingRaw('COUNT(*) > 1')->get();

Eloquent has() 方法可以作用于深层的关联

Eloquent has() 方法可以通过 books.ratings 的方式,而使查询可以做用于更深层的关联上!

// Author -> hasMany(Book::class);
// Book -> hasMany(Rating::class);
$authors = Author::has('books.ratings')->get();

通过 Has 方法对 hasMany 数据限制

在一对多关联中, hasMany() 允许通过 has() 方法进行关联数据条数的限制:

// Author -> hasMany(Book::class)
$authors = Author::has('books', '>', 5)->get();

模型默认值

你可以通过 belongsTo 关联, to avoid fatal errors when calling it like {{ $post->user->name }} if $post->user doesn’t exist.

public function user()
{
    return $this->belongsTo('App\User')->withDefault();
}

一次性创建多条关联记录

如果你定义了 hasMany() 关联,你可以通过 saveMany() 来一次性创建多条关联数据:

$post = Post::find(1);
$post->comments()->saveMany([
    new Comment(['message' => 'First comment']),
    new Comment(['message' => 'Second comment']),
]);

快速且精确的加载

通过 with 你可以获取关联表甚至特定字段信息:

$users = App\Book::with('author:id,name')->get();

你可以使用他获取更深一层次的关联:

$users = App\Book::with('author.country:id,name')->get();

上级信息的级联更新

例如你想在更新评论信息的时候想同时更新上级关联的帖子信息的 updated_at 字段,你可以通过指定 $touch 属性实现:

class Comment extends Model
{
    protected $touches = ['post'];
}

总是检测关联是否存在

永远不要在未检测关联是否存在的情况下使用 $model->relationship->field

It may be deleted for whatever reason, outside your code, by someone else’s queued job etc.

可以通过 if-else,在 Blade 中使用 {{ $model->relationship->field ?? '' }} , 或者 {{ optional($model->relationship)->field }} 进行检测。

使用 withCount() 获取记录条数

如果你定义了 hasMany() 关联,当你想要统计关联数据的数量的时候,尝试下 withCount 吧。例子, 假如你有一个 Post 模型,该模型会有多个 Comments 关联,看下如何使用 withCount() 吧:

public function index()
{
    $users = User::withCount(['posts', 'comments'])->get();
    return view('users', compact('users'));
}

然后在模板文件中使用 {relationship}_count 属性就可以获取相应的数据统计了:

@foreach ($users as $user)
<tr>
    <td>{{ $user->name }}</td>
    <td class="text-center">{{ $user->posts_count }}</td>
    <td class="text-center">{{ $user->comments_count }}</td>
</tr>
@endforeach

关联查询的筛选条件

如果你想要在加载关联的时候做一些条件限制,可以通过回调函数实现。例如你想获取国家的前3个城市,可以通过以下代码实现:

$countries = Country::with(['cities' => function($query) {
    $query->orderBy('population', 'desc');
    $query->take(3);
}])->get();

始终加载关联

你即可以通过 $with 属性设置模型始终会加载的关联,也可以在构造函数中动态处理加载项:

class ProductTag extends Model
{
    protected $with = ['product'];

    public function __construct() {
        parent::__construct();
        $this->with = ['product'];

        if (auth()->check()) {
            $this->with[] = 'user';
        }
    }
}

belongsTo 和 hasMany 的使用

定义 belongsTo 关联和 hasMany 关联,这样可以在创建关联数据的时候有由系统填充关联字段信息:

// 如果定义了 Post -> belongsTo(User), and User -> hasMany(Post)...
// 以前你需要这样创建文章信息...
Post::create([
    'user_id' => auth()->id(),
    'title' => request()->input('title'),
    'post_text' => request()->input('post_text'),
]);

// 现在,你可以这样
auth()->user()->posts()->create([
    'title' => request()->input('title'),
    'post_text' => request()->input('post_text'),
]);

自定义归属关联名称

使用 as 可以重命名你的关联:

模型中定义:

public function podcasts() {
    return $this->belongsToMany('App\Podcast')
        ->as('subscription')
        ->withTimestamps();
}

控制器中使用:

$podcasts = $user->podcasts();
foreach ($podcasts as $podcast) {
    // instead of $podcast->pivot->created_at ...
    echo $podcast->subscription->created_at;
}

数据迁移

迁移执行顺序

通过修改迁移文件的时间戳前缀可以达到排序迁移执行数据的目的。例如:将2018_08_04_070443_create_posts_table.php 修改为 2018_07_04_070443_create_posts_table.php ( 修改 2018_08_042018_07_04 ).

Migration 设定时间戳时区

迁移中 timestamps()timestampsTz() 都可以设定时区。

Schema::create('employees', function (Blueprint $table) {
    $table->increments('id');
    $table->string('name');
    $table->string('email');
    $table->timestampsTz();
});

另外还有 dateTimeTz(), timeTz(), timestampTz(), softDeletesTz().

数据 Migrations 类型

一些特定值得迁移类型:

$table->geometry('positions');
$table->ipAddress('visitor');
$table->macAddress('device');
$table->point('position');
$table->uuid('id');

更多类型查阅: official documentation.

默认时间戳

通过 timestamp() 设定列为时间戳类型,通过
useCurrent() 设定该列的默认值。

$table->timestamp('created_at')->useCurrent();
$table->timestamp('updated_at')->useCurrent();

视图

foreach 中 $loop 的使用

通过 $loop 判断该数据是否是最先/最后的数据:

@foreach ($users as $user)
     @if ($loop->first)
        This is the first iteration.
     @endif

     @if ($loop->last)
        This is the last iteration.
     @endif

     <p>This is user {{ $user->id }}</p>
@endforeach

当然他还有其他可用属性例如: $loop->iteration$loop->count.
详情阅读: official documentation.

如何判断 View 是否存在?

在你加载 view 之前你可以判断 view 是否存在,从而避免不必要的错误显示。

if (view()->exists('custom.page')) {
 // Load the view
}

你可以提供多个 view 供选择:

return view()->first(['custom.dashboard', 'dashboard'], $data);

错误模板页面

快速创建特定错误的页面,你只要以该错误code命名并创建相应的 blade 即可。例如: 500(resources/views/errors/500.blade.php)/403(resources/views/errors/403.blade.php),系统会通过相应的 code 自动匹配错误显示页面。

直接使用 view

可以直接在路由中绑定需要显示的 view:

// 在 controller 绑定 view
Route::get('about', 'TextsController@about');
class TextsController extends Controller
{
    public function about()
    {
        return view('texts.about');
    }
}
// 直接在路由中绑定
Route::view('about', 'texts.about');

Blade @auth

在 Blade 中直接使用 auth() 可以判断以及获取当前登录的用户信息:

例子:

@if(auth()->user())
    // 用户已登录
@endif

或者更简单的方式:

@auth
    // 鉴权通过
@endauth

相反的方法 @guest

@guest
    // 鉴权未通过
@endguest

Blade中循环嵌套中使用 $loop

Blade 循环嵌套,可以通过 $loop 获取上层数据:

@foreach ($users as $user)
    @foreach ($user->posts as $post)
        @if ($loop->parent->first)
            This is first iteration of the parent loop.
        @endif
    @endforeach
@endforeach

自定义 Blade 指令

Laravel 提供了简单的方式自定义 Blade 指令,只需在 app/Providers/AppServiceProvider.php 注册自己的指令即可。例子:你想要使用新的标签替换 <br> 标签:

<textarea>@br2nl($post->post_text)</textarea>

将该指令添加到 AppServiceProvider 的 boot() 方法中:

public function boot()
{
    Blade::directive('br2nl', function ($string) {
        return "<?php echo preg_replace('/\<br(\s*)?\/?\>/i', \"\n\", $string); ?>";
    });
}

Blade 指令说明: IncludeIf, IncludeWhen, IncludeFirst

当你不确定 Blade 的组件是否存在的时候可以使用一下方法:

仅仅在存在时加载该组件:

@includeIf('partials.header')

仅仅在有权限的时候加载该组件

@includeWhen(auth()->user()->role_id == 1, 'partials.header')

当该组件不存在时,会加载默认组件:

@includeFirst('adminlte.header', 'default.header')

路由

路由组嵌套

路由组可以使用嵌套:

Route::group(['prefix' => 'account', 'as' => 'account.'], function() {
    Route::get('login', 'AccountController@login');
    Route::get('register', 'AccountController@register');

    Route::group(['middleware' => 'auth'], function() {
        Route::get('edit', 'AccountController@edit');
    });
});

子域通配符

你可以通过动态子域名创建相应的路由:

Route::domain('{username}.workspace.com')->group(function () {
    Route::get('user/{id}', function ($username, $id) {
        //
    });
});

What’s behind the routes?

Auth::routes() 下包含了那些路由呢?
你可以在 /vendor/laravel/ui/src/AuthRouteMethods.php 找到:

public function auth()
{
    return function ($options = []) {
        // Authentication Routes...
        $this->get('login', 'Auth\LoginController@showLoginForm')->name('login');
        $this->post('login', 'Auth\LoginController@login');
        $this->post('logout', 'Auth\LoginController@logout')->name('logout');
        // Registration Routes...
        if ($options['register'] ?? true) {
            $this->get('register', 'Auth\RegisterController@showRegistrationForm')->name('register');
            $this->post('register', 'Auth\RegisterController@register');
        }
        // Password Reset Routes...
        if ($options['reset'] ?? true) {
            $this->resetPassword();
        }
        // Password Confirmation Routes...
        if ($options['confirm'] ?? class_exists($this->prependGroupNamespace('Auth\ConfirmPasswordController'))) {
            $this->confirmPassword();
        }
        // Email Verification Routes...
        if ($options['verify'] ?? false) {
            $this->emailVerification();
        }
    };
}

Laravel 7 之前, 存在与文件 /vendor/laravel/framework/src/illuminate/Routing/Router.php

路由注入绑定

你可以通过绑定 user 参数 Route::get('api/users/{user}', function (App\User $user) { … } - 不仅仅可以通过自增 ID 字段筛选,也可以使用 {user}username 字段筛选,只要在模型中这样处理即可:

public function getRouteKeyName() {
    return 'username';
}

快速定义路由控制器

在此之前,你可能这样写:

Route::get('page', 'PageController@action');

上面写法在编辑器中无法从 route 直接跳转到相应的 controller 中,尝试一下方法:

Route::get('page', [\App\Http\Controllers\PageController::class, 'action']);

现在你可以在编辑器中直接点击 PageController 编辑器会根据路径自动找到相关文件(这需要你的编辑器支持,像 phpstorm)。

路由默认值

如果你你不想在路由匹配失败时显示 404 错误页面,你可以通过回调函数设置默认显示内容,这样在路由匹配失败的时候会直接显示你自定义的内容:

Route::group(['middleware' => ['auth'], 'prefix' => 'admin', 'as' => 'admin.'], function () {
    Route::get('/home', 'HomeController@index');
    Route::resource('tasks', 'Admin\TasksController');
});

// 其他路由
Route::fallback(function() {
    return 'Hm, why did you land here somehow?';
});

使用正则验证路由参数

我们可以直接在路由定义时使用 “where” 方法验证路由参数。一个非常典型的情况是在路由的前面加上语言设置, 像 fr/blogen/article/333 这样。我们如何确保这两个首字母不用于语言以外的其他字符串?

routes/web.php:

Route::group([
    'prefix' => '{locale}',
    'where' => ['locale' => '[a-zA-Z]{2}']
], function () {
    Route::get('/', 'HomeController@index');
    Route::get('article/{id}', 'ArticleController@show');
});

全局,访客,用户的限流

你可以通过 throttle:60,1 来限制单位时间内请求某个可连接的此处:

Route::middleware('auth:api', 'throttle:60,1')->group(function () {
    Route::get('/user', function () {
        //
    });
});

你可以针对不同用户组进行不同限制:

// maximum of 10 requests for guests, 60 for authenticated users
Route::middleware('throttle:10|60,1')->group(function () {
    //
});

Also, you can have a DB field users.rate_limit and limit the amount for specific user:

Route::middleware('auth:api', 'throttle:rate_limit,1')->group(function () {
    Route::get('/user', function () {
        //
    });
});

路由的Query params 参数设置

你可以通过 route 方法第二个参数,以数组的形式将query 参数绑定到路由:

Route::get('user/{id}/profile', function ($id) {
    //
})->name('profile');

$url = route('profile', ['id' => 1, 'photos' => 'yes']); // Result: /user/1/profile?photos=yes

验证

图片验证

你可以验证上传图片的尺寸:

['photo' => 'dimensions:max_width=4096,max_height=4096']

自定义验证错误消息

可以自定义现有规则的错误消息,只需要创建相应的语言文件即可 resources/lang/xx/validation.php

'custom' => [
     'email' => [
        'required' => 'We need to know your e-mail address!',
     ],
],

时间验证中的 “now” 和 “yesterday”关键字

你可以通过 before/after 规则来验证日期,并将各种字符串作为参数传递,例如:tomorrow, now, yesterday。 例如:'start_date' => 'after:now'。 它在底层使用 strtotime() 验证。

$rules = [
    'start_date' => 'after:tomorrow',
    'end_date' => 'after:start_date'
];

有条件的验证规则

如果你的验证规则需要同时满足额外的条件,在 FormRequest 方法中定义 withValidator() 添加你的条件即可:

use Illuminate\Validation\Validator;
class StoreBlogCategoryRequest extends FormRequest {
    public function withValidator(Validator $validator) {
        if (auth()->user()->is_admin) {
            $validator->addRules(['some_secret_password' => 'required']);
        }
    }
}

自定义验证消息

通过FormRequestmessages() 方法,你可以自定义验证错误提示信息:

class StoreUserRequest extends FormRequest
{
    public function rules()
    {
        return ['name' => 'required'];
    }

    public function messages()
    {
        return ['name.required' => 'User name should be real name'];
    }
}

验证前置操作

验证前置操作,如果你需要在验证之前对某些字段做一些处理, prepareForValidation() 可以实现该功能:

protected function prepareForValidation()
{
    $this->merge([
        'slug' => Illuminate\Support\Str::slug($this->slug),
    ]);
}

遇到错误时终止验证

默认情况下,laraevl 会在处理完成所有验证规则之后,将错误信息一并返回;当然如果你想在遇到第一个错误的时候就终止继续往下的验证你可以通过添加一下规则: bail

$request->validate([
    'title' => 'bail|required|unique:posts|max:255',
    'body' => 'required',
]);

Policies

一次性检测多个权限

@can Blade 指令可以检测当前用户是否有某个权限,但是当场景复杂点要怎么处理?比如当我在同时拥有多个权限才能进行某个操作的时候? @canany 指令了解下:

@canany(['update', 'view', 'delete'], $post)
    // 当前用户拥有以下其权限: 更新,显示或者删除文章
@elsecanany(['create'], \App\Post::class)
    // 当前用户无法创建文章
@endcanany

集合

不要在集合过滤中使用 NULL

你可以在 Eloquent 中使用 Null 过滤,但是在集合( collection )中,Null 过滤将不会生效:

// 这样可以
$messages = Message::where('read_at is null')->get();

// 这样无法正常返回
$messages = Message::all();
$unread_messages = $messages->where('read_at is null')->count();

// 这样也可以
$unread_messages = $messages->where('read_at', '')->count();

在集合上使用自定义 groupBy 回调

如果你想根据某些条件对结果进行分组处理,并且该条件列并非数据库字段,你可以通过 GroupBy 回调实现。

例如,如果你想按注册日期对用户进行分组,代码如下:

$users = User::all()->groupBy(function($item) {
    return $item->created_at->format('Y-m-d');
});

⚠️ Notice: User::all() 将返回集合类型数据,因此这是在集合上进行的 GroupBy 操作

集合的复用

当你在查询结果上使用 ->all() 或者 ->get() 方法的时候,该操作是针对结果集合进行的操作,不会再额外的进行查询操作。

$users = User::all();
echo 'Max ID: ' . $users->max('id');
echo 'Average age: ' . $users->avg('age');
echo 'Total budget: ' . $users->sum('budget');

鉴权

你链接 Auth::once() 吗?

Auth::once() 可以用于构建无状态请求,他不会产生任何 cookie信息,这很有利于接口的开发:

if (Auth::once($credentials)) {
    //
}

更新密码同时更新用户 token

在更新用户密码的同时更新用户 token 很有必要:

模型:

public function setPasswordAttribute($value)
{
    $this->attributes['password'] = $value;
    $this->attributes['api_token'] = Str::random(100);
}

邮件

将测试邮件存储到 laravel.log

开发过程中,你可能需要测试邮件发送,但是你有不希望测试邮件真正发送到客户邮箱,这时候你可以通过配置 .env 参数 MAIL_DRIVER=log 这样,邮件将会以文本的形式存储到 storage/logs/laravel.log ,而不会真正发送出去。

邮件预览

如果你使用 Mailables 为发送邮件提供服务,那么你可以直接在浏览器中浏览邮件预览,而不必真正的发送:

Route::get('/mailable', function () {
    $invoice = App\Invoice::find(1);
    return new App\Mail\InvoicePaid($invoice);
});

Laravel 通知的默认主题(subject)

如果你在使用 toMail() 发送邮件通知的时候,未指定相关主题(subject)laravel 提供了默认参数可以使用:

因此,你只需要有:

class UserRegistrationEmail extends Notification {
    //
}

然后你就可以在注册完成收到一封注册邮件提醒。

发送通知

你可以通过 $user->notify() 发送通知给特定用户,你也可以通过 Notification::route() 发送给任何其他需要通知的地方:

Notification::route('mail', 'taylor@example.com')
        ->route('nexmo', '5555555555')
        ->route('slack', 'https://hooks.slack.com/services/...')
        ->notify(new InvoicePaid($invoice));

Artisan

Artisan 命令参数

当我们创建我们的 Artisan 命令的时候,可以通过 $this->confirm(), $this->anticipate(), $this->choice() 等方法询问并要求输入参数:

// 确认框
if ($this->confirm('Do you wish to continue?')) {
    //
}

// 附加可选项
$name = $this->anticipate('What is your name?', ['Taylor', 'Dayle']);

// 附加默认值
$name = $this->choice('What is your name?', ['Taylor', 'Dayle'], $defaultIndex);

维护模式

页面维护模式实现如下:

php artisan down

执行上面命令后,再访问站点的时候会得到 503 错误信息。

你也可以通过提供参数实现而外的效果:

  • message 参数指定显示信息
  • retry 参数设定页面重载时间
  • allow 允许访问的 IP
    php artisan down --message="Upgrading Database" --retry=60 --allow=127.0.0.1

当维护完成,运行一下命令上线吧!

php artisan up

数据工厂

Factory 的回调方法

有时候,你某些数据的插入/修改需要基于其他数据的完成,这时你可以通过回调方法实现,例子如下:

$factory->afterCreating(App\User::class, function ($user, $faker) {
    $user->accounts()->save(factory(App\Account::class)->make());
});

通过 Seeds/Factories 生成图片

Faker能生成的不仅仅是文本,还可以生成指定大小的图像:

$factory->define(User::class, function (Faker $faker) {
    return [
        'name' => $faker->name,
        'email' => $faker->unique()->safeEmail,
        'email_verified_at' => now(),
        'password' => bcrypt('password'),
        'remember_token' => Str::random(10),
        'avatar' => $faker->image(storage_path('images'), 50, 50)
    ];
});

日志和调试

给日志记录传递参数

你可以通过 Log::info() 来记录日志,或者 info() 快捷方法可以实现同样的效果。

Log::info('User failed to login.', ['id' => $user->id]);

更方便的方法 DD

你可以直接通过在查询结果之后的 ->dd() 操作来打印结果。

// Instead of
$users = User::where('name', 'Taylor')->get();
dd($users);
// Do this
$users = User::where('name', 'Taylor')->get()->dd();
本文中的所有译文仅用于学习和交流目的,转载请务必注明文章译者、出处、和本文链接
我们的翻译工作遵照 CC 协议,如果我们的工作有侵犯到您的权益,请及时联系我们。

原文地址:https://www.reddit.com/r/laravel/comment...

译文地址:https://learnku.com/laravel/t/45370

本帖已被设为精华帖!
本文为协同翻译文章,如您发现瑕疵请点击「改进」按钮提交优化建议
《L02 从零构建论坛系统》
以构建论坛项目 LaraBBS 为线索,展开对 Laravel 框架的全面学习。应用程序架构思路贴近 Laravel 框架的设计哲学。
《G01 Go 实战入门》
从零开始带你一步步开发一个 Go 博客项目,让你在最短的时间内学会使用 Go 进行编码。项目结构很大程度上参考了 Laravel。
讨论数量: 12
Marrigan

@c

Member::query()->with('groupInfo:id,name')->Limit('10')->get()->toArray();

file

3年前 评论
cwj 3年前

一个人翻译的内容那么多?能稍微分段下吗?

3年前 评论

@summer 大佬能不能重新分下段啊 似乎自动分段功能有点小问题啊

3年前 评论

多谢分享!!多谢分享!!

3年前 评论

那个with函数,指定列有问题,我怎么查不出来,用冒号选择的话,我查出来的数据是空的

3年前 评论
Marrigan (楼主) 3年前

非常实用,又get新技能了 :+1:

3年前 评论

666。。。mark一下慢慢看~~

3年前 评论

牛皮啊,这么多小技巧

3年前 评论

收藏一波,感谢分享

3年前 评论

全部看完了。谢谢

3年前 评论
Jyunwaa

好东西,收藏!感谢楼主! :kissing_heart:

3年前 评论

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!