Laravel Framework 13.x

Typesense 的语义与混合搜索

拉取请求由 @tharropoulos 提交

Scout 的 Typesense 引擎现已支持 semantic() 和 hybrid() 搜索。模型嵌入设置可以利用 Laravel AI 从 toSearchableEmbedding() 生成向量,也可以使用 Typesense 的原生自动嵌入功能;同时也支持预计算向量。应用程序可以仅通过含义进行搜索,也可以通过 Scout 构建器将语义匹配与文本结果相结合。

可靠的 MariaDB 向量查询与 Eloquent 向量转换

拉取请求由 @eas4ai 提交

MariaDB 向量距离查询现在会使用 vec_fromtext() 转换绑定向量,修复了使用 whereVectorSimilarTo() 和 orderByVectorDistance() 等方法时的 SQL 错误。新的 AsVector Eloquent 转换可以将 MariaDB 的二进制向量或 PostgreSQL 兼容的文本向量读取为浮点数数组,并在写入时接受数组或 Arrayable 值。

use Illuminate\Database\Eloquent\Casts\AsVector;
use Illuminate\Database\Eloquent\Model;

class Document extends Model
{
    protected $casts = [
        'embedding' => AsVector::class,
    ];
}

在磁盘间复制或移动文件

拉取请求由 @jackbayliss 提交

文件系统磁盘现在提供 copyToDisk() 和 moveToDisk(),用于将文件传输到另一个已配置的磁盘,并且可以选择指定新路径。这两种方法都会对文件进行流式处理并关闭流;moveToDisk() 仅在复制成功后才会删除源文件。

use Illuminate\Support\Facades\Storage;

Storage::disk('local')->copyToDisk('s3', 'reports/report.csv', 'archive/report.csv');
Storage::disk('local')->moveToDisk('backup', 'reports/report.csv');

选择开发期间运行的命令

拉取请求由 @jackbayliss 提交

应用程序现在可以使用 DevCommands::withoutVendorCommands() 和 DevCommands::withoutDefaultCommands(),从 php artisan dev 中排除 vendor 提供或框架默认的开发命令。这使项目能够保留自己的开发命令,而无需维护每个 vendor 和默认命令名称的列表。

Laravel Echo 中的 Mercure 广播

拉取请求由 @dunglas 提交

Laravel Echo 现在内置了一个基于浏览器原生 EventSource API 的 Mercure 连接器,无需单独的客户端库。它支持私有、在线状态以及加密频道,同时支持悄悄话。Hub URL 默认为当前源下的 /.well-known/mercure,React、Vue 和 Svelte 集成可以通过 VITE_MERCURE_HUB_URL 进行配置。

按相邻值分块集合

拉取请求由 @JosephSilber 提交

新的 chunkBy() 方法会在所选值发生变化时拆分集合和惰性集合。与 groupBy() 不同,它只对连续的匹配项进行分组:具有相同键但后续出现的值将形成单独的数据块。传入属性名称或回调函数以选择要比较的值。

collect([1, 1, 2, 2, 1])->chunkBy(fn ($value) => $value);
// [[1, 1], [2, 2], [1]]

一次性邮件和通知断言

拉取请求由 @talaridisTh 提交

邮件和通知的模拟对象现在提供了针对应恰好发生一次的事件的断言:Mail::assertSentOnce()、Mail::assertQueuedOnce()、Notification::assertSentToOnce() 以及 Notification::assertSentOnDemandOnce()。这些是对应 ...Times(..., 1) 断言的更简洁替代方案。

使用集合和数组对象转换存储 SQL NULL

拉取请求由 @zeinrahmad76 提交

AsCollection::nullable() 和 AsArrayObject::nullable() 现在可在属性设置为 null 时选择存储原生 SQL NULL,从而使 whereNull() 等查询能够匹配到该值。除非选择了可空变体,否则现有的转换将保持其原有行为,即存储 JSON "null" 值。

use Illuminate\Database\Eloquent\Casts\AsCollection;
use Illuminate\Database\Eloquent\Model;

class Order extends Model
{
    protected $casts = [
        'items' => AsCollection::nullable(),
    ];
}

请求原地修改 MySQL 索引

拉取请求由 @SanderMuller 提交

MySQL 架构迁移现在可以将 inplace() 链式调用到索引和外键定义中,以请求 ALGORITHM=INPLACE。结合现有的 lock('none') 选项,这允许迁移明确请求一个干扰性更小的 DDL 操作,而不是默默接受不同的算法;MySQL 可能会拒绝在上述约束下无法执行的操作。

use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

Schema::table('video_sessions', function (Blueprint $table) {
    $table->index('video_id')->inplace()->lock('none');
});

将 Worker 崩溃计入作业的异常限制

拉取请求由 @williamjulianvicary 提交

作业可以使用 #[CountCrashesAsExceptions] 特性或 $countCrashesAsExceptions 属性,选择将意外终止的 worker 尝试计入 maxExceptions。这有助于防止作业在崩溃或被外部强制终止 worker 后无限重试;正常完成和由 worker 管理的超时不计入崩溃。该功能通过缓存标记来识别已开启此功能的作业。

AI

基于运行时配置构建 AI 提供商

拉取请求由 @pushpak1300 提交

Ai::build() 可根据配置数组创建提供商,而不会更改应用程序已配置的提供商。这支持运行时加载的凭据,例如特定租户的密钥,并且允许将构建的提供商添加到故障转移列表中。对于排队代理,应在代理的 provider() 方法中构建提供商,以便 worker 能够重新创建它,而不是仅在调用处进行构建。

use Laravel\Ai\Ai;

$agent->prompt($text, provider: [
    Ai::build(['driver' => 'anthropic', 'key' => $tenant->ai_key]),
]);

Horizon

Horizon 中的对数队列自动扩缩容

拉取请求由 @Gummibeer 提交

Horizon 监控器现在可以使用 log 自动扩缩容策略,与 time 和 size 策略并列。它会以对数方式对队列积压情况进行加权,降低一个过大的队列占用几乎所有可用 worker 的概率。当保持较小队列正常运转比最大化最大积压队列的吞吐量更重要时,此功能非常有用。

Scout

在 Scout 中使用 Meilisearch 的原生嵌入器

拉取请求由 @Strift 提交

Scout 的 Meilisearch 引擎现在可以为 semantic() 和 hybrid() 查询使用 Meilisearch 自带的嵌入器,只需将模型的嵌入 driver 设置为 meilisearch 并提供一个 embedder。随后,Meilisearch 将生成文档和查询的嵌入向量,而通过 options(['vector' => ...]) 传入的向量可以覆盖查询嵌入。默认的 laravel-ai 驱动程序保持不变。