[转+]深入探讨 Service Provider

原文地址 : 深入探討 Service Provider
Service Provider 是 Laravel 管理 Package 的核心技术
Laravel 提供了 service container 让我们方便实现 依赖注入,而service provider则是我们注册及管理 service container 的地方。
事实上 Laravel 内部所有的核心组件都是使用 service provider 统一管理,除了可以用来管理 package 外,也可以用来管理自己写的物件。

阅读更多

Laravel (Code Review) - 01

1. 带标签的缓存是无法不带标签删除的

1
2
3
4
5
6
7
8
9
#laravel 5.5
// 标签内部的数据外部是获取不到的
\Cache::tags('test')->remember('abc', SysConfig::HALF_DAY_MIN, function () {
return 5;
});
$a = \Cache::get('abc');
\Cache::forget('abc');
$b = \Cache::get('abc');
$this->assertEquals($a, $b);

2. 创建的数据和保存的数据不符合

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
# 创建前
$input = [
"mobile" => "17081297193"
"password" => ""
"type" => "user"
"is_enable" => 1
];
$user = PamAccount::create($input);
$user = [
"mobile" => "18056346460"
"password" => ""
"type" => "user"
"is_enable" => 1
"updated_at" => "2018-07-26 22:07:30"
"created_at" => "2018-07-26 22:07:30"
"id" => 96
];
# 从数据库查询
$user = \User::find($user->id);
$user = [
"id" => 96
"mobile" => "18056346460"
"parent_id" => 0
"password" => ""
"type" => "user"
"is_enable" => 1
"login_times" => 0
"reg_platform" => "ios"
"created_at" => "2018-07-26 22:07:30"
"updated_at" => "2018-07-26 22:07:30"
]

I believe this is designed this way to limit number of SQL queries. If you need to get actual data saved in the database, you need to obtain this record explicitely, just the way you did :)
INSERT query doesn’t return actual row.

3. 事件中绝对不要返回 fasle

因为在 PHP 5.5 中 这样说明

Stopping The Propagation Of An Event
Sometimes, you may wish to stop the propagation of an event to other listeners. You may do so by returning false from your listener’s handle method.


4. 控制器方法

1
2
3
4
5
index()                  # 列表
establish($id = null) # 创建 / 编辑
update() # 更新 / 批量更新
delete() # 删除, 存在的订单不是彻底删除使用 delete
destroy() # 销毁(彻底删除)

5. 路由写法

路由器第二个参数不可以传 key

1
2
3
4
# 传值 bad
route('dsk_base_area.establish', ['parent_id' => $item['areaid']])
# 不传值 good
route('dsk_base_area.establish', [$item->areaid]])

这两个哪个写起来更简洁呢?
因为使用 route 的时候接收到的参数在控制器传参数进行获取
public function establish($parent_id) 这种方法才能够接收到数据的.
ps: 使用 $request->input('parent_id') 根本获取不到东西

6. 使用对象和对象的错误提示

1
2
3
4
5
6
# 使用对象的好处
route('dsk_base_area.create', [$item['areaid']]) # 如果不存在字段, 则报 undefined index 错误
route('dsk_base_area.create', [$item->area_id]) # 这里不报错的.
# 使用映射过的对象的好处是容易识记
route('dsk_base_area.create', [$item->areaid]) # 这里不报错的.
route('dsk_base_area.create', [$item->area_id]) # 使用映射过的字段更便于记忆, 减少浏览器的 `typo` 错误

7. 合理使用模型提供的方法

1
2
3
4
5
6
7
8
9
10
11
# 取一条
UserMessage::where('item_id', $item_id)->select("*")->first();
UserMessage::where('item_id', $item_id)->first();
UserMessage::find($item_id);
# 取单个
UserMessage::where('item_id', $item_id)->lists('username')->first();
UserMessage::where('item_id', $item_id)->value('username');
# 模型方法
$item = UserMessage::find($item_id);
$item->num += 1;
$item->save();

8. Form 使用 post 方法提交可以不填写 ‘method’

1
2
3
4
5
6
# 这里来自于表单提交
@if (isset($item))
{!! Form::model($item,['route' => ['dsk_adv_item.edit', $item->id], 'id' => 'form_ad_place','method' => 'post']) !!}
@else
{!! Form::open(['route' => 'dsk_adv_item.create','id' => 'form_ad_place','enctype'=>'multipart/form-data']) !!}
@endif

优化后

1
2
3
4
5
@if (isset($item))
{!! Form::model($item,['route' => ['dsk_adv_item.edit', $item->id], 'id' => 'form_ad_place']) !!}
@else
{!! Form::open(['route' => 'dsk_adv_item.create','id' => 'form_ad_place']) !!}
@endif

9. 对于编辑/创建使用同一个模版

编辑和创建来说, 我们使用同一个模版, 模板的名字应该命名为 establish.blade.php

10. [批量]更新使用 update

因为这里的更新就是批量的, 并且使用的方式不是更新一个, 所以这里不使用 batchUpdate

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class AdPlaceController{
# bad
public function batchUpdate() {
// ...
}
# good
public function update() {
$update = \Input::input('update');
foreach ($update as $id => $item) {
AdvPlace::where('id', $id)->update($item);
}
return site_end('success', '更新成功');
}
}

11. 取消不需要的导入

1
2
3
4
5
6
use Order\Action\Hunter;
use Order\Models\Filters\OrderHunterFilter;
use Order\Models\OrderHunter;
use Order\Models\Resources\EarnResource;
use Site\Tests\Base\SiteTestCase;
use System\Models\PamAccount;

12. 类内部调用使用 self (self_accessor)

1
2
3
4
5
6
7
8
/**
* @param int $account_id 用户ID
* @return StatisticsRangeFilter
*/
public function account($account_id): self
{
return $this->where('account_id', $account_id);
}

13. Laravel 中 Carbon 对象可以直接进行时间传递

1
2
3
4
5
6
7
// deprecated
$rePublishTimer = Carbon::now()->subMinutes($interval)->toDateTimeString();
$accountIds = CustomHunter::where('updated_at', '<', $rePublishTimer)
distinct()->pluck('account_id');
// suggest
$accountIds = CustomHunter::where('updated_at', '<', Carbon::now()->subMinutes($interval))
distinct()->pluck('account_id');

14. 数据获取

获取数据应当采用最简单的形式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// bad : new 模型, 没有考虑逻辑
if ((new \System\Models\PamBind)->where('qq_key', $openId)->exists()) {
return $this->setError('已经绑定过');
}
PamBind::create([
'account_id' => $this->pam->id,
'qq_key' => $openId,
]);
// good : 优化后的代码
if (PamBind::where('qq_key', $openId)->exists()) {
return $this->setError('已经被绑定过');
}
PamBind::updateOrCreate([
'account_id' => $this->pam->id,
], [
'qq_key' => $openId,
]);

15.初始化异常处理

获取数据需要做异常处理, 否则会出现无查询结果

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// bad : 错误信息
public function init($id)
{
$this->appVersion = AppVersion::findOrFail($id);
$this->id = $this->appVersion->id;
return $this;
}
// good : 正确代码
public function init($id)
{
try {
$this->appVersion = AppVersion::findOrFail($id);
$this->id = $this->appVersion->id;
return true;
} catch (\Exception $e) {
return $this->setError($e->getMessage());
}
}

16. 队列中运行延迟时候需要确保存在 delay() 方法

使用 Illuminate\Bus\Queueable 这个 Trait,
.env 中的 QUEUE_DRIVER 能够是 sync

17. empty()Collection::empty() 方法不同

这段代码来自于清除未支付的中间订单

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# 原始代码
$list = FinancePayTransfer::where('status', FinancePayTransfer::STATUS_UNPAY)
->where('updated_at','<', Carbon::now()->subWeek()->subMinutes(30)->toDateTimeString())->select(['id'])->take(100)->get();
if ($list) {
foreach ($list as $k => $rs) {
FinancePayTransfer::where('id', $rs->id)->delete();
}
}
# 优化后代码
# [优化] Laravel 中可以直接传入对象进行操作返回, 所以这里不必再进行转换
$dayEnd = Carbon::now()->subWeek();
/** @var Collection $list */
$list = FinancePayTransfer::where('status', FinancePayTransfer::STATUS_UNPAY)
->where('updated_at','<', $dayEnd)
->take(100)->lists('id');
# [bug] 如果 $list 为空, 条目值为空, 因为$list 是对象, 所以 if ($list) 会一直是 true
# [优化] 减少数据库请求次数,使用 whereIn 方法替代数据库的循环删除方法.
if (!$list->isEmpty()) {
FinancePayTransfer::whereIn('id', $list)->delete();
}

