Laravel 扩展 - Seeder 填充数据生成

Laravel 框架支持 db:seed 来填充表。相对应的,需要自己编写 DatabaseSeeder.php 文件。 如果填充文件行数少,或者可以利用工厂类生成会很方便。
但是有些数据是需要手动填写与组合的。例如:目录的组织,权限的组织,通用配置的组织。数据大,改动多,不易组织。

nuyfeng/make-database 可以直接通过数据库来生成 Seeder 文件,省去的繁琐的复制。

GITHUB: make-database

1
2
3
4
5
6
7
8
9
10
11
12
13
composer require --dev nuyfeng/make-database   //安装扩展

php artisan database:build-seeder --help

Description:
根据数据库生成 seeder 数据

Usage:
database:build-seeder [options]

Options:
--max-rows[=MAX-ROWS] 表允许最大的行数,超过此值跳过生成. 0为不限制 [default: "100"]
--tables[=TABLES] 指定生成数据表表列表 example users,sites,logs

DcatAdmin 表头固定

DcatAdmin 默认不提供固定表头的功能,可以通过自定义 CSS 来实现
本 CSS 来自 DcatAdmin 项目中另一个地方的样式。

将代码直接贴在需要固定表头的 Grid 即可。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
Admin::style(<<<STYLE
thead tr:nth-child(1) th {
background-color: #fff;
position: sticky;
top: 60px; // 顶部 Banner
z-index: 10;
}
thead tr:nth-child(2) th {
background-color: #fff;
border-bottom: 0;
position: sticky;
top: 101px; //手动计算的
z-index: 10;
}
STYLE
);

其中 top 是我手动计算的,可能要根据实际高度自行修改。或者有自适应的方法也欢迎提供。
效果如题所示:

Snipaste_2022-03-31_14-22-34.png

Laravel POST 参数过多引发的 405错误

Laravel 中,更新一个资源应该使用 PUT 方法。但是在实现中, FORM 表单只支持 POST,GET 方法,在其中添加 _method 字段让 Laravel 将请求当作 PUT,DELETE等字段。


今天正常运行的系统突然无法更新数据,HTTP STATUS 405 提示信息为:

1
The POST method is not supported for this route. Supported methods: GET,HEAD,PUT,PATCH,DELETE.

由于这个错误提示的误导,我一直以为是路由出了问题,往这方面排查了挺长时间。
最终通过查看站点日志,发现 PHP 报错了:

1
FastCGI sent in stderr: "PHP message: PHP Warning:  Unknown: Input variables exceeded 1000. To increase the limit change max_input_vars in php.ini. in Unknown on line 0" while reading response header from upstream

到此问题就很清楚了,报错的表单中有很多 checkbox 导致处于表单末尾的 _method 因为默认最大提交限制为 1000 的问题无法被系统接收到,从而导致系统无法根据 _method 项来用 PUT 方式处理 POST 请求。

处理方法也很简单,在 php.ini 中修改 max_input_vars 的值即可。记得要去掉配置项前面的 ; 符号,不然不会生效(我第一次更改后还是报错,以为不是这里的问题,检查后才发现值虽然改了,但是默认是注释状态)。

PHP8 - Named arguments 与 Constructor property promotion

PHP8 已于 2020-11-26 发布,这次带来了我们期待已久的 JIT 。但这篇文章主要讲讲新特性的理解与使用。

Named arguments

我们会在函数参数列表中使用默认值:

1
2
3
function setUser(int $age, string $name, string $money = "0.00", int $sex = 0, $job = null)
{
}

以前当我们想要使用 $money 的默认值并设置 $sex 的值时:

1
setUser(12,"Lilin", "0.00", 1);

$money 的值被我们显式的设置了,似乎使函数声明中的默认值“浪费了”
在 PHP8 中,我们可以根据参数名来设置参数的值:

1
setUser(12,name:"Lilin", sex:1);

我们可以通过指定参数名来设置对应的参数值,这么做的好处不仅仅可以使我们更方便的使用预设的默认值.代码不是一成不变的,在某一天我们需要维护上个月的代码,如果我遇到了这样的函数调用:

1
getUserWith($userId, true, 5, 100, today(), true)

我想我的内心一定是崩溃的,我可以根据经验推断出 $userId 是用户 ID , today() 是根据今天的日期搜索。但是有两个 true , 这似乎需要阅读参数列表才能判断出来。
如果使用命名参数,情况就会变成这样:

1
getUserWith(userId:$userId, emailVerify:true, limit:5, offset:100, time:today(), telphoneVerify:true)

Constructor property promotion

以前我们在对象初始化时,往往这样操作:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class Point {
public float $x;
public float $y;
public float $z;
public function __construct(
float $x = 0.0,
float $y = 0.0,
float $z = 0.0
) {
$this->x = $x;
$this->y = $y;
$this->z = $z;
}
}

现在我们可以在构造函数中完成这一切:

1
2
3
4
5
6
7
class Point {
public function __construct(
public float $x = 0.0,
public float $y = 0.0,
public float $z = 0.0,
) {}
}

