sqlite Laravel添加列,默认值取决于第二列

mctunoxg  于 2023-03-03  发布在  SQLite
关注(0)|答案(3)|浏览(111)

我有一个用户表,我想通过导航/users/{slug}来查看每个用户。例如,对于名为John Doe的用户,路径将如下所示/users/john-doe。当前我正在使用id查看用户(/users/1)。要实现这一点,我可以只是迭代所有用户创建的鼻涕虫,并检查是否给定的鼻涕虫是相同的。如果我有几百个用户,效率就不高了,这需要时间。我想过增加一个新的列。

Schema::table('users', function (Blueprint $table) {
    $table->string('slug')->after('name');
});

问题是这样做行不通,因为该列需要一个默认值,而“默认”值取决于name的值。
我也可以只在Schema::create(...)函数中添加列并运行php artisan migrate:refresh。但这样我会失去所有其他用户。
有人有主意吗?

zbq4xfa0

zbq4xfa01#

我也做同样的事情slug是从name(或title等)列生成的,但我不在数据库中这样做。
创建User模型示例时,请设置slug,如下所示:

public function store(Request $request) {
  $request->merge(['slug' => Str::slug($request->input('name'))]);

  // Validate `$request`

  User::create($request);

  // OR

  $user = new User();
  $user->name = $request->input('name');
  $user->slug = Str::slug($user->name);
  $user->save();
}

此外,如果使用FormRequest,则可以执行以下操作:

public function store(MyFormRequest $request) { 
  User::create($request);
}

MyFormRequest.php内部:

class MyFormRequest extends FormRequest {
  protected function prepareForValidation() {
    $this->merge(['slug' => Str::slug($this->name)]);
  }

  public function rules() {
    // ...
  }
}

在您的情况下,由于您有一组现有用户,您需要运行类似以下的命令:

foreach(User::all() as $user) {
  $user->update(['slug' => Str::slug($user->name)]);
}

在运行迁移“回填”您的块之后。
侧记,小心依赖名字的蛞蝓;人没有唯一的名字,所以你可能会得到两个“John Doe”的鼻涕虫,这需要一些自定义的逻辑来区分它们。

ao218c7q

ao218c7q2#

实际上,您只需向用户模型添加一个resolveRouteBinding函数来解析模型。

/**
 * Retrieve the model for a bound value.
 *
 * @param  mixed  $value
 * @param  string|null  $field
 * @return \Illuminate\Database\Eloquent\Model|null
*/
public function resolveRouteBinding($value, $field = null)
{
    if ($field != null) {
        return parent::resolveRouteBinding($value, $field);
    } elseif (is_numeric($value)) {
        return parent::resolveRouteBinding($value, 'id');
    } else {
        return parent::resolveRouteBinding($value, 'slug');
    }
}

有了这个功能,Laravel会自动解析你的模型,如果给定的值是数字的话。
为了生成slug,我会使用一个Observer,它将slug设置在creating上。在将模型保存到数据库之前,你应该能够轻松地填充它。为了保持slug是最新的,你可以只使用observer的updating事件。

/**
 * Handle the User "creating" event.
 */
public function creating(User $user): void
{
    $user->slug = Str::slug($user->name);
}

对于第一次迁移,我会使用默认值或允许它为空,当您为每个用户初始设置slug时,可以在另一次迁移中更改它。
亚历克斯·比尔

edqdpe6u

edqdpe6u3#

在SQL中,通常不能设置"动态"默认值(取决于另一列),但可以设置列nullable,然后通过编程为现有行计算其值,最后将该列更改为not null
示例:

Schema::table('users', function (Blueprint $table) {
    $table->string('slug')->nullable()->after('name');
});

// Compute slug values

Schema::table('users', function (Blueprint $table) {
    $table->string('slug')->nullable(false)->change();
});

相关问题