18. 类名和文件名大小写匹配

如果不匹配会造成类在 unix 平台中无法匹配

19. 类方法名使用正确的方法名称

orderBy 是正确写法, 不是 OrderBy

1
2
3
4
5
6
# bad
AdvPlace::OrderBy('list_order', 'asc')->lists('title', 'id');
$DB->orderby('id', 'desc');
# good
AdvPlace::orderBy('list_order', 'asc')->lists('title', 'id');
$DB->orderBy('id', 'desc');

20. 生成 Laravel ide-helper 用来提示函数

使用以下命令可以生成代码提示

1
php artisan ide-helper:generate

21 使用 Map 会掉 el### 3.1 使用 Map 会坑

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
38
39
40
41
42
43
44
45
46
47
$items   = [
[
'id' => 'a',
'type' => 'pc',
],
[
'id' => 'b',
'type' => 'web',
],
[
'id' => 'c',
'type' => 'pc',
],
];
$collect = collect($items)
->where('type', 'pc')
->map(function ($item) {
return $item;
});
/**
这里使用 where 之后是存在 Key 的
0 => array:2 [
"id" => "a"
"type" => "pc"
]
2 => array:2 [
"id" => "c"
"type" => "pc"
]
*/
// 解决方案
$data = collect();
$collect = collect($items)
->where('type', 'pc')
->each(function ($item) use ($data) {
$data->push($item);
});
/*
0 => array:2 [
"id" => "a"
"type" => "pc"
]
1 => array:2 [
"id" => "c"
"type" => "pc"
]
*/

22 使用 collect 转换成数组

toArray 递归转换成数组, 支持 toArray 方法的可以递归转换成数组

1
2
3
4
5
6
7
8
// collect 内部可以转换成数组
$collect = collect([1, 2, 3, 4]);
$colCollect = collect([$collect, $collect, $collect]);
$this->assertIsArray($colCollect->toArray()[0]);
// collect 不支持 toArray 模式的以数组展示
$std = new stdClass();
$colStd = collect([$std, $std, $std]);
$this->assertIsObject($colStd->toArray()[0]);

原文地址 : Laravel (Code Review) - 01
本站是作者语雀文档的镜像站, 如对文章有任何疑问请移步语雀进行 提问

Laravel 5.5 升级到 6.0 记录

1. 可以选择缓存使用 phpredis/predis

phpredis : 指的是使用 pecl 安装的 php 扩展 redis
predis   : 指的是 github 上的 predis/predis 的包
Laravel 推荐使用 phpredis 来代替 predis。原因是 predis 包很长时间没有更新
所以要记得先安装 phpredis, 然后在 config/app.php 中去掉 Redis 别名
Mac 安装

1
2
3
4
5
# 这里需要将当前版本设置为主版本才可以, 如果不是主版本则安装会太费劲
$ brew link --force php@{version}
$ pecl install igbinary
$ pecl install redis
$ brew services restart php@7.2

其他平台
应该是直接安装即可(未测试)
项目中在考虑兼容的情况下, 使用 predis, 暂时不启用 phpredis.

2. Unable to create configured logger. Using emergency logger

在 5.6 之后已经将配置文件独立 config/logging.php, 将这个文件放置到指定目录, 然后 app.php 移除日志的配置 Logging Configuration

3. Call to undefined method Illuminate\Events\Dispatcher::fire()