与 Named arguments 配合,我们的函数初始化将变得十分简洁:
new Point(z:1.0)


PHP8官网介绍页

PHP RFC: Named Arguments

CodeIgniter4 日期自动更新 useTimestamps

在 CodeIgniter4 中,如果想要 Model 在创建及更新数据时自动更新对应的日期字段,可以使用 useTimestamps。但是有很多人会遇到遇到一些问题,其中最主要的问题是数据库字段与数据内容不匹配导致的。我们在设置了 $useTimestamps = true 后,往往忽略了与之配套使用的字段 dateFormat

一般的,我们在数据库中存储时间使用时间戳,我一般设置为 int UNSIGNED。大多人也是如此,在 CI4 中 dateFormat 的默认值为 datetime

1
2
3
4
5
6
7
8
9
case datetime:
$converted = $value->format(Y-m-d H:i:s);
break;
case date:
$converted = $value->format(Y-m-d);
break;
case int:
$converted = $value->getTimestamp();
break;

默认的日期格式为 2020-05-09 12:12:12 如果我们的数据会为 int 则数据会存储被为 2020 ,后边的信息无法存储。
所以我们需要将日期格式设置为 $dateFormat = int

CodeIgniter4 useSoftDeletes 软删除

做数据删除的时候,我们往往会用到软删除。CI4对这一功能进行了支持。

CI4 使用 deleted_at 字段是否为 NULL 来判断是数据是否被删除。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<?php namespace App\Models;

use CodeIgniter\Model;

class UserModel extends Model
{
protected $table = users;
protected $primaryKey = id;

protected $returnType = array;
protected $useSoftDeletes = true;

protected $allowedFields = [name, email];

protected $useTimestamps = false;
protected $createdField = created_at;
protected $updatedField = updated_at;
protected $deletedField = deleted_at;

protected $validationRules = [];
protected $validationMessages = [];
protected $skipValidation = false;
}

如果 useSoftDeletes 设置为 true, 则所有数据结果默认排除掉已经删除的数据,具体的做法是会在 SQL 语句中增加 deleted_at IS NULL 来进行数据的过滤。

有很多人在 GITHUB 发 ISSUES 表示自己的 useSoftDeletes 无法正常工作,实际上是因为我们默认习惯将 deleted_at 默认设置为 int, DEFAILT 0, NOT NULL。我们需要让 deleted_at 允许 NULL 并且默认为 NULL 。这样我们才能使用 useSoftDelets

如果我们希望返回的数据临时包括已删除的数据, 我们可以使用 withDeleted

如果我们希望返回的数据只包括已删除的数据,我们可以使用 onlyDeleted

CodeIgniter4 CORS 跨域问题

当使用前后端分离,并且前端后端域名不统一时,我遇到了跨域的问题

1
Access to XMLHttpRequest at http://localhost/api/login from origin http://localhost:8010 has been blocked by CORS policy: Response to preflight request doesnt pass access control check: NoAccess-Control-Allow-Origin header is present on the requested resource.```
1
Access to XMLHttpRequest at http://localhost/api/login from origin http://localhost:8010 has been blocked by CORS policy: Request header field content-type is not allowed by Access-Control-Allow-Headers in preflight response.

我们只需要在返回的 response 中添加 header就可以了

首先我们创建一个 Filter 用来批量在生成的 response 中添加 headers

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
App\Filters\Api.php
<?php
namespace App\Filters;

use CodeIgniter\Filters\FilterInterface;
use CodeIgniter\HTTP\RequestInterface;
use CodeIgniter\HTTP\ResponseInterface;

class Api implements FilterInterface
{
public function before(RequestInterface $requset)
{

}

public function after(RequestInterface $request, ResponseInterface $response)
{
$response->setHeader(Access-Control-Allow-Origin, *);
$response->setHeader(Access-Control-Allow-Headers, Content-Type);
return $response;
}
}

接下来我们将注册并配置 App\Filters\Api::class, 编辑配置文件 App\Config\Filters.php

1
2
3
4
5
6
7
8
...
public $aliases = [
csrf => \CodeIgniter\Filters\CSRF::class,
toolbar => \CodeIgniter\Filters\DebugToolbar::class,
honeypot => \CodeIgniter\Filters\Honeypot::class,
api => \App\Filters\Api::class, //注册 Filter
];
...

配置该 filter 对哪些 uri 生效

public $filters = [
        api => [
            after =>[
                api/*,
            ]
        ]
    ];

至此,在每个路径为 api/* 的请求返回前,就会执行 after 中的代码,添加 headers

[typecho 插件] GoogleRecaptcha

typecho_GoogleRecaptcha

为 Typecho Admin 开启Google invisible Recaptcha 验证

开启 Google reCAPTCHA

前往 Google reCAPTCHA 开启 reCAPTCHA 并 获取参数

  1. 选择 Invisible reCAPTCHA ,填写 Domains 进行注册
  2. 获取 Site key & Secret key
    <https://i.loli.net/2018/01/09/5a5413230deab.png

插件配置

将 Site Key & Secret Key 填入对应的配置项

配置加载 JS 使用的地址

配置后端验证 response 使用的地址

Github