多厘

多厘 查看完整档案

济南编辑  |  填写毕业院校山东猎象网络科技有限公司  |  技术经理 编辑 segmentfault.com/u/duoli 编辑
编辑

while(vue && react && javascript && php):
    全栈 += 1;
do;

个人动态

多厘 提出了问题 · 1月11日

大家帮忙看下, 这个 nginx 的 rewrite 规则的正确写法是什么, 关于反向代理的

location ~* "(?<begin>rplocal|rposs)/([a-z0-9]{3})/([a-z0-9]{8})/(.*)$" {
    rewrite "(?<begin>rplocal|rposs)/([a-z0-9]{3})/([a-z0-9]{8})/(.*)$" /$2/$3/$4 break;
    if ($begin = 'rplocal') {
        set $proxy http://127.0.0.1:9222;
    }
    if ($begin = 'rposs') {
        set $proxy https://url-domain.com;
    }
    proxy_pass $proxy;
}

目的是通过 url 反向到不同的地址

这里补充一个可以通过的方案, 但是此方案还有冗余 rewrite, 是使用 openresty + echo 调试出来的

location ~* "(rplocal|rposs)/([a-z0-9]{3})/([a-z0-9]{8})/(.*)$" {
    set $type $1;
    if ($type = "rplocal") {
        rewrite "^/([a-z\-]*)/(\w{3})(\w{5})/(.*)$" /$2/$3/$4 break;
        proxy_pass http://127.0.0.1:9222;
    }
    if ($type = "rposs") {
        rewrite "^/([a-z\-]*)/(\w{3})(\w{5})/(.*)$" /$2/$3/$4 break;
        proxy_pass https://url-domain.com;
    }
}

关注 3 回答 1

多厘 发布了文章 · 2020-11-06

fzaninotto/Faker 不继续维护, 基于其自建中文 Faker 生成库

Poppy Faker 是基于 fzaninotto/Faker 的中文版本, 因为之前的版本包含语言过多, 作者已经停止维护, 所以将这个数据进行拆离, 并加入中国特色的部分验证规则.

Faker 可以帮助你创建数据库数据, XML 报表, 填写假地址, 或者匿名的数据.

安装

composer require poppy/faker

基本使用

在项目根目录下运行

$ php -S 0.0.0.0:8000 -t tests/
PHP 7.2.33 Development Server started at Thu Nov  5 15:21:19 2020
Listening on http://0.0.0.0:8000
Document root is /path/of/poppy/faker/tests
Press Ctrl-C to quit.

然后再浏览器访问即可获取详细的示例数据

http://127.0.0.1:8000/       # 返回 带有样式的示例数据
http://127.0.0.1:8000/?md    # 返回 Markdown 格式数据

基于包的调整项目

  • 删除 ORM
  • 删除除 [en_US, zh_CN, zh_TW] , 之外的语言
  • 增加 zhCN 身份证号生成

创建假数据

使用 \\Poppy\\Faker\\Factory::create('zh_CN') 来创建和初始化生成器, 这里保留之前英文版生成数据的规则

<?php
// use the factory to create a \Poppy\Faker\Generator instance
$faker = \Poppy\Faker\Factory::create('zh_CN');

// generate data by accessing properties
echo $faker->name;
  // 'Lucy Cechtelar';
echo $faker->address;
  // "426 Jordy Lodge
  // Cartwrightshire, SC 88120-6700"
echo $faker->text;
  // Dolores sit sint laboriosam dolorem culpa et autem. Beatae nam sunt fugit
  // et sit et mollitia sed.
  // Fuga deserunt tempora facere magni omnis. Omnis quia temporibus laudantium
  // sit minima sint.

Base

// 生成随机整数 0 - 9
$faker->randomDigit;                                  // 8
// 生成唯一整数
$faker->unique()->randomDigit;                        // 1
// 生成随机不为空的整数
$faker->randomDigitNotNull;                           // 8
// 生成随机数字
$faker->randomNumber($nbDigits = 5, $strict = false); // 6783
// 生成随机浮点数
$faker->randomFloat($nbMaxDecimals = null, $min = 0, $max = null); // 13399.11050914
// 在指定范围内生成随机数
$faker->numberBetween($min = 1000, $max = 9000);      // 3953
// 生成随机字符
$faker->randomLetter;                                 // t
// 在给定的数组中,随机生成给定的个数字符
$faker->randomElements($array = ['a', 'b', 'c'], $count = 2); // Array
(
    [0] => a
    [1] => c
)

// 在给定的数组中,生成单个随机字符
$faker->randomElement($array = ['a', 'b', 'c']);      // a
// 打乱给定的字符串
$faker->shuffle('hello, world');                      // elrlh dowol,
// 打乱给定的数组
$faker->shuffle([1, 2, 3]);                           // Array
(
    [0] => 3
    [1] => 1
    [2] => 2
)