在 (5.8 升级指南)(https://laravel.com/docs/5.8/upgrade) 指出,
Likelihood Of Impact: Low

1
2
deprecated and removed
Events The fire Method

使用 dispatch 方法替代 You should use the dispatch method instead.

4. Class ‘Illuminate\Support\Facades\Input’ not found

使用 Request 替代 Input
Input no longer exists. Either use the Request facade or alias that instead of Input.

5. str_contains 等 helper 函数

这些函数均需要替换成静态函数方法 Str::contains
下面是 辅助函数列表
5.1 辅助函数列表


原文地址 : Laravel 5.5 升级到 6.0 记录
本站是作者语雀文档的镜像站, 如对文章有任何疑问请移步语雀进行 提问

Laravel-Excel 3.0 文档

基本用法

最简单的导出方法是创建一个自定义的导出类, 这里我们使用发票导出作为示例.
App/Exports 下创建一个 InvoicesExport

1
2
3
4
5
6
7
8
9
namespace App\Exports;
use Maatwebsite\Excel\Concerns\FromCollection;
class InvoicesExport implements FromCollection
{
public function collection()
{
return Invoice::all();
}
}

在控制器中你可以使用如下方式来下载

1
2
3
4
public function export() 
{
return Excel::download(new InvoicesExport, 'invoices.xlsx');
}

或者存储在 s3 磁盘中

1
2
3
4
public function storeExcel() 
{
return Excel::store(new InvoicesExport, 'invoices.xlsx', 's3');
}

依赖注入

如果你的导出需要依赖, 你可以注入导出类

1
2
3
4
5
6
7
8
9
10
11
12
13
namespace App\Exports;
use Maatwebsite\Excel\Concerns\FromCollection;
class InvoicesExport implements FromCollection
{
public function __construct(InvoicesRepository $invoices)
{
$this->invoices = $invoices;
}
public function collection()
{
return $this->invoices->all();
}
}
1
2
3
4
public function export(Excel $excel, InvoicesExport $export) 
{
return $excel->download($export, 'invoices.xlsx');
}

严格的 null 对比

如果你希望 0 在 excel 单元格中就是显示 0, 而不是显示 null(空单元格), 你可以使用 WithStrictNullComparison

1
2
3
4
5
6
7
8
9
10
11
12
13
14
namespace App\Exports;
use Maatwebsite\Excel\Concerns\FromCollection;
use Maatwebsite\Excel\Concerns\WithStrictNullComparison;
class InvoicesExport implements FromCollection, WithStrictNullComparison
{
public function __construct(InvoicesRepository $invoices)
{
$this->invoices = $invoices;
}
public function collection()
{
return $this->invoices->all();
}
}

Collection 全局定义/宏

这个包提供了 laravel collection 的一些额外的方法(宏) 来简单的下载或者是存储到 excel

把 collection 作为 Excel 下载

1
2
3
4
5
(new Collection([[1, 2, 3], [1, 2, 3]]))->downloadExcel(
$filePath,
$writerType = null,
$headings = false
)

在磁盘上存储 collection

1
2
3
4
5
6
(new Collection([[1, 2, 3], [1, 2, 3]]))->storeExcel(
$filePath,
$disk = null,
$writerType = null,
$headings = false
)

在磁盘上存储导出

导出可以存储到任何 Laravel 支持的 文件系统

1
2
3
4
5
6
7
8
9
public function storeExcel() 
{
// Store on default disk
Excel::store(new InvoicesExport(2018), 'invoices.xlsx');
// Store on a different disk (e.g. s3)
Excel::store(new InvoicesExport(2018), 'invoices.xlsx', 's3');
// Store on a different disk with a defined writer type.
Excel::store(new InvoicesExport(2018), 'invoices.xlsx', 's3', Excel::XLSX);
}

Exportables / 可导出的

在之前的例子中, 我们使用 Excel::download 这个 facade 来开始一个导出.
Laravel-Excel 同样支持  Maatwebsite\Excel\Concerns\Exportable trait, 来让一个类可以直接导出, 当然, 这个类里边需要有 collection 方法.

1
2
3
4
5
6
7
8
9
10
11
namespace App\Exports;
use Maatwebsite\Excel\Concerns\FromCollection;
use Maatwebsite\Excel\Concerns\Exportable;
class InvoicesExport implements FromCollection
{
use Exportable;
public function collection()
{
return Invoice::all();
}
}

我们可以不通过 facade 直接进行类的下载

1
return (new InvoicesExport)->download('invoices.xlsx');

或者是存储到磁盘上.

1
return (new InvoicesExport)->store('invoices.xlsx', 's3');

Responsable / 可响应的

之前的例子可以做的简单一点, 例如我们添加 Laravel 的 Responsable 到导出类中

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
namespace App\Exports;
use Illuminate\Contracts\Support\Responsable;
use Maatwebsite\Excel\Concerns\FromCollection;
use Maatwebsite\Excel\Concerns\Exportable;
class InvoicesExport implements FromCollection, Responsable
{
use Exportable;
/**
* It's required to define the fileName within
* the export class when making use of Responsable.
*/
private $fileName = 'invoices.xlsx';
public function collection()
{
return Invoice::all();
}
}

你可以更简单的返回导出类,但是不需要调用 ->download() 方法.

1
return new InvoicesExport();

From Query / 从查询输出

在之前的例子中, 我们在导出类中进行查询, 当然这个解决方案可以用在小的导出类中. 对于更大一点数据的导出类可能造成比较大的性能开销.
通过使用 FromQuery 关系, 我们可以通过预查询一个导出, 这个场景实现的原理是查询可以分块执行.
InvoicesExport 类中,添加 FromQuery 关系, 并且添加一个查询, 并且确保不要使用 ->get() 来获取到数据!.

1
2
3
4
5
6
7
8
9
10
11
namespace App\Exports;
use Maatwebsite\Excel\Concerns\FromQuery;
use Maatwebsite\Excel\Concerns\Exportable;
class InvoicesExport implements FromQuery
{
use Exportable;
public function query()
{
return Invoice::query();
}
}

我们可以通过同样的方式来下载

1
return (new InvoicesExport)->download('invoices.xlsx');

自定义查询

这种方式可以通过自定义的参数来进行查询. 简单的作为依赖项传入导出类即可.

作为构造器惨呼

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
namespace App\Exports;
use Maatwebsite\Excel\Concerns\FromQuery;
use Maatwebsite\Excel\Concerns\Exportable;
class InvoicesExport implements FromQuery
{
use Exportable;
public function __construct(int $year)
{
$this->year = $year;
}
public function query()
{
return Invoice::query()->whereYear('created_at', $this->year);
}
}

$year 参数可以传递给导出类.

1
return (new InvoicesExport(2018))->download('invoices.xlsx');

作为设置项

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
namespace App\Exports;
use Maatwebsite\Excel\Concerns\FromQuery;
use Maatwebsite\Excel\Concerns\Exportable;
class InvoicesExport implements FromQuery
{
use Exportable;
public function forYear(int $year)
{
$this->year = $year;
return $this;
}
public function query()
{
return Invoice::query()->whereYear('created_at', $this->year);
}
}

我们可以通过 forYear 方法来调整年份.

1
return (new InvoicesExport)->forYear(2018)->download('invoices.xlsx');

通过视图

我们可以通过 blade 视图来创建导出. 通过使用 FromView 关系.

1
2
3
4
5
6
7
8
9
10
11
12
namespace App\Exports;
use Illuminate\Contracts\View\View;
use Maatwebsite\Excel\Concerns\FromView;
class InvoicesExport implements FromView
{
public function view(): View
{
return view('exports.invoices', [
'invoices' => Invoice::all()
]);
}
}

这种方式会导出一个 Html 表格到 Excel 单元表, 例如 users.blade.php:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<table>
<thead>
<tr>
<th>Name</th>
<th>Email</th>
</tr>
</thead>
<tbody>
@foreach($users as $user)
<tr>
<td>{{ $user->name }}</td>
<td>{{ $user->email }}</td>
</tr>
@endforeach
</tbody>
</table>

队列

如果你处理更大数据量的数据, 很明智的方法就是使用队列来运行.
例如下边的导出类:

1
2
3
4
5
6
7
8
9
10
11
namespace App\Exports;
use Maatwebsite\Excel\Concerns\Exportable;
use Maatwebsite\Excel\Concerns\FromQuery;
class InvoicesExport implements FromQuery
{
use Exportable;
public function query()
{
return Invoice::query();
}
}

我们只需要调用一个 ->queue() 方法即可.

1
return (new InvoicesExport)->queue('invoices.xlsx');

后台处理这些查询的方式是通过多任务/多切割的方式来进行. 这些任务使用正确的顺序来执行. 并且保证之前的查询都是正确的.

另一种方式的队列实现

你可以将导出作为一个可以扔到队列中的实现(利用 Laravel), 可以使用 ShouldQueue 约束.

1
2
3
4
5
6
7
8
9
10
11
12
namespace App\Exports;
use Maatwebsite\Excel\Concerns\Exportable;
use Maatwebsite\Excel\Concerns\FromQuery;
use Illuminate\Contracts\Queue\ShouldQueue;
class InvoicesExport implements FromQuery, ShouldQueue
{
use Exportable;
public function query()
{
return Invoice::query();
}
}

在控制器中可以调用普通的 ->store() 方法. 基于 ShouldQueue, 通过 laravel 的队列方式来实现队列处理. [ps:你需要首先自行配置队列]

1
return (new InvoicesExport)->store('invoices.xlsx');

追加任务 / jobs

queue() 方法返回一个 Laravel 的  PendingDispatch 实例, 这意味着你可以把其他的任务串联起来, 仅仅当前一个任务执行成功的时候, 后续的任务才能够被执行.

1
2
3
return (new InvoicesExport)->queue('invoices.xlsx')->chain([
new NotifyUserOfCompletedExport(request()->user()),
]);
1
2
3
4
5
6
7
8
9
10
11
namespace App\Jobs;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
class InvoiceExportCompletedJob implements ShouldQueue
{
use Queueable;
public function handle()
{
// Do something.
}
}

自定义队列

PendingDispatch 返回的时候, 我们可以改变我们使用的队列.

1
return (new InvoicesExport)->queue('invoices.xlsx')->allOnQueue('exports');

多单元表

为了能够让导出支持多单元表, 需要使用 WithMultipleSheets 关系来实现. 这个 sheets() 方法需要返回一个单元表数组.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
namespace App\Exports;
use Maatwebsite\Excel\Concerns\Exportable;
use Maatwebsite\Excel\Concerns\WithMultipleSheets;
class InvoicesExport implements WithMultipleSheets
{
use Exportable;
protected $year;
public function __construct(int $year)
{
$this->year = $year;
}
/**
* @return array
*/
public function sheets(): array
{
$sheets = [];
for ($month = 1; $month <= 12; $month++) {
$sheets[] = new InvoicesPerMonthSheet($this->year, $month);
}
return $sheets;
}
}

这个 InvoicesPerMonthSheet 可以实现多种关系. 例如 FromQuery, FromCollection, …

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
namespace App\Exports;
use Maatwebsite\Excel\Concerns\FromQuery;
use Maatwebsite\Excel\Concerns\WithTitle;
class InvoicesPerMonthSheet implements FromQuery, WithTitle
{
private $month;
private $year;
public function __construct(int $year, int $month)
{
$this->month = $month;
$this->year = $year;
}
/**
* @return Builder
*/
public function query()
{
return Invoice
::query()
->whereYear('created_at', $this->year)
->whereMonth('created_at', $this->month);
}
/**
* @return string
*/
public function title(): string
{
return 'Month ' . $this->month;
}
}

以下可以下载 2018 年的所有的发票, 它包含 12 单元表来显示每个月的数据.

1
2
3
4
public function download() 
{
return (new InvoicesExport(2018))->download('invoices.xlsx');
}

数据遍历

遍历行

通过添加  WithMapping, 你可以遍历添加到单元行中的每一条数据然后并返回.
这种方法你可以控制每一列的数据, 假设你使用 Eloquent 的 query builder.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
use Maatwebsite\Excel\Concerns\FromQuery;
use Maatwebsite\Excel\Concerns\WithMapping;
class InvoicesExport implements FromQuery, WithMapping
{
/**
* @var Invoice $invoice
*/
public function map($invoice): array
{
return [
$invoice->invoice_number,
Date::dateTimeToExcel($invoice->created_at),
];
}
}

添加表头

可以通过添加一个  WithHeadings 约束来实现. 表头会添加到所有数据的第一行的位置上.

1
2
3
4
5
6
7
8
9
10
11
use Maatwebsite\Excel\Concerns\FromQuery;
use Maatwebsite\Excel\Concerns\WithHeadings;
class InvoicesExport implements FromQuery, WithHeadings
public function headings(): array
{
return [
'#',
'Date',
];
}
}

格式化列

