返回

Laravel 中“Call to a member function prepare() on null”错误:原因与解决方案

php

解决 Laravel 中“Call to a member function prepare() on null”错误

在 Laravel 中使用 Sanctum 生成个人访问令牌时,开发人员可能会遇到 "Call to a member function prepare() on null" 错误。本文将深入探讨导致此错误的原因,并提供详细的解决方案。

错误原因

"Call to a member function prepare() on null" 错误通常由以下原因引起:

1. 模型关系未定义: 令牌模型与关联模型之间的关系未正确定义。

2. 数据库表不存在: 存储个人访问令牌的数据库表(personal_access_tokens)不存在或为空。

3. 迁移未运行: 用于创建 personal_access_tokens 表的数据库迁移尚未运行。

解决方案

为了解决此错误,需要采取以下步骤:

1. 检查模型关系

确保令牌模型与关联模型之间已定义关系。例如,如果令牌属于 User 模型,则在 User 模型中定义以下关系:

public function tokens()
{
    return $this->hasMany(Token::class);
}

2. 创建数据库表

确保已在数据库中创建 personal_access_tokens 表。可以运行以下迁移命令:

php artisan migrate

或者手动创建表:

CREATE TABLE personal_access_tokens (
    id INT NOT NULL AUTO_INCREMENT,
    tokenable_id INT NOT NULL,
    tokenable_type VARCHAR(255) NOT NULL,
    name VARCHAR(255) NOT NULL,
    token VARCHAR(64) UNIQUE NOT NULL,
    abilities TEXT NULL,
    last_used_at TIMESTAMP NULL,
    created_at TIMESTAMP NOT NULL,
    updated_at TIMESTAMP NOT NULL,
    PRIMARY KEY (id),
    INDEX personal_access_tokens_tokenable_type_tokenable_id_index (tokenable_type, tokenable_id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

3. 使用命名范围

在使用 $user->createToken('token_base_name') 创建令牌时,Sanctum 会使用名为 findOrCreate 的命名范围在 personal_access_tokens 表中查找关联的令牌。确保已在令牌模型中定义此命名范围:

public function scopeFindOrCreate(Builder $query, $tokenable, string $name, string $abilities = '[]')
{
    $token = $query->where('tokenable_id', $tokenable->getKey())
        ->where('tokenable_type', get_class($tokenable))
        ->where('name', $name)
        ->first();

    if ($token) {
        $token->fill([
            'abilities' => $abilities,
            'last_used_at' => now(),
        ])->save();

        return $token;
    }

    return $tokenable->createToken($name, $abilities);
}

其他建议:

  • 确保 SanctumServiceProvider 已注册到 app.php 中。
  • 检查服务器日志以获取更多详细信息。
  • 尝试使用其他数据库驱动(例如 MySQL)测试问题是否仍然存在。

结论

通过遵循这些解决方案,开发人员可以解决 "Call to a member function prepare() on null" 错误,并成功在 Laravel 中生成个人访问令牌。

常见问题解答

1. 为什么需要 findOrCreate 命名范围?

findOrCreate 命名范围允许 Sanctum 在 personal_access_tokens 表中查找现有令牌,如果没有找到,则创建一个新令牌。

2. 如何查看 Sanctum 服务器日志?

Sanctum 服务器日志通常位于 storage/logs/sanctum.log 中。

3. 使用其他数据库驱动时需要注意什么?

使用其他数据库驱动时,需要确保 personal_access_tokens 表的架构与所使用的驱动兼容。

4. 如何解决迁移失败的问题?

如果迁移失败,可以检查迁移脚本是否存在语法错误,或者尝试重新运行迁移命令。

5. 为什么在创建令牌时指定 abilities 参数很重要?

abilities 参数允许开发人员限制令牌的权限。