// 给占位符生成随机整数 (数字为#)
$faker->numerify('Hello ###');                        // Hello 713
// 给占位符生成随机字符串 (字符串为?)
$faker->lexify('Hello ???');                          // Hello jjg
// 给占位符生成混合的随机字符串
$faker->bothify('Hello ##??');                        // Hello 79ks
// 给占位符生成随机的字符(字母、数字、符号)
$faker->asciify('Hello ***');                         // Hello B.7
// 根据正则规则生成随机字符
$faker->regexify('[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,4}'); // _XD%HRE@VUREXV2D.OLYE

Lorem

// 生成随机个数的字符串
$faker->word;                                         // 议
// 随机生成指定个数的字符串
$faker->words($nb = 3, $asText = false);              // Array
(
    [0] => 玩
    [1] => 转
    [2] => 答
)

// 随机生成一条语句
$faker->sentence($nbWords = 6, $variableNbWords = true); // 纳怀房海交知.
// 随机生成指定条数的语句
$faker->sentences($nb = 3, $asText = false);          // Array
(
    [0] => 授界类表如守.
    [1] => 尼痛念化人归懂总.
    [2] => 圣味送杂含贝机四.
)

// 随机生成一个段落
$faker->paragraph($nbSentences = 3, $variableNbSentences = true); // 雄摇马史她戴袋. 层关飞某阿喊. 松上助仍奥外讲.
// 随机生成指定个数段落
$faker->paragraphs($nb = 3, $asText = false);         // Array
(
    [0] => 充条数和制尔进知中. 果藏供创阵急遗然. 从请生反雄仍洲叶护.
    [1] => 报停暗险端市. 兴定北洛革. 去夜慢纳脚脱. 调雪妙托脱走它相. 汉典儿九刻.
    [2] => 真语强究授童剧银. 型济著武热吧克藏. 母英封蒙.
)

// 随机生成一个文本
$faker->text($maxNbChars = 200);                      // 熟称喝救告吸确. 馆推布信久识. 民又事黄要之怎划. 奇兰现介先对戏. 罪总乎论雪兵黄岛. 禁安议做亲差学极.

Person

// 职位
$faker->title;             // 太太
// 称谓
$faker->titleMale;         // 教授
// 女性称谓
$faker->titleFemale;       // 律师
// 姓名
$faker->name               // 萧文君
// 名字
$faker->firstName          // 志明
// 男性名字
$faker->firstNameMale      // 华
// 女性名字
$faker->firstNameFemale    // 楠
// 姓
$faker->lastName           // 马
// 随机生成一个可以校验的身份证号
$faker->idNumber           // 640181200809108307

Address

// 随机生成省份/州
$faker->state;                                 // 河南省
// 随机城市省份/州缩写
$faker->stateAbbr;                             // 蒙
// 随机生成城市后缀
$faker->citySuffix;                            // Ville
// 随机生成街道后缀
$faker->streetSuffix;                          // Street
// 随机生成建筑编号
$faker->buildingNumber;                        // 11
// 随机生成城市
$faker->city;                                  // 拉萨
// 随机生成街道名
$faker->streetName;                            // 畅 Street
// 随机生成街道地址
$faker->streetAddress;                         // 71 孟 Street
// 随机生成邮编
$faker->postcode;                              // 217000
// 随机生成地址
$faker->address;                               // 沈阳兴山区
// 随机生成国家
$faker->country;                               // 圣马力诺
// 随机生成纬度
$faker->latitude($min = -90, $max = 90);       // 75.15737
// 随机生成经度
$faker->longitude($min = -180, $max = 180);    // -81.385411

Phone Number

// 生成随机电话号码
$faker->phoneNumber;        // 13273265620
// 随机生成e164电话
$faker->e164PhoneNumber;    // +3411056457052

Company

// 随机生成公司
$faker->company;          // 巨奥信息有限公司
// 随机生成公司后缀
$faker->companySuffix;    // 传媒有限公司
// 随机生成职务
$faker->jobTitle;         // 必

Text

// 随机生成一段文本
$faker->realText($maxNbChars = 200, $indexSize = 2);  // CHAPTER IV. The Rabbit Sends in a deep, hollow tone: 'sit down, both of you, and don't speak a word till I've finished.' So they had to pinch it to make out exactly what they WILL do next! If they.

Datetime

// 随机生成时间戳
$faker->unixTime($max = 'now');                       // 84146285
// 随机生成时间
$faker->dateTime($max = 'now', $timezone = date_default_timezone_get()); // DateTime Object
(
    [date] => 1981-09-02 21:14:42.000000
    [timezone_type] => 3
    [timezone] => Asia/Shanghai
)

//  dateTimeAd
$faker->dateTimeAD;                                   // DateTime Object
(
    [date] => 0308-03-16 05:39:50.000000
    [timezone_type] => 3
    [timezone] => Asia/Shanghai
)