你可以格式化整列, 通过添加 WithColumnFormatting, 如果你想更多范围的自定义. 推荐使用 AfterSheet 事件来直接和地城的 Worksheet 类进行交互.

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
namespace App\Exports;
use PhpOffice\PhpSpreadsheet\Shared\Date;
use PhpOffice\PhpSpreadsheet\Style\NumberFormat;
use Maatwebsite\Excel\Concerns\WithColumnFormatting;
use Maatwebsite\Excel\Concerns\WithMapping;
class InvoicesExport implements WithColumnFormatting, WithMapping
{
public function map($invoice): array
{
return [
$invoice->invoice_number,
Date::dateTimeToExcel($invoice->created_at),
$invoice->total
];
}
/**
* @return array
*/
public function columnFormats(): array
{
return [
'B' => NumberFormat::FORMAT_DATE_DDMMYYYY,
'C' => NumberFormat::FORMAT_CURRENCY_EUR_SIMPLE,
];
}
}

日期

当操作日期的时候. 推荐使用 \PhpOffice\PhpSpreadsheet\Shared\Date::dateTimeToExcel() 来正确的解析你的日期数据.

导出关系

Interface Explanation
Maatwebsite\Excel\Concerns\FromCollection Use a Laravel Collection to populate the export.
Maatwebsite\Excel\Concerns\FromQuery Use an Eloquent query to populate the export.
Maatwebsite\Excel\Concerns\FromView Use a (Blade) view to to populate the export.
Maatwebsite\Excel\Concerns\WithTitle Set the Workbook or Worksheet title.
Maatwebsite\Excel\Concerns\WithHeadings Prepend a heading row.
Maatwebsite\Excel\Concerns\WithMapping Format the row before it’s written to the file.
Maatwebsite\Excel\Concerns\WithColumnFormatting Format certain columns.
Maatwebsite\Excel\Concerns\WithMultipleSheets Enable multi-sheet support. Each sheet can have its own concerns (except this one).
Maatwebsite\Excel\Concerns\ShouldAutoSize Auto-size the columns in the worksheet.
Maatwebsite\Excel\Concerns\WithStrictNullComparison Uses strict comparisions when testing cells for null value.
Maatwebsite\Excel\Concerns\WithEvents Register events to hook into the PhpSpreadsheet process.

Traits

Trait Explanation
Maatwebsite\Excel\Concerns\Exportable Add download/store abilities right on the export class itself.
Maatwebsite\Excel\Concerns\RegistersEventListeners Auto-register the available event listeners.

扩展

事件

导出过程有一些事件,你可以利用这些事件与底层类进行交互,以向导出添加自定义行为。
通过使用事件,您可以连接到父包。如果你需要完全控制导出,则不需要使用诸如 “query” 或者 “view” 之类的便利方法。
事件将通过添加 WithEvents 关注来激活。在 registerEvents 方法中,你必须返回一系列事件。Key 是事件的完全限定名(FQN),Value 是可调用的事件监听器。这可以是一个闭包、可调用的数组 或 invokable 类。

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
namespace App\Exports;
use Maatwebsite\Excel\Concerns\WithEvents;
use Maatwebsite\Excel\Events\BeforeExport;
use Maatwebsite\Excel\Events\BeforeWriting;
use Maatwebsite\Excel\Events\BeforeSheet;
class InvoicesExport implements WithEvents
{
/**
* @return array
*/
public function registerEvents(): array
{
return [
// Handle by a closure.
BeforeExport::class => function(BeforeExport $event) {
$event->writer->getProperties()->setCreator('Patrick');
},
// Array callable, refering to a static method.
BeforeWriting::class => [self::class, 'beforeWriting'],
// Using a class with an __invoke method.
BeforeSheet::class => new BeforeSheetHandler()
];
}
public static function beforeWriting(BeforeWriting $event)
{
//
}
}

请注意,使用 Closure 将不可能与队列导出合并,因为PHP不能序列化闭包。在这些情况下,最好使用 RegistersEventListeners 特性。

自动注册事件监听器

通过使用 RegistersEventListeners trait ,你可以自动注册事件监听器,而不需要使用 registerEvents 。只有在创建方法时,侦听器才会被注册。

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
namespace App\Exports;
use Maatwebsite\Excel\Concerns\WithEvents;
use Maatwebsite\Excel\Concerns\RegistersEventListeners;
use Maatwebsite\Excel\Events\BeforeExport;
use Maatwebsite\Excel\Events\BeforeWriting;
use Maatwebsite\Excel\Events\BeforeSheet;
use Maatwebsite\Excel\Events\AfterSheet;
class InvoicesExport implements WithEvents
{
use Exportable, RegistersEventListeners;
public static function beforeExport(BeforeExport $event)
{
//
}
public static function beforeWriting(BeforeWriting $event)
{
//
}
public static function beforeSheet(BeforeSheet $event)
{
//
}
public static function afterSheet(AfterSheet $event)
{
//
}
}

可用的事件

Event name Payload Explanation
Maatwebsite\Excel\Events\BeforeExport $event->writer : Writer Event gets raised at the start of the process.
Maatwebsite\Excel\Events\BeforeWriting $event->writer : Writer Event gets raised before the download/store starts.
Maatwebsite\Excel\Events\BeforeSheet $event->sheet : Sheet Event gets raised just after the sheet is created.
Maatwebsite\Excel\Events\AfterSheet $event->sheet : Sheet Event gets raised at the end of the sheet process.

WriterSheet 都是可以进行宏操作的,这意味着它可以很容易地扩展以满足你的需要。Writer 和 Sheet都有一个 ->getDelegate() 方法,它返回底层的PhpSpreadsheet 类。这将允许你为 PhpSpreadsheets 方法添加快捷方法,而这个方法在这个包中是不可用的。

Writer / 写入

1
2
3
4
use \Maatwebsite\Excel\Writer;
Writer::macro('setCreator', function (Writer $writer, string $creator) {
$writer->getDelegate()->getProperties()->setCreator($creator);
});

Sheet / 单元表

1
2
3
4
use \Maatwebsite\Excel\Sheet;
Sheet::macro('setOrientation', function (Sheet $sheet, $orientation) {
$sheet->getDelegate()->getPageSetup()->setOrientation($orientation);
});

你还可以为样式单元添加一些快捷方法。你可以自由使用这个宏,或者创造你自己的语法!

1
2
3
4
use \Maatwebsite\Excel\Sheet;
Sheet::macro('styleCells', function (Sheet $sheet, string $cellRange, array style) {
$sheet->getDelegate()->getStyle($cellRange)->applyFromArray($style);
});

以上例子可作:

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
namespace App\Exports;
use Maatwebsite\Excel\Concerns\WithEvents;
use Maatwebsite\Excel\Events\BeforeExport;
use Maatwebsite\Excel\Events\AfterSheet;
class InvoicesExport implements WithEvents
{
/**
* @return array
*/
public function registerEvents(): array
{
return [
BeforeExport::class => function(BeforeExport $event) {
$event->writer->setCreator('Patrick');
},
AfterSheet::class => function(AfterSheet $event) {
$event->sheet->setOrientation(\PhpOffice\PhpSpreadsheet\Worksheet\PageSetup::ORIENTATION_LANDSCAPE);
$event->sheet->styleCells(
'B2:G8',
[
'borders' => [
'outline' => [
'borderStyle' => \PhpOffice\PhpSpreadsheet\Style\Border::BORDER_THICK,
'color' => ['argb' => 'FFFF0000'],
],
]
]
);
},
];
}
}

对于 PhpSpreadsheet 方法, 可查看文档: https://phpspreadsheet.readthedocs.io/

测试 / Testing

The Excel facade can be used to swap the exporter to a fake.

测试下载

1
2
3
4
5
6
7
8
9
10
11
12
13
/**
* @test
*/
public function user_can_download_invoices_export()
{
Excel::fake();
$this->actingAs($this->givenUser())
->get('/invoices/download/xlsx');
Excel::assertDownloaded('filename.xlsx', function(InvoicesExport $export) {
// Assert that the correct export is downloaded.
return $export->collection()->contains('#2018-01');
});
}

测试存储导出

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
/**
* @test
*/
public function user_can_store_invoices_export()
{
Excel::fake();
$this->actingAs($this->givenUser())
->get('/invoices/store/xlsx');
Excel::assertStored('filename.xlsx', 'diskName');
Excel::assertStored('filename.xlsx', 'diskName', function(InvoicesExport $export) {
return true;
});
// When passing the callback as 2nd param, the disk will be the default disk.
Excel::assertStored('filename.xlsx', function(InvoicesExport $export) {
return true;
});
}

