我正在学习Laravel,非常初学。所以,这个想法是实现slug
url。有Category
模特。该模型可以拥有无限数量的slu .. 如果我要求最后一个,我会得到合适的页面。如果我请求另一个slug(oblolete),我将301重定向到最后一个。
类别是父子层次结构模型。我需要与CategorySlug
模型一对一的关系,因为我不关心所有以前的slug值。
迁移:
class CreateCategoriesTable extends Migration
{
public function up()
{
Schema::create('categories', function (Blueprint $table) {
$table->bigIncrements('id');
$table->string('title');
});
Schema::table('categories', function (Blueprint $table) {
$table->unsignedBigInteger('parent_id')->nullable()->after('id');;
$table->foreign('parent_id')->references('id')->on('categories')->onUpdate('cascade')->onDelete('cascade');
});
}
}
class CreateCategoriesSlugTable extends Migration
{
public function up()
{
Schema::create('categories_slug', function (Blueprint $table) {
$table->bigIncrements('id');
$table->string('value')->unique()->index()->nullable(false);
$table->timestamp('created_at')->useCurrent();
});
Schema::table('categories_slug', function (Blueprint $table) {
$table->unsignedBigInteger('category_id')->nullable()->after('id');
$table->foreign('category_id')->references('id')->on('categories')->onUpdate('cascade')->onDelete('cascade');
});
}
}
楷模:
class Category extends Model
{
public function children() {
return $this->hasMany('App\Category', 'parent_id', 'id')->
orderBy('order')->
with('children');
}
public function slug() {
return $this->hasOne('App\CategorySlug', 'category_id', 'id')->
orderBy('created_at', 'desc')->limit(1);
}
}
class CategorySlug extends Model
{
/**
* @return App\Category
*/
public function category() {
return $this->belongsTo('App\Category', 'category_id', 'id')->with('slug');
}
}
当我在控制器中运行下一个代码时,我希望每个代码Category
都有fill slug
属性。
$categories = Category::where('parent_id', null)->with('children', 'slug')->get();
但事实上,只有第一个有适当的slug
。其他人的slug属性等于null。所有children
属性都加载正常。
我将源代码放到GitHub存储库中。除其他外,还有种子文件。
更新:感谢@ marlon-ferreira我做了一些更改:
class Category extends Model
{
...
public function slug() {
return $this->hasOne('App\CategorySlug', 'category_id', 'id')->latest();
}
}
现在,一切正常!我更喜欢使用hasOne
因为我不喜欢写$category->slug[0]->value
而不是$category->slug->value
。好吗?
为什么我不能取代latest()
的limit(1) + orderBy('created_at')
?
发布于 2019-05-10 16:07:36
这是我的建议:
关于分类模型:
public function slug() {
return $this->hasMany('App\CategorySlug', 'category_id', 'id')->latest();
}
latest()
方法只为您提供最新的slug。使用这种方法,当您调用slug()
关系时,它只会检索最新的CategorySlug记录。
关于分类模型:
public function children() {
return $this->hasMany('App\Category', 'parent_id', 'id')->
orderBy('order')->
with('children', 'slug');
}
所以,这个控制器调用......
$categories = Category::where('parent_id', null)->with('children', 'slug')->get();
...将仅返回主类别(parent_id = null)的最新slug,以及所有子级的slug。
在我为您提供了解决方案之后,我想谈谈通常许多Laravel / Eloquent开发人员不知道的事情。
基本上,你正在创造一个无限的渴望加载。让我向你解释一下:
这是您的分类模型及其关系:
Categories => Categories (children)
=> CategorySlug (slug)
这是你的CategorySlug模型及其关系:
CategorySlug => Category
由于您的CategorySlug模型上的WITH定义,实际上,您只是重新检索相同的CategorySlug模型。
这没有意义,而且创造了无限的急切加载。示例说明:
Category::find(1)->slug();
这里会发生什么:
category will load slug -> slug will load category -> category will load slug -> ...
这是一个无限的渴望加载。它将导致数据库超时异常。
要避免它,只需删除with
CategorySlug模型。
根据我的观点,这没有必要。
如果您的要求发生变化,请告诉我,您确实需要这种反向关系。
有两种方法可以让您只检索最旧或最新的记录。例:
$categories = Category::where('is_active', true); // we have many categories here
$last_created_category = $categories->latest(); // latest category created
$old_updated_category = $categories->oldest('updated_at'); // oldest category updated
两种方法都接受字符串作为参数,以识别必须对哪个字段进行排序。
默认是created_at
。
范围是创建自定义可重用实现的好方法。
假设您的控制器实现,我们可以在以下情况下应用范围:
关于分类模型 -
class Category extends Model
{
...
public function scopeWithoutParent($query) {
return $query->whereNull('parent_id');
}
}
控制器 -
$categories = Category::withoutParent()->with('children', 'slug')->get();
这可能是您可以在项目中使用的技巧。
基本上,你可以强制雄辩地加载关系,而无需显式调用它。
关于分类模型 -
class Category extends Model
{
...
protected $with = [ 'children', 'slug' ];
public function children() {
return $this->hasMany('App\Category', 'parent_id', 'id')->orderBy('order');
}
public function slug() {
return $this->hasMany('App\CategorySlug', 'category_id', 'id')->latest();
}
控制器 -
$categories = Category::withoutParent()->get();
如您所见,您不必再显式调用该关系。
希望这会有所帮助。
祝你有美好的一天。
https://stackoverflow.com/questions/-100006711
复制相似问题