// 随机生成ios8601时间
$faker->iso8601($max = 'now');                        // 1991-03-04T20:59:46+0800
// 根据格式随机生成日期
$faker->date($format = 'Y-m-d', $max = 'now');        // 1983-03-01
// 根据格式随机生成时间
$faker->time($format = 'H:i:s', $max = 'now');        // 22:34:27
// 生成指定范围的时间
$faker->dateTimeBetween($startDate = '-30 years', $endDate = 'now'); // DateTime Object
(
    [date] => 2006-07-12 13:47:24.000000
    [timezone_type] => 3
    [timezone] => Asia/Shanghai
)

// 随机生成一个指定间隔的时间
$faker->dateTimeInInterval($startDate = '-30 years', $interval = '+ 5 days', $timezone = date_default_timezone_get()); // DateTime Object
(
    [date] => 1990-11-08 17:13:04.000000
    [timezone_type] => 3
    [timezone] => Asia/Shanghai
)

// 随机生成当前世纪的时间
$faker->dateTimeThisCentury($max = 'now', $timezone = date_default_timezone_get()); // DateTime Object
(
    [date] => 1991-02-19 01:39:03.000000
    [timezone_type] => 3
    [timezone] => Asia/Shanghai
)

// 随机生成当前十年的时间
$faker->dateTimeThisDecade($max = 'now', $timezone = date_default_timezone_get()); // DateTime Object
(
    [date] => 2013-12-25 22:46:17.000000
    [timezone_type] => 3
    [timezone] => Asia/Shanghai
)

// 随机生成当前年的时间
$faker->dateTimeThisYear($max = 'now', $timezone = date_default_timezone_get()); // DateTime Object
(
    [date] => 2020-05-18 23:34:51.000000
    [timezone_type] => 3
    [timezone] => Asia/Shanghai
)

// 随机生成当前月的时间
$faker->dateTimeThisMonth($max = 'now', $timezone = date_default_timezone_get()); // DateTime Object
(
    [date] => 2020-10-27 04:22:07.000000
    [timezone_type] => 3
    [timezone] => Asia/Shanghai
)

// 随机生成 am/pm
$faker->amPm($max = 'now');                           // 下午
// 随机生成月份的某一天
$faker->dayOfMonth($max = 'now');                     // 30
// 随机生成星期
$faker->dayOfWeek($max = 'now');                      // 星期日
// 随机生成月份
$faker->month($max = 'now');                          // 03
// 随机生成月份的名称
$faker->monthName($max = 'now');                      // 十一月
// 随机生成年份
$faker->year($max = 'now');                           // 2004
// 随机生成世纪
$faker->century;                                      // XV
// 随机生成时区
$faker->timezone;                                     // Asia/Hebron

Internet

// 随机生成邮箱地址
$faker->email;              // xiao_er@hotmail.com
// 随机生成安全的邮箱地址
$faker->safeEmail;          // an82@example.net
// 随机生成免费的邮箱地址
$faker->freeEmail;          // alian@126.com
// 随机生成公司邮箱地址
$faker->companyEmail;       // tong_mai@qu.com
// 随机生成免费邮箱域名
$faker->freeEmailDomain;    // 126.com
// 随机生成安全邮箱域名
$faker->safeEmailDomain;    // example.org
// 随机生成用户名
$faker->userName;           // ting_du
// 随机生成密码
$faker->password;           // h1RZMuV54|n=Q$L-in]
// 随机生成域名
$faker->domainName;         // yan.org
// 随机生成域
$faker->domainWord;         // bai
// todo Tld
$faker->tld;                // biz
// 随机生成url地址
$faker->url;                // https://zhou.info/方-农-死-规.html
// 随机生成块
$faker->slug;               // 的-城-心-古-终-参-济-文
// 随机生成ipv4地址
$faker->ipv4;               // 243.54.13.136
// 随机生成本地ipv4地址
$faker->localIpv4;          // 10.5.211.82
// 随机生成ipv6地址
$faker->ipv6;               // 7ca1:9d43:46d5:589f:1b2b:e372:5e17:1a91
// 随机生成mac地址
$faker->macAddress;         // 14:38:9C:55:CD:C5

UserAgent

// 用户代理
$faker->userAgent;           // Mozilla/5.0 (X11; Linux x86_64; rv:6.0) Gecko/20190828 Firefox/36.0
// 谷歌
$faker->chrome;              // Mozilla/5.0 (Windows 98; Win 9x 4.90) AppleWebKit/5321 (KHTML, like Gecko) Chrome/37.0.885.0 Mobile Safari/5321
// 火狐
$faker->firefox;             // Mozilla/5.0 (Windows NT 5.1; en-US; rv:1.9.2.20) Gecko/20110217 Firefox/36.0
// Safari
$faker->safari;              // Mozilla/5.0 (iPad; CPU OS 7_0_1 like Mac OS X; en-US) AppleWebKit/531.7.5 (KHTML, like Gecko) Version/3.0.5 Mobile/8B111 Safari/6531.7.5
// 欧朋
$faker->opera;               // Opera/8.83 (Windows NT 5.01; en-US) Presto/2.12.189 Version/12.00
// ie
$faker->internetExplorer;    // Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.1; Trident/3.1)

Payment