测试队列导出

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
/**
* @test
*/
public function user_can_queue_invoices_export()
{
Excel::fake();
$this->actingAs($this->givenUser())
->get('/invoices/queue/xlsx');
Excel::assertQueued('filename.xlsx', 'diskName');
Excel::assertQueued('filename.xlsx', 'diskName', function(InvoicesExport $export) {
return true;
});
// When passing the callback as 2nd param, the disk will be the default disk.
Excel::assertQueued('filename.xlsx', function(InvoicesExport $export) {
return true;
});
}

原文地址 : Laravel-Excel 3.0 文档
本站是作者语雀文档的镜像站, 如对文章有任何疑问请移步语雀进行 提问

[转+] Laravel 中间件的介绍以及使用

介绍

Laravel 中间件提供了一种方便的机制来过滤进入应用的 HTTP 请求。
例如,Laravel 内置了一个中间件来验证用户的身份认证。如果用户没有通过身份认证,中间件会将用户重定向到登录界面。但是,如果用户被认证,中间件将允许该请求进一步进入该应用。
Laravel 自带了一些中间件,包括身份验证、CSRF 保护等。所有这些中间件都位于** app/Http/Middleware**``** **目录。

中间件的执行顺序说明

定义中间件

通过运行 make:middleware Artisan 命令来创建新的中间件:

1
php artisan make:middleware CheckAge

该命令将会在 app/Http/Middleware 目录下创建一个新的 CheckAge类,在这个中间件中,我们仅允许 age 参数大于 200 的请求对此路由进行访问,否则,我们将此用户重定向到 home

1
2
3
4
5
6
7
8
9
10
11
12
<?php
namespace App\Http\Middleware;
use Closure;
class CheckAge
{
/**
* 处理传入的请求
*
* @param \Illuminate\Http\Request $request
* @param \Closure $next
* @return mixed
*/

正如你所见,假如给定的 age 参数小于或等于 200 ,这个中间件将返回一个 HTTP 重定向到客户端;否则,请求将进一步传递到应用中。要让请求继续传递到应用程序中(即允许「通过」中间件验证的),只需使用 $request 作为参数去调用回调函数 $next
最好将中间件想象为一系列 HTTP 请求必须经过才能进入你应用的「层」。每一层都会检查请求(是否符合某些条件),(如果不符合)甚至可以(在请求访问你的应用之前)完全拒绝掉。

前置 & 后置中间件

一个中间件在请求之前或者之后进行任务处理,取决于中间件的代码逻辑放置的位置。
前置中间件

1
2
3
4
5
6
7
8
9
10
11
<?php
namespace App\Http\Middleware;
use Closure;
class BeforeMiddleware
{
public function handle($request, Closure $next)
{
// Perform action
return $next($request);
}
}

后置中间件

1
2
3
4
5
6
7
8
9
10
11
12
<?php
namespace App\Http\Middleware;
use Closure;
class AfterMiddleware
{
public function handle($request, Closure $next)
{
$response = $next($request);
// 执行操作
return $response;
}
}

注册中间件

全局中间件

假设你想让中间件在应用处理每个 HTTP 请求期间运行,只需要在 app/Http/Kernel.php 中的 $middleware属性中列出这个中间件

为路由分配中间件

假设你想为指定的路由分配中间件,首先应该在 app/Http/Kernel.php 文件内为该中间件分配一个 。默认情况下, Kernel 类的 $routeMiddleware 属性下包含了 Laravel 内置的中间件。若要加入自定义的中间件,只需把它附加到列表后并为其分配一个自定义 即可。例如:

1
2
3
4
5
6
7
8
9
// 在 App\Http\Kernel 类中
protected $routeMiddleware = [
'auth' => \Illuminate\Auth\Middleware\Authenticate::class,
'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class,
'bindings' => \Illuminate\Routing\Middleware\SubstituteBindings::class,
'can' => \Illuminate\Auth\Middleware\Authorize::class,
'guest' => \App\Http\Middleware\RedirectIfAuthenticated::class,
'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class,
];

一旦在 Kernel 类中定义好了中间件,就可以通过 middleware 方法将为路由分配中间件:

1
2
3
Route::get('admin/profile', function () {
//
})->middleware('auth');

你也可以为路由分配多个中间件:

1
2
3
Route::get('/', function () {
//
})->middleware('first', 'second');

分配中间件时,你还可以传递完整的类名:

1
2
3
4
use App\Http\Middleware\CheckAge;
Route::get('admin/profile', function () {
//
})->middleware(CheckAge::class);

中间件群组

某些时候你可能希望使用一个 key 把多个中间件打包成一个组,方便将他们应用到路由中。你可以使用 Http kernel 的 $middlewareGroups 属性。
Laravel 内置了 webapi 两个中间件组,它们包含了常用的中间件,你可能会想应用到 web UI 和 API 路由中:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
/**
* 应用程序的路由中间件组
*
* @var array
*/
protected $middlewareGroups = [
'web' => [
\App\Http\Middleware\EncryptCookies::class,
\Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
\Illuminate\Session\Middleware\StartSession::class,
\Illuminate\View\Middleware\ShareErrorsFromSession::class,
\App\Http\Middleware\VerifyCsrfToken::class,
\Illuminate\Routing\Middleware\SubstituteBindings::class,
],
'api' => [
'throttle:60,1',
'auth:api',
],
];

中间件组和单个中间件一样可以被应用到路由和控制器行为中。同时,中间组很方便得将多个中间件一次性应用到路由上:

1
2
3
4
5
6
Route::get('/', function () {
//
})->middleware('web');
Route::group(['middleware' => ['web']], function () {
//
});

中间件参数

中间件也可以接受额外的参数。举个例子,假如你的应用需要在执行特定操作之前验证用户是否为给定的 「角色」,你可以通过创建一个 CheckRole 中间件,由它来接收「角色」名称作为附加参数。他应该是放在$next 之后
附加的中间件参数应该在 $next 参数之后被传递:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<?php
namespace App\Http\Middleware;
use Closure;
class CheckRole
{
/**
* 处理传入的参数
*
* @param \Illuminate\Http\Request $request
* @param \Closure $next
* @param string $role
* @return mixed
*/
public function handle($request, Closure $next, $role)
{
if (! $request->user()->hasRole($role)) {
// 重定向
}
return $next($request);
}
}

定义路由时通过一个 : 来隔开中间件名称和参数来指定中间件参数。多个参数就使用逗号分隔:

1
2
3
Route::put('post/{id}', function ($id) {
//
})->middleware('role:editor');

Terminable 中间件

有时中间件可能需要在 HTTP 响应发送到浏览器之后处理一些工作。比如,Laravel 内置的「session」中间件会在响应发送到浏览器之后将会话数据写入存储器中。如果你在中间件中定义一个 terminate 方法,则会在响应发送到浏览器后自动调用:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<?php
namespace Illuminate\Session\Middleware;
use Closure;
class StartSession
{
public function handle($request, Closure $next)
{
return $next($request);
}
public function terminate($request, $response)
{
// Store the session data...
}
}

terminate 方法应该同时接收和响应。一旦定义了这个中间件,你应该将它添加到路由列表或 app/Http/Kernel.php 文件的全局中间件中。
在你的中间件上调用 terminate 调用时,Laravel 会从 服务容器 中解析出一个新的中间件实例。如果要在调用 handleterminate 方法时使用同一个中间件实例,就使用容器的 singleton 方法向容器注册中间件。

参考文章


原文地址 : [转+] Laravel 中间件的介绍以及使用
本站是作者语雀文档的镜像站, 如对文章有任何疑问请移步语雀进行 提问

laravel 生命周期


laravel 的生命周期主要分为 3 个主要阶段:

  • 加载项目依赖,
  • 创建应用实例,
  • 接受请求并响应

入口文件实现的代码:

阅读更多

Laravel 6.0 升级到 6.x 记录

composer 2.0

composer 2.0 版本和 laravel 6.0 版本不兼容

这个是 laravel 6.0 lts 版本的问题, 由于更改了加载方式, 这个方式在 6.0 版本中没有被修复导致的问题, 可以查看 : https://github.com/composer/composer/issues/9340
对于 laravel 版本的支持程度可以查看

这里的解决问题的办法是强制使用 composer 1.x 版本

1
$ composer self-update --1

相关组件

为了使用 composer 2.x, 我把 laravel 6.0 升级到 6.x , 因为 laravel 自 6.18 之后才支持 composer 2, 同时升级的组件还有

1
2
3
4
5
6
7
8
"require": {
tucker-eric/eloquentfilter : "~2" => "3"
},
"require-dev": {
"itsgoingd/clockwork": "~4.0" => "~5.0"
"barryvdh/laravel-ide-helper": "~2.7" => "~2.*"
"doctrine/dbal": "^2.5" => "^3"
},

Method Monolog\Logger::addDebug() does not exist

重新命名一下之前的 ide-helper.php 重新发布一下配置

1
$ php artisan vendor:publish --provider="Barryvdh\LaravelIdeHelper\IdeHelperServiceProvider" --tag=config

移除 Log 部分

1
2
3
4
5
6
7
8
9
10
11
12
'magic' => [
- 'Log' => [
- 'debug' => 'Monolog\Logger::addDebug',
- 'info' => 'Monolog\Logger::addInfo',
- 'notice' => 'Monolog\Logger::addNotice',
- 'warning' => 'Monolog\Logger::addWarning',
- 'error' => 'Monolog\Logger::addError',
- 'critical' => 'Monolog\Logger::addCritical',
- 'alert' => 'Monolog\Logger::addAlert',
- 'emergency' => 'Monolog\Logger::addEmergency',
- ],
],

原文地址 : Laravel 6.0 升级到 6.x 记录
本站是作者语雀文档的镜像站, 如对文章有任何疑问请移步语雀进行 提问

Faq

Laravel 错误 Class log does not exist …

Fatal error: Uncaught exception ‘ReflectionException’ with message ‘Class log does not exist’ in /Users/freek/dev/laravel/vendor/laravel/framework/src/Illuminate/Container/Container.php:776

出现这种问题的原因是不能够加载 log 方法. 原因是在加载的时候会加载 config 文件的数据, 而 config 文件中的配置是批量加载的, 所以在自己加载的时候 config 文件的写法不支持自定义的函数变量/ 常量/ 自定义方法.
所以从配置文件入手, 删除未加载的配置文件, 删除未导入包的配置文件.
这种问题一般出现在 复制项目, 并且删除了包的情况下.

参考文章:


原文地址 : Faq
本站是作者语雀文档的镜像站, 如对文章有任何疑问请移步语雀进行 提问

laravel artisan

用法

1
2
3
4
5
6
7
8
9
10
11
12
13
$ php artisan
Laravel Framework version 5.1.46 (LTS)
Usage:
command [options] [arguments]
Options:
-h, --help 显示当前的帮助信息
-q, --quiet 不输出任何信息
-V, --version 显示当前版本
--ansi 强制 ANSI 输出
--no-ansi 禁用 ANSI 输出
-n, --no-interaction 不进行交互
--env[=ENV] 运行环境
-v|vv|vvv, --verbose 详细输出: 1 普通, 2 更加详细 , 3 debug

可用命令

全局命令

1
2
3
4
5
6
7
8
9
10
11
12
13
clear-compiled       清除编译生成的文件,相当于 optimize 的反操作
down 将站点设为维护状态
env 显示当前运行环境, 来源于 .env 的配置
help 显示一个命令的帮助
list 列出命令
optimize 优化应用程序性能,生成自动加载文件,且产生聚合编译文件 bootstrap/compiled.php
[--force] 强制编译已写入文件 (storage/frameworks/compiled.php)
[--psr] 不对 Composer 的 dump-autoload 进行优化
serve 使用 PHP 内置的开发服务器启动应用 【要求 PHP 版本在 5.4 或以上】
[--host 0.0.0.0] 使其在本地服务器外也可正常工作
[--port 8080] 指定运行的端口号
tinker 进入与当前应用环境绑定的 REPL 环境,相当于 Rails 框架的 rails console 命令
up 将站点设回可访问状态

app

1
app:name             设置应用的命名空间

auth

1
auth:clear-resets    清除过期的密码重置令牌

cache

1
2
cache:clear          清空应用缓存
cache:table 创建缓存数据库表 migration

config

1
2
config:cache         合并所有的配置信息为一个,提高加载速度
config:clear 移除配置缓存文件

db

1
2
3
4
db:seed              运行所有的 seed 假数据生成类
[--class[="..."]] 可以指定运行的类,默认是: "DatabaseSeeder"
[--database[="..."]] 可以指定数据库
[--force] 当处于生产环境时强制执行操作

event

1
event:generate       基于注册的信息,生成遗漏的 events 和 handlers

handler

1
2
3
4
5
6
7
handler:command      生成新的处理器类
[--command="..."] 需要处理器处理的命令类名字
name
handler:event 创建一个新的事件处理器类
[--event="..."] 需要处理器处理的事件类名字
[--queued] 需要处理器使用队列话处理的事件类名字
name

key

1
key:generate         生成应用的 key(会覆盖)

make

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
make:command         在默认情况下, 这将创建未加入队列的自处理命令
[--handler] 标识来生成一个处理器
[--queued] 来使其入队列
name
make:console 创建一个新的 Artisan 命令
[--command[="..."]] 命令被调用的名称。 (默认为: "command:name")
name
make:controller 创建一个新的资源控制器
[--plain] 生成一个空白的控制器类
name 指定的名称, 可以类似于 `App\\Http\Controllers\DashboardController`
make:event 创建一个新的事件类
name
make:job 创建新的队列
make:listener 创建新的事件监听器
make:middleware 创建一个新的中间件类
name
make:migration 创建一个新的迁移文件
[--create[="..."]] 将被创建的数据表
[--table[="..."]] 将被迁移的数据表
name
make:model 创建一个新的 Eloquent 模型类
name
make:policy 创建新策略
make:provider 创建一个新的服务提供者类
name
make:request 创建一个新的表单请求类
name
make:seeder 创建新的seeder
make:test 创建

migrate

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
migrate              执行数据迁移 / 数据库迁移
[--database[="..."]] 指定数据库连接(下同)
[--force] 当处于生产环境时强制执行,不询问(下同)
[--path[="..."]] 指定单独迁移文件地址
[--pretend] 把将要运行的 SQL 语句打印出来(下同)
[--seed] Seed 任务是否需要被重新运行(下同)
migrate:install 创建迁移数据库表
[--database[="..."]]
migrate:refresh 重置并重新运行所有的 migrations
[--database[="..."]]
[--force]
[--seed]
[--seeder[="..."]] 指定主 Seeder 的类名
migrate:reset 回滚所有的数据库迁移
[--database[="..."]]
[--force]
[--pretend]
migrate:rollback 回滚最最近一次运行的迁移任务
[--database[="..."]]
[--force]
[--pretend]
migrate:status migrations 数据库表信息

queue

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
queue:failed         查看所有执行失败的队列任务
queue:failed-table 为执行失败的数据表任务创建一个迁移
queue:flush 清除所有执行失败的队列任务
queue:forget 删除一个执行失败的队列任务
queue:listen 监听指定的队列
[--queue[="..."]] 被监听的队列
[--delay[="..."]] 给执行失败的任务设置延时时间 (默认为零: 0)
[--memory[="..."]] 内存限制大小,单位为 MB (默认为: 128)
[--timeout[="..."]] 指定任务运行超时秒数 (默认为: 60)
[--sleep[="..."]] 当没有任务处于有效状态时, 设置其进入休眠的秒数 (默认为: 3)
[--tries[="..."]] 任务记录失败重试次数 (默认为: 0)
[connection]
queue:restart 在当前的队列任务执行完毕后, 重启队列的守护进程
queue:retry 对指定 id 的执行失败的队列任务进行重试
id 失败队列任务的 ID
queue:subscribe 订阅一个 url 地址到 Iron.io 推送队列 / 指定订阅 Iron.io 队列的链接
[--type[="..."]] 指定队列的推送类型
queue Iron.io 的队列名称
url 将被订阅的 URL
queue:table 为队列数据库表创建一个新的迁移
queue:work 处理下一个队列任务
[--queue[="..."]] 被监听的队列
[--daemon] 在后台模式运行
[--delay[="..."]] 给执行失败的任务设置延时时间 (默认为零: 0)
[--force] 强制在「维护模式下」运行
[--memory[="..."]] 内存限制大小,单位为 MB (默认为: 128)
[--sleep[="..."]] 当没有任务处于有效状态时, 设置其进入休眠的秒数 (默认为: 3)
[--tries[="..."]] 任务记录失败重试次数 (默认为: 0)
[connection]

route

1
2
3
route:cache          生成路由缓存文件来提升路由效率
route:clear 移除路由缓存文件
route:list 显示已注册过的路由

schedule

1
2
3
schedule:run         运行计划命令
[linux] 这个命令配合 crontab 一起使用
win 下可以配合计划任务(编写 bat 文件, 使用计划任务调用)

session

1
session:table        为 session 数据表生成迁移文件

vendor

1
2
3
4
vendor:publish       从 vendor 的扩展包中发布任何可发布的资源
[--force] 重写所有已存在的文件
[--provider[="..."]] 指定你想要发布资源文件的服务提供者
[--tag[="..."]] 指定你想要发布标记资源

view

1
view:clear           清空已经编译的缓存文件.

原文地址 : laravel artisan
本站是作者语雀文档的镜像站, 如对文章有任何疑问请移步语雀进行 提问

# Laravel 错误 Class log does not exist ...

错误信息

Fatal error: Uncaught exception ‘ReflectionException’ with message ‘Class log does not exist’ in /Users/freek/dev/laravel/vendor/laravel/framework/src/Illuminate/Container/Container.php:776

出现这种问题的原因是不能够加载 log 方法. 原因是在加载的时候会加载 config 文件的数据, 而 config 文件中的配置是批量加载的, 所以在自己加载的时候 config 文件的写法不支持自定义的函数变量/ 常量/ 自定义方法.
所以从配置文件入手, 删除未加载的配置文件, 删除未导入包的配置文件.
这种问题一般出现在 复制项目, 并且删除了包的情况下.

参考文章:

%23%23%23%20%E9%94%99%E8%AF%AF%E4%BF%A1%E6%81%AF%0A%0A%3E%20Fatal%20error%3A%20%20Uncaught%20exception%20’ReflectionException’%20with%20message%20’Class%20log%20does%20not%20exist’%20in%20%2FUsers%2Ffreek%2Fdev%2Flaravel%2Fvendor%2Flaravel%2Fframework%2Fsrc%2FIlluminate%2FContainer%2FContainer.php%3A776%0A%0A%E5%87%BA%E7%8E%B0%E8%BF%99%E7%A7%8D%E9%97%AE%E9%A2%98%E7%9A%84%E5%8E%9F%E5%9B%A0%E6%98%AF%E4%B8%8D%E8%83%BD%E5%A4%9F%E5%8A%A0%E8%BD%BD%20log%20%E6%96%B9%E6%B3%95.%20%20%E5%8E%9F%E5%9B%A0%E6%98%AF%E5%9C%A8%E5%8A%A0%E8%BD%BD%E7%9A%84%E6%97%B6%E5%80%99%E4%BC%9A%E5%8A%A0%E8%BD%BD%20config%20%E6%96%87%E4%BB%B6%E7%9A%84%E6%95%B0%E6%8D%AE%2C%20%E8%80%8C%20config%20%E6%96%87%E4%BB%B6%E4%B8%AD%E7%9A%84%E9%85%8D%E7%BD%AE%E6%98%AF%E6%89%B9%E9%87%8F%E5%8A%A0%E8%BD%BD%E7%9A%84%2C%20%E6%89%80%E4%BB%A5%E5%9C%A8%E8%87%AA%E5%B7%B1%E5%8A%A0%E8%BD%BD%E7%9A%84%E6%97%B6%E5%80%99%20config%20%E6%96%87%E4%BB%B6%E7%9A%84%E5%86%99%E6%B3%95%E4%B8%8D%E6%94%AF%E6%8C%81%E8%87%AA%E5%AE%9A%E4%B9%89%E7%9A%84%E5%87%BD%E6%95%B0%E5%8F%98%E9%87%8F%2F%20%E5%B8%B8%E9%87%8F%2F%20%E8%87%AA%E5%AE%9A%E4%B9%89%E6%96%B9%E6%B3%95.%0A%0A%E6%89%80%E4%BB%A5%E4%BB%8E%E9%85%8D%E7%BD%AE%E6%96%87%E4%BB%B6%E5%85%A5%E6%89%8B%2C%20%E5%88%A0%E9%99%A4%E6%9C%AA%E5%8A%A0%E8%BD%BD%E7%9A%84%E9%85%8D%E7%BD%AE%E6%96%87%E4%BB%B6%2C%20%E5%88%A0%E9%99%A4%E6%9C%AA%E5%AF%BC%E5%85%A5%E5%8C%85%E7%9A%84%E9%85%8D%E7%BD%AE%E6%96%87%E4%BB%B6.%20%0A%0A%E8%BF%99%E7%A7%8D%E9%97%AE%E9%A2%98%E4%B8%80%E8%88%AC%E5%87%BA%E7%8E%B0%E5%9C%A8%20%E5%A4%8D%E5%88%B6%E9%A1%B9%E7%9B%AE%2C%20%E5%B9%B6%E4%B8%94%E5%88%A0%E9%99%A4%E4%BA%86%E5%8C%85%E7%9A%84%E6%83%85%E5%86%B5%E4%B8%8B.%20%0A%0A%23%23%23%20%E5%8F%82%E8%80%83%E6%96%87%E7%AB%A0%3A%20%0A%0A-%20%5BClass%20log%20does%20not%20exist%5D(https%3A%2F%2Flaracasts.com%2Fdiscuss%2Fchannels%2Fgeneral-discussion%2Fclass-log-does-not-exist)%0A%0A


原文地址 : # Laravel 错误 Class log does not exist …
本站是作者语雀文档的镜像站, 如对文章有任何疑问请移步语雀进行 提问

[译]Laravel 5.0 之 ValidatesWhenResolved

[译]Laravel 5.0 之 ValidatesWhenResolved

暂无评论

本文译自  Matt Stauffer  的系列文章.


在创建 FormRequest 的时候, Taylor(译注: Laravel 框架的作者) 还编写了一个接口 (ValidatesWhenResolved) 和一个 trait (ValidatesWhenResolvedTrait), 都是用于对控制器方法进行校验的. 这种校验会在IOC 容器对该方法的依赖项解析成功时调用.
老实说, 我目前还没有写出一个在 FormRequests 类之外的应用场景来使用这两个东西的实例. 但我还是想写一篇文档来介绍它们, 希望有比我更聪明的人来找出它们在实际项目中可能的应用场景.
所以, 如果你读过我的上一篇文章, 你已经了解了 FormRequest 对象, 通过 IOC 的依赖注入机制注入到方法, 可以取消相关方法的执行. 假如表单提交的数据不能通过校验, 与该表单对应的 POST route 会被负责校验它的 FormRequest 类取消执行.
这带来的一个结果就是: “触发 IOC 容器的 FormRequest 调用校验方法” 这个操作可以被分离为一个单独的接口, 名为  ValidatesWhenResolved. 借助这一点, 我们也可以创建类似 FormRequest 的类, 在执行控制器方法 (理论上非控制器也可以) 之前对请求进行拦截, 并决定它能否通过校验.

说明: 如果一个请求校验失败的话, 路由或方法其实没有真正取消. FormRequest 只是抛出了一个 HTTP 异常, 该异常随后以 JSON 格式返回, 或者被重定向到处理异常的页面. 理论上来说, 你不实现这个接口, 而只是简单地在控制器的构造函数中进行校验并抛出异常也是一样的. 但是借助这个接口, 我们可以保持代码清洁, 并且可以在一个命名的方法中来执行校验.

接口

在本文写作的时候, 该接口的签名是这样的:

namespace Illuminate\Contracts\Validation;
  
use Illuminate\Contracts\Container\Container;
  
interface ValidatesWhenResolved {
  
        ``/**
          ``* 对指定的类实例进行校验
          ``*
          ``* @return void
          ``*/
        ``public function validate();
  
}

通过该签名可知, 实现这个接口只需要实现一个方法  validate(). 事实上, 对于实现这个方法的类, 我们只需要知道一点, 就是当 IOC 容器解析到它的时候, 会调用  validate()  这个方法. 接下来我们就来创建一个并非 FormRequest 扩展类但是却实现了这个接口的类:

在控制器中不使用 FormRequest 进行校验

// app/Http/Controllers/ValidatedController.php
  
namespace App\Http\Controllers;
  
use App\Random\RandomAccess;
use Illuminate\Routing\Controller;
use Response;
  
class ValidatedController  ``extends Controller
{
        ``public function random(RandomAccess  ``$ram``)
        ``{
                ``return Response::make(``'You made it!'``);
        ``}
}

上面是一个简单的控制器. 有了路由之后, 我们来创建一个不继承 FormRequest 的验证类:

// app/Random/RandomAccess.php
namespace App\Random;
  
use Exception;
use Illuminate\Contracts\Validation\ValidatesWhenResolved;
use Illuminate\Http\Request;
  
class RandomAccess  ``implements ValidatesWhenResolved
{
        ``public function __construct(Request  ``$request``)
        ``{
                ``$this``->request =  ``$request``;
        ``}
  
        ``public function validate()
        ``{
                ``// Test for an even vs. odd remote port
                ``if ((``$this``->request->server->get(``'REMOTE_PORT'``) / 2) % 2 > 0)
                ``{
                        ``throw new Exception(``"WE DON'T LIKE ODD REMOTE PORTS"``);
                ``}
        ``}
}

现在控制器方法就被拦截并且随机抛出异常 (取决于请求访问的端口是奇数还是偶数, 这恐怕是有史以来最没实用价值的一个例子了, 哈哈).
如你所见, 这里没有用到什么神奇的东西,  validate()  方法是否返回 true 或者 false 并不重要. 你当然可以通过 ValidatesWhenResolvedTrait 这个 trait 来实现 FormRequest 中的  failedValidation()  的部分流程, 而在上面的例子中, 只需要抛出异常就可以了.

在控制器之外使用 FormRequest 风格的验证

在控制器之外也可以使用这些手段, 比如在 FormRequest 风格的验证中使用 ValidatesWhenResolvedTrait. 但我暂时没有找到合适的用例, 所以我先简单地略过这部分. 你可以自己尝试… 但是我想不出有什么理由值得这样去做, 呵呵.

真实案例

你肯定不会像上面的例子里那样去随机抛出异常. 本文探讨的这些新特性最终看起来有点像以前的 route filters. 但我还是怀疑它们在实际中能有多少应用场景. 不管怎么说, 要是你想给你的控制器注入什么东西的话, 或者可以让它实现 ValidatesWhenResolved 接口或者使用 ValidatesWhenResolvedTrait, 这样它就能通过注入进行自动校验, 不用额外去调用一个校验方法了.

结束语

你可以认为这篇文章的目的就是为了钓鱼, 看看能否找到对这个新特性的实际应用场景. 假如你有什么想法, 可以通过 Twitter 与  @stauffermatt  进行讨论.


原文地址 : [译]Laravel 5.0 之 ValidatesWhenResolved
本站是作者语雀文档的镜像站, 如对文章有任何疑问请移步语雀进行 提问

# [转] Laravel 5.3+ 控制器里如何获取登录用户

原文地址: Laravel 5.3+ 控制器里如何获取登录用户
应该不少同学都遇到这个问题了:5.3 起,由于框架运行流程的修改,你无法在控制器的构造函数里获取登录用户,那么我们怎么办呢?以下是几个方法:

  1. 不再从构造函数取用户
    我们可以从 request 中获取登录用户:request()->user()
  2. 或者在控制器方法里我们使用  Auth::user()

除了上面的折中的办法,我们一定要在构造函数搞定的话那么请看这里:

阅读更多

# [译] 如何在 Laravel 中 使用 Beauty mail 发送漂亮的HTML电子邮件

原文地址 : How to send beautiful HTML emails with Laravel using Beauty mail
2018年8月14日

大家好,欢迎回到 laravel。这里将向您展示如何使用SnowFire的Beauty邮件包在您的laravel应用程序中发送干净漂亮的HTML电子邮件。在我之前的一篇文章中我向您展示了如何使用SendGrid邮件服务提供商发送电子邮件,在这里我扩展了发送干净优雅的HTML电子邮件而不是纯文本电子邮件。

阅读更多

# laravel 学习笔记 - 显示自定义控制器数据调用

创建控制器

  • 使用命令行创建 Welcome 控制器

    1
    php artisan make:controller FirstController --only=index

    运行上述命令后,Laravel 会生成 app/Http/controllers/WelcomeController.php 文件。生成文件后修改其中的 index 方法:

    1
    2
    3
    public function index() {
    return view('first.index');;
    }
  • 创建视图
    resources/views/ 目录新建文件夹 first 并创建文件 index.blade.php ;
    index.blade.php 文件中添加 <h1>Hello, Laravel!</h1> ;

%23%23%20%E5%88%9B%E5%BB%BA%E6%8E%A7%E5%88%B6%E5%99%A8%0A-%20%20%E4%BD%BF%E7%94%A8%E5%91%BD%E4%BB%A4%E8%A1%8C%E5%88%9B%E5%BB%BA%20Welcome%20%E6%8E%A7%E5%88%B6%E5%99%A8%0A%60%60%60%0Aphp%20artisan%20make%3Acontroller%20FirstController%20–only%3Dindex%0A%60%60%60%0A%E8%BF%90%E8%A1%8C%E4%B8%8A%E8%BF%B0%E5%91%BD%E4%BB%A4%E5%90%8E%EF%BC%8CLaravel%20%E4%BC%9A%E7%94%9F%E6%88%90%20app%2FHttp%2Fcontrollers%2FWelcomeController.php%20%E6%96%87%E4%BB%B6%E3%80%82%E7%94%9F%E6%88%90%E6%96%87%E4%BB%B6%E5%90%8E%E4%BF%AE%E6%94%B9%E5%85%B6%E4%B8%AD%E7%9A%84%20index%20%E6%96%B9%E6%B3%95%EF%BC%9A%0A%60%60%60%0Apublic%20function%20index()%20%7B%0A%20%20%20%20return%20view(‘first.index’)%3B%3B%0A%7D%0A%60%60%60%0A%0A-%20%E5%88%9B%E5%BB%BA%E8%A7%86%E5%9B%BE%0A%E5%9C%A8%20%60resources%2Fviews%2F%60%20%E7%9B%AE%E5%BD%95%E6%96%B0%E5%BB%BA%E6%96%87%E4%BB%B6%E5%A4%B9%20%60first%60%20%E5%B9%B6%E5%88%9B%E5%BB%BA%E6%96%87%E4%BB%B6%20%60index.blade.php%60%20%3B%0A%E5%9C%A8%20%60index.blade.php%60%20%E6%96%87%E4%BB%B6%E4%B8%AD%E6%B7%BB%E5%8A%A0%20%60%3Ch1%3EHello%2C%20Laravel!%3C%2Fh1%3E%60%20%3B


原文地址 : # laravel 学习笔记 - 显示自定义控制器数据调用
本站是作者语雀文档的镜像站, 如对文章有任何疑问请移步语雀进行 提问

Laravel 5.5 升级到 6.0 记录

1. 可以选择缓存使用 phpredis/predis

phpredis : 指的是使用 pecl 安装的 php 扩展 redis
predis : 指的是 github 上的 predis/predis 的包
Laravel 推荐使用 phpredis 来代替 predis。原因是predis 包很长时间没有更新
所以要记得先安装 phpredis, 然后在 config/app.php 中去掉 Redis 别名
Mac 安装

1
2
3
4
5
# 这里需要将当前版本设置为主版本才可以, 如果不是主版本则安装会太费劲
$ brew link --force php@{version}
$ pecl install igbinary
$ pecl install redis
$ brew services restart php@7.2

其他平台
应该是直接安装即可(未测试)
项目中在考虑兼容的情况下, 使用predis, 暂时不启用 phpredis.

2. Unable to create configured logger. Using emergency logger

在 5.6 之后已经将配置文件独立 config/logging.php, 将这个文件放置到指定目录, 然后 app.php 移除日志的配置 Logging Configuration

3. Call to undefined method Illuminate\Events\Dispatcher::fire()

在 (5.8 升级指南)(https://laravel.com/docs/5.8/upgrade) 指出,
Likelihood Of Impact: Low

1
2
deprecated and removed
Events The fire Method

使用 dispatch 方法替代 You should use the dispatch method instead.

4. Class ‘Illuminate\Support\Facades\Input’ not found

使用 Request 替代 Input
Input no longer exists. Either use the Request facade or alias that instead of Input.

5. str_contains 等 helper 函数

这些函数均需要替换成静态函数方法 Str::contains
下面是 辅助函数列表
5.1 辅助函数列表


原文地址 : Laravel 5.5 升级到 6.0 记录
本站是作者语雀文档的镜像站, 如对文章有任何疑问请移步语雀进行 提问