// 随机生成信用卡类型
$faker->creditCardType;                    // MasterCard
// 随机生成信用卡号
$faker->creditCardNumber;                  // 343611837373950
// 随机生成信用卡有效日期
$faker->creditCardExpirationDate;          // DateTime Object
(
    [date] => 2022-11-09 16:46:16.000000
    [timezone_type] => 3
    [timezone] => Asia/Shanghai
)

// 随机生成信用卡有效日期
$faker->creditCardExpirationDateString;    // 11/20
// 随机生成信用卡明细
$faker->creditCardDetails;                 // Array
(
    [type] => Visa
    [number] => 4556837981031508
    [name] => 鄢子安
    [expirationDate] => 06/21
)

// 随机生成国际银行账号
$faker->iban($countryCode = null);         // GR8189640507T689358O3SK6K5B
// todo 瑞士银行账号
$faker->swiftBicNumber;                    // DWDFOKO4S3Y

Color

// 随机生成16进制颜色
$faker->hexColor;           // #7675e0
// 随机生成rgb格式的颜色
$faker->rgbColor;           // 222,237,164
// 随机生成数组格式的rgb颜色
$faker->rgbColorAsArray;    // Array
(
    [0] => 118
    [1] => 160
    [2] => 37
)

// 随机生成css格式的rgb颜色
$faker->rgbCssColor;        // rgb(133,60,133)
// 随机生成颜色名称
$faker->safeColorName;      // 黑色
//  颜色名称
$faker->colorName;          // 暗兰紫

File

// 随机生成文件扩展名
$faker->fileExtension;    // 3dml
// 随机生成mime类型
$faker->mimeType;         // application/vnd.pvi.ptid1

Image

// 随机生成图片地址
$faker->phUrl($width = 640, $height = 480);    // https://fakeimg.pl/640x480/282828/eae0d0?
// 随机生成头像地址
$faker->avatarUrl(300, 'girl');                // https://pravatar.cc/300?img=38
// 返回 Svg Url 地址
$faker->svgUrl(100, 100)                       // https://pravatar.cc/bottts/19857.svg?width=100&height=100

UUID

// 随机生成一个唯一字串
$faker->uuid    // 47b5b18c-6fee-3188-9d88-ecb7e406da4b

Calculator

// 随机生成13位ean码
$faker->ean13;     // 0120309434624
// 随机生成8位ean码
$faker->ean8;      // 44845025
// 随机生成13位isbn码
$faker->isbn13;    // 9798976904019
// 随机生成10位isbn码
$faker->isbn10;    // 7300501559

Miscellaneous

// 随机生成bool值 false
$faker->boolean;                               // 1
// 平衡的生成bool值
$faker->boolean($chanceOfGettingTrue = 50);    // 
//  Md5
$faker->md5;                                   // 02ab746139e35599e12a2a0fc21ece2c
//  Sha1
$faker->sha1;                                  // 81308895610bbe530dec6269e4cce55044dda0dd
//  Sha256
$faker->sha256;                                // 3cc0882a1c3d7f68298a93c32ce2f094118ad72dbe00ef35e96f4613aaecef2f
//  Locale
$faker->locale;                                // ja_JP
// 随机生成国家编码
$faker->countryCode;                           // IS
// 随机生成语言编码
$faker->languageCode;                          // mn
// 随机生成货币代码
$faker->currencyCode;                          // KZT
//  Emoji
$faker->emoji;                                 // 😞

Biased

// 在10到20之间得到一个随机数,有更多的几率接近20
$faker->biasedNumberBetween($min = 10, $max = 20, $function = 'sqrt'); // 17

Html

// 随机生成一个不超过 $maxDepth层的html, 任何级别上都不超过$maxWidth个元素
$faker->randomHtml($maxDepth = 2, $maxWidth = 3);    // <html><head><title>&#35328;&#33410;&#26174;&#30331;.</title></head><body><form action="example.com" method="POST"><label for="username">&#21017;</label><input type="text" id="username"><label for="password">&#38750;</label><input type="password" id="password"></form><i>&#27700;&#32447;&#21517;&#35785;&#21568;&#23396;&#36215;.</i></body></html>

License

Faker is released under the MIT License. See the bundled LICENSE file for details.

查看原文

赞 1 收藏 1 评论 1

多厘 提出了问题 · 2020-02-03

java 中如何将 emoji 表情识别为 1个字符

对于 emoji 中 ? 这个符号, 如何将这个符号识别为 1个字符

php 处理这个多字节字符为 1 个字符

关注 2 回答 1

多厘 赞了回答 · 2019-10-15

解决git 如何克隆或下载一个仓库子文件夹?

我的解决方法:
https://github.com/geekhac/to...子目录为例:

git init todomvc && cd todomvc

git config core.sparsecheckout true //设置允许克隆子目录

echo '/examples/react/*' >> .git/info/sparse-checkout //设置要克隆的仓库的子目录路径

git remote add origin https://github.com/geekhac/to...

git pull origin master

关注 4 回答 3

多厘 评论了文章 · 2019-04-26

[译] Laravel-Excel 3.0 文档

Basics

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

App/Exports 下创建一个 InvoicesExport

namespace App\Exports;

use Maatwebsite\Excel\Concerns\FromCollection;

class InvoicesExport implements FromCollection
{
    public function collection()
    {
        return Invoice::all();
    }
}

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

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

或者存储在 s3 磁盘中

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

依赖注入

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

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();
    }
}
public function export(Excel $excel, InvoicesExport $export) 
{
    return $excel->download($export, 'invoices.xlsx');
}

严格的 null 对比

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

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 下载

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

在磁盘上存储 collection

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

在磁盘上存储导出

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

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 方法.

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 直接进行类的下载

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

或者是存储到磁盘上.

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

Responsable / 可响应的

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

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() 方法.

return new InvoicesExport();

From Query / 从查询输出

在之前的例子中, 我们在导出类中进行查询, 当然这个解决方案可以用在小的导出类中. 对于更大一点数据的导出类可能造成比较大的性能开销.

通过使用 FromQuery 关系, 我们可以通过预查询一个导出, 这个场景实现的原理是查询可以分块执行.

InvoicesExport 类中,添加 FromQuery 关系, 并且添加一个查询, 并且确保不要使用 ->get() 来获取到数据!.

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();
    }
}

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

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

自定义查询

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

作为构造器参数

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 参数可以传递给导出类.

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

作为设置项

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 方法来调整年份.

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

通过视图

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

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:

<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>

队列

如果你处理更大数据量的数据, 很明智的方法就是使用队列来运行.

例如下边的导出类:

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() 方法即可.

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

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

另一种方式的队列实现

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

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:你需要首先自行配置队列]

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

追加任务 / jobs

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

return (new InvoicesExport)->queue('invoices.xlsx')->chain([
    new NotifyUserOfCompletedExport(request()->user()),
]);
namespace App\Jobs;

use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;

class InvoiceExportCompletedJob implements ShouldQueue
{
    use Queueable;

    public function handle()
    {
        // Do something.
    }
}

自定义队列

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

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

多单元表

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

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 可以实现多种关系. 例如 FromQueryFromCollection, ...

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 单元表来显示每个月的数据.

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

数据遍历

遍历行

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


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 约束来实现. 表头会添加到所有数据的第一行的位置上.


use Maatwebsite\Excel\Concerns\FromQuery;
use Maatwebsite\Excel\Concerns\WithHeadings;

class InvoicesExport implements FromQuery, WithHeadings

    public function headings(): array
    {
        return [
            '#',
            'Date',
        ];
    }
}

格式化列

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

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() 来正确的解析你的日期数据.

导出关系

InterfaceExplanation
Maatwebsite\Excel\Concerns\FromCollectionUse a Laravel Collection to populate the export.
Maatwebsite\Excel\Concerns\FromQueryUse an Eloquent query to populate the export.
Maatwebsite\Excel\Concerns\FromViewUse a (Blade) view to to populate the export.
Maatwebsite\Excel\Concerns\WithTitleSet the Workbook or Worksheet title.
Maatwebsite\Excel\Concerns\WithHeadingsPrepend a heading row.
Maatwebsite\Excel\Concerns\WithMappingFormat the row before it's written to the file.
Maatwebsite\Excel\Concerns\WithColumnFormattingFormat certain columns.
Maatwebsite\Excel\Concerns\WithMultipleSheetsEnable multi-sheet support. Each sheet can have its own concerns (except this one).
Maatwebsite\Excel\Concerns\ShouldAutoSizeAuto-size the columns in the worksheet.
Maatwebsite\Excel\Concerns\WithStrictNullComparisonUses strict comparisions when testing cells for null value.
Maatwebsite\Excel\Concerns\WithEventsRegister events to hook into the PhpSpreadsheet process.

Traits

TraitExplanation
Maatwebsite\Excel\Concerns\ExportableAdd download/store abilities right on the export class itself.
Maatwebsite\Excel\Concerns\RegistersEventListenersAuto-register the available event listeners.

扩展

事件

导出过程有一些事件,你可以利用这些事件与底层类进行交互,以向导出添加自定义行为。

通过使用事件,您可以连接到父包。如果你需要完全控制导出,则不需要使用诸如 "query" 或者 "view" 之类的便利方法。

事件将通过添加 WithEvents 关注来激活。在 registerEvents 方法中,你必须返回一系列事件。Key 是事件的完全限定名(FQN),Value 是可调用的事件监听器。这可以是一个闭包、可调用的数组 或 invokable 类。

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 。只有在创建方法时,侦听器才会被注册。

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 namePayloadExplanation
Maatwebsite\Excel\Events\BeforeExport$event->writer : WriterEvent gets raised at the start of the process.
Maatwebsite\Excel\Events\BeforeWriting$event->writer : WriterEvent gets raised before the download/store starts.
Maatwebsite\Excel\Events\BeforeSheet$event->sheet : SheetEvent gets raised just after the sheet is created.
Maatwebsite\Excel\Events\AfterSheet$event->sheet : SheetEvent gets raised at the end of the sheet process.

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

Writer / 写入

use \Maatwebsite\Excel\Writer;

Writer::macro('setCreator', function (Writer $writer, string $creator) {
    $writer->getDelegate()->getProperties()->setCreator($creator);
});

Sheet / 单元表

use \Maatwebsite\Excel\Sheet;

Sheet::macro('setOrientation', function (Sheet $sheet, $orientation) {
    $sheet->getDelegate()->getPageSetup()->setOrientation($orientation);
});

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

use \Maatwebsite\Excel\Sheet;

Sheet::macro('styleCells', function (Sheet $sheet, string $cellRange, array style) {
    $sheet->getDelegate()->getStyle($cellRange)->applyFromArray($style);
});

以上例子可作:

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.

测试下载

/**
* @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');
    });
}

测试存储导出

/**
* @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;
    });
}

测试队列导出

/**
* @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;
    });
}
查看原文

多厘 评论了文章 · 2019-03-24

[译] Laravel-Excel 3.0 文档

Basics

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

App/Exports 下创建一个 InvoicesExport

namespace App\Exports;

use Maatwebsite\Excel\Concerns\FromCollection;

class InvoicesExport implements FromCollection
{
    public function collection()
    {
        return Invoice::all();
    }
}

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

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

或者存储在 s3 磁盘中

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

依赖注入

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

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();
    }
}
public function export(Excel $excel, InvoicesExport $export) 
{
    return $excel->download($export, 'invoices.xlsx');
}

严格的 null 对比

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

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 下载

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

在磁盘上存储 collection

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

在磁盘上存储导出

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

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 方法.

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 直接进行类的下载

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

或者是存储到磁盘上.

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

Responsable / 可响应的

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

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() 方法.

return new InvoicesExport();

From Query / 从查询输出

在之前的例子中, 我们在导出类中进行查询, 当然这个解决方案可以用在小的导出类中. 对于更大一点数据的导出类可能造成比较大的性能开销.

通过使用 FromQuery 关系, 我们可以通过预查询一个导出, 这个场景实现的原理是查询可以分块执行.

InvoicesExport 类中,添加 FromQuery 关系, 并且添加一个查询, 并且确保不要使用 ->get() 来获取到数据!.

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();
    }
}

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

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

自定义查询

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

作为构造器参数

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 参数可以传递给导出类.

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

作为设置项

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 方法来调整年份.

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

通过视图

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

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:

<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>

队列

如果你处理更大数据量的数据, 很明智的方法就是使用队列来运行.

例如下边的导出类:

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() 方法即可.

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

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

另一种方式的队列实现

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

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:你需要首先自行配置队列]

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

追加任务 / jobs

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

return (new InvoicesExport)->queue('invoices.xlsx')->chain([
    new NotifyUserOfCompletedExport(request()->user()),
]);
namespace App\Jobs;

use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;

class InvoiceExportCompletedJob implements ShouldQueue
{
    use Queueable;

    public function handle()
    {
        // Do something.
    }
}

自定义队列

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

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

多单元表

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

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 可以实现多种关系. 例如 FromQueryFromCollection, ...

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 单元表来显示每个月的数据.

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

数据遍历

遍历行

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


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 约束来实现. 表头会添加到所有数据的第一行的位置上.


use Maatwebsite\Excel\Concerns\FromQuery;
use Maatwebsite\Excel\Concerns\WithHeadings;

class InvoicesExport implements FromQuery, WithHeadings

    public function headings(): array
    {
        return [
            '#',
            'Date',
        ];
    }
}

格式化列

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

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() 来正确的解析你的日期数据.

导出关系

InterfaceExplanation
Maatwebsite\Excel\Concerns\FromCollectionUse a Laravel Collection to populate the export.
Maatwebsite\Excel\Concerns\FromQueryUse an Eloquent query to populate the export.
Maatwebsite\Excel\Concerns\FromViewUse a (Blade) view to to populate the export.
Maatwebsite\Excel\Concerns\WithTitleSet the Workbook or Worksheet title.
Maatwebsite\Excel\Concerns\WithHeadingsPrepend a heading row.
Maatwebsite\Excel\Concerns\WithMappingFormat the row before it's written to the file.
Maatwebsite\Excel\Concerns\WithColumnFormattingFormat certain columns.
Maatwebsite\Excel\Concerns\WithMultipleSheetsEnable multi-sheet support. Each sheet can have its own concerns (except this one).
Maatwebsite\Excel\Concerns\ShouldAutoSizeAuto-size the columns in the worksheet.
Maatwebsite\Excel\Concerns\WithStrictNullComparisonUses strict comparisions when testing cells for null value.
Maatwebsite\Excel\Concerns\WithEventsRegister events to hook into the PhpSpreadsheet process.

Traits

TraitExplanation
Maatwebsite\Excel\Concerns\ExportableAdd download/store abilities right on the export class itself.
Maatwebsite\Excel\Concerns\RegistersEventListenersAuto-register the available event listeners.

扩展

事件

导出过程有一些事件,你可以利用这些事件与底层类进行交互,以向导出添加自定义行为。

通过使用事件,您可以连接到父包。如果你需要完全控制导出,则不需要使用诸如 "query" 或者 "view" 之类的便利方法。

事件将通过添加 WithEvents 关注来激活。在 registerEvents 方法中,你必须返回一系列事件。Key 是事件的完全限定名(FQN),Value 是可调用的事件监听器。这可以是一个闭包、可调用的数组 或 invokable 类。

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 。只有在创建方法时,侦听器才会被注册。

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 namePayloadExplanation
Maatwebsite\Excel\Events\BeforeExport$event->writer : WriterEvent gets raised at the start of the process.
Maatwebsite\Excel\Events\BeforeWriting$event->writer : WriterEvent gets raised before the download/store starts.
Maatwebsite\Excel\Events\BeforeSheet$event->sheet : SheetEvent gets raised just after the sheet is created.
Maatwebsite\Excel\Events\AfterSheet$event->sheet : SheetEvent gets raised at the end of the sheet process.

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

Writer / 写入

use \Maatwebsite\Excel\Writer;

Writer::macro('setCreator', function (Writer $writer, string $creator) {
    $writer->getDelegate()->getProperties()->setCreator($creator);
});

Sheet / 单元表

use \Maatwebsite\Excel\Sheet;

Sheet::macro('setOrientation', function (Sheet $sheet, $orientation) {
    $sheet->getDelegate()->getPageSetup()->setOrientation($orientation);
});

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

use \Maatwebsite\Excel\Sheet;

Sheet::macro('styleCells', function (Sheet $sheet, string $cellRange, array style) {
    $sheet->getDelegate()->getStyle($cellRange)->applyFromArray($style);
});

以上例子可作:

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.

测试下载

/**
* @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');
    });
}

测试存储导出

/**
* @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;
    });
}

测试队列导出

/**
* @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;
    });
}
查看原文

多厘 关注了专栏 · 2019-03-01

PHP面试

我叫琉忆,是《PHP程序员面试笔试宝典》、《PHP程序员面试笔试真题解析》的作者。本栏每周一三五更新,将会全面的带你去见识PHP的各类面试知识和真题,全面了解掌握PHP面试!

关注 178

多厘 发布了文章 · 2019-01-09

[译]使用Laravel访问前端Cookie

镜像地址: https://juejin.im/post/5c35c1...

在我们的应用程序中,我们可以在JS端设置cookie,但我们也希望在后端使用。我们可以使用$_COOKIE 全局魔术变量,但如果我们使用Laravel,我们会使用它提供的方法。让我们下Laravel中是如何使用的

在前端设置Cookie

在这篇文章中,我们关注现有的cookie。如果对如何从 JavasScript 处理它们感兴趣,请阅读文档

现在,假设我们有一个带有“ is-collapsed ”键的现有cookie 。我们想检查后端的值,以便在服务器端执行某些操作。

Laravel和Cookies

我们可以通过 request()->cookie() 方法或使用 Cookie Facade 来访问我们的cookie 。

问题是,如果我们想要访问我们在前端设置的 cookie,我们会得到 null。但是我们使用 $_COOKIE 变量,我们可以访问它,这证明 cookie 是存在的。那问题在什么地方呢?

默认情况下,框架带有用于加密cookie的中间件。如果我们从后端设置一个cookie,它会自动加密,因此Laravel可以读取它。从JS我们没有任何加密,这就是我们无法从框架中访问它们的原因。

如何解决这个问题?

app/Http/Kernel.php 中, 在 web 中间件分组中(5.2+),我们可以找到 EncryptCookies::class 行。通过注释这个中间件,可以关闭 cookie 的自动加密,但这种方法不是我们想要的解决方案。

建议的方法是使用中间件并添加一些不需要加密的排除项,Laravel无论怎样都应该访问它们。我们可以在 app/Http/Middlewares/EncryptCookies.php. 插入中间件的排除项。

/**
 * The names of the cookies that should not be encrypted.
 *
 * @var array
 */
protected $except = [
    'is-collapsed',
];

通过将 cookie 的名称添加到 except 数组,我们可以使用 Cookie Facade 或 request()->cookie() 方法读取cookie 。

如果您对更多信息感兴趣,请查看 文档  或查看有关 加密如何工作 的章节。

查看原文

赞 1 收藏 1 评论 0

多厘 关注了标签 · 2018-11-23

workerman

Workerman是一款纯PHP开发的开源高性能的PHP socket 服务器框架

http://www.workerman.net/

关注 111

多厘 收藏了文章 · 2018-10-30

Mac OS制作Ubuntu安装U盘

采用U盘安装Ubuntu系统是目前比较常见的安装方式之一,在Windows上有制作安装U盘的工具(比如Universal USB Installer),那么在Mac OS上面如何制作安装U盘呢?
答案是命令行!

hdiutil

第一步,需要到Ubuntu下载需要的Ubuntu的安装文件。
然后就需要使用第一个命令hdiutil
hdituil:是一个Mac OS上面处理镜像文件的命令,可以对镜像文件进行制作,验证和转换等...
我们知道DMG格式是Mac OS上常用的打包格式文件,需要把下载的Ubuntu安装文件(.iso)转换成(.dmg)格式的文件,方便在Mac OS上面进行操作,转换命令:

cd Downloads/
hdiutil convert -format UDRW -o ubuntu.iso ubuntu-14.04.5-desktop-amd64.iso

-format为生成文件的权限,UDRW :表示转换成有read/write的权限的镜像。
等待转换完成即可~

diskutil

第二步需要需要对U盘进行操作,而diskutil就是用来对Mac OS的磁盘操作的命令。
diskutil:操作本地磁盘,可以对磁盘进行卸载,挂载等操作。
列出当前挂载的磁盘:

diskutil list

dev/disk0 (internal, physical):
   #:                       TYPE NAME                    SIZE       IDENTIFIER
   0:      GUID_partition_scheme                        *251.0 GB   disk0
   1:                        EFI EFI                     209.7 MB   disk0s1
   2:          Apple_CoreStorage Macintosh HD            250.1 GB   disk0s2
   3:                 Apple_Boot Recovery HD             650.0 MB   disk0s3
/dev/disk1 (internal, virtual):
   #:                       TYPE NAME                    SIZE       IDENTIFIER
   0:                  Apple_HFS Macintosh HD           +249.8 GB   disk1
                                 Logical Volume on disk0s2
                                 45CD1187-14DE-4203-9895-FBB1B3770F1E
                                 Unencrypted
/dev/disk2 (external, physical):
   #:                       TYPE NAME                    SIZE       IDENTIFIER
   0:     Apple_partition_scheme                        *8.1 GB     disk2
   1:        Apple_partition_map                         4.1 KB     disk2s1
   2:                  Apple_HFS                         2.4 MB     disk2s2

其中/dev/disk2就是U盘。
需要先卸载掉U盘,然后在把安装文件写入到U盘中,这样就需要用到卸载命令:

diskutil unmountDisk /dev/disk2

再次使用diskutil list命令就不会显示出disk2了。

dd

第三步,把安装文件写入U盘,这里需要使用命令dd
dd:是Unix类Unix系统上的命令,作用就是用指定大小的块拷贝一个文件,并在拷贝的同时进行指定的转换。

在进行拷贝之前,还需要做的一件时间,因为使用hdiutil转换的文件后缀名为.dmg,所以需要把文件重命名为.iso,在安装的时候系统才能够更好的识别。

mv ubuntu.iso.dmg ubuntu.iso

然后把安装文件拷贝到U盘中

sudo dd if=./ubuntu.iso of=/dev/rdisk2 bs=1m

这行命令必须使用root权限,

  • if:输入的文件名

  • of:输出的文件名

  • bs:是块大小,这里使用1m的块大小。
    漫长的等待....

1052+1 records in
1052+1 records out
1104052224 bytes transferred in 249.471583 secs (4425563 bytes/sec)

操作完成之后,安全地拔出U盘

sudo eject /dev/rdisk2

可以使用U盘进行Ubuntu的安装了!

销毁安装数据

安装完成之后,U盘上面的安装文件还在,这样会影响我们正常使用U盘。可以把U盘格式化一次,清除数据,也可以使用dd命令销毁磁盘数据:

sudo dd if=/dev/urandom of=/dev/rdisk2

使用随机数填充U盘,可以用来销毁数据,一般用于重要数据否则没有必要使用随机数填充。

查看原文

认证与成就

  • 获得 148 次点赞
  • 获得 20 枚徽章 获得 0 枚金徽章, 获得 2 枚银徽章, 获得 18 枚铜徽章

擅长技能
编辑

开源项目 & 著作
编辑

  • 猎象电竞

    猎象电竞做最美的陪玩平台...... 电子竞技行业陪玩服务平台

  • 产品大牛

    PMdaniu是一个服务于产品经理、设计师等职业的云端协作工作平台 . 与数万的同行一起托管原型,撰写文档,管理项目,构建高效工作体系 , 作品参考、讨论交流融入社交元素,变革职业成长方式

  • 导航湾

    导航湾 是一个网址导航分享社区, 你可根据工作, 职业, 兴趣等方面创建日常所需的工具、网站、资源的链接,将它们汇集起来,分享给身边的朋友

  • 易代练

    易代练是一款专注代练行业的第三方交易服务平台

  • 易代练 - H5

    易代练手机版是一款专注代练行业的第三方交易服务平台在手机上的实现

  • Wulihub

    WuliHub中国站是服务于中国用户的网盘式的静态页面托管平台,可托管由软件导出的HTML文件或代码编写的静态HTML,简单且好用,像网盘管理所有托管的HTML

注册于 2013-10-17
个人主页被 1.8k 人浏览