首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >获取相关数据

获取相关数据
EN

Stack Overflow用户
提问于 2019-05-10 06:59:17
回答 1查看 0关注 0票数 0

我正在学习Laravel,非常初学。所以,这个想法是实现slugurl。有Category模特。该模型可以拥有无​​限数量的slu .. 如果我要求最后一个,我会得到合适的页面。如果我请求另一个slug(oblolete),我将301重定向到最后一个。

类别是父子层次结构模型。我需要与CategorySlug模型一对一的关系,因为我不关心所有以前的slug值。

迁移:

代码语言:javascript
复制
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');
        });
    }
}
代码语言:javascript
复制
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');
        });
    }
}

楷模:

代码语言:javascript
复制
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);
    }
}
代码语言:javascript
复制
class CategorySlug extends Model
{
    /**
     * @return App\Category
     */
    public function category() {
        return $this->belongsTo('App\Category', 'category_id', 'id')->with('slug');
    }

}

当我在控制器中运行下一个代码时,我希望每个代码Category都有fill slug属性。

代码语言:javascript
复制
$categories = Category::where('parent_id', null)->with('children', 'slug')->get();

但事实上,只有第一个有适当的slug。其他人的slug属性等于null。所有children属性都加载正常。

我将源代码放到GitHub存储库中。除其他外,还有种子文件。

更新:感谢@ marlon-ferreira我做了一些更改:

代码语言:javascript
复制
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')

EN

回答 1

Stack Overflow用户

发布于 2019-05-10 16:07:36

仅返回所有类别树(根和子项)的最后一个SlugCategory

这是我的建议:

关于分类模型:

代码语言:javascript
复制
public function slug() {
    return $this->hasMany('App\CategorySlug', 'category_id', 'id')->latest();
}
  1. 你按原样设置了slug关系:一对多(Category hasMany Slugs);
  2. 您调用该latest()方法只为您提供最新的slug。

使用这种方法,当您调用slug()关系时,它只会检索最新的CategorySlug记录。

关于分类模型:

代码语言:javascript
复制
public function children() {
    return $this->hasMany('App\Category', 'parent_id', 'id')->
            orderBy('order')->
            with('children', 'slug');
}

所以,这个控制器调用......

代码语言:javascript
复制
$categories = Category::where('parent_id', null)->with('children', 'slug')->get();

...将仅返回主类别(parent_id = null)的最新slug,以及所有子级的slug。

警告 - 无限渴望加载

在我为您提供了解决方案之后,我想谈谈通常许多Laravel / Eloquent开发人员不知道的事情。

基本上,你正在创造一个无限的渴望加载。让我向你解释一下:

这是您的分类模型及其关系:

代码语言:javascript
复制
Categories => Categories (children)
           => CategorySlug (slug)

这是你的CategorySlug模型及其关系:

代码语言:javascript
复制
CategorySlug => Category
  1. 您使用返回Category模型的方法创建了CategorySlug模型。
  2. 在同一个方法中,您使类别关系返回WITH关联的slug。

由于您的CategorySlug模型上的WITH定义,实际上,您只是重新检索相同的CategorySlug模型。

这没有意义,而且创造了无限的急切加载。示例说明:

代码语言:javascript
复制
Category::find(1)->slug();

这里会发生什么:

代码语言:javascript
复制
category will load slug -> slug will load category -> category will load slug -> ...

这是一个无限的渴望加载。它将导致数据库超时异常。

要避免它,只需删除withCategorySlug模型。

根据我的观点,这没有必要。

如果您的要求发生变化,请告诉我,您确实需要这种反向关系。

技巧和额外的知识

  • 最古老和最新的方法

有两种方法可以让您只检索最旧或最新的记录。例:

代码语言:javascript
复制
$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

  • 范围策略用法

范围是创建自定义可重用实现的好方法。

假设您的控制器实现,我们可以在以下情况下应用范围:

关于分类模型 -

代码语言:javascript
复制
class Category extends Model
{
    ...

    public function scopeWithoutParent($query) {
        return $query->whereNull('parent_id');
    }
}

控制器 -

代码语言:javascript
复制
$categories = Category::withoutParent()->with('children', 'slug')->get();
  • 永远渴望加载你的人际关系

这可能是您可以在项目中使用的技巧。

基本上,你可以强制雄辩地加载关系,而无需显式调用它。

关于分类模型 -

代码语言:javascript
复制
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();
    }

控制器 -

代码语言:javascript
复制
$categories = Category::withoutParent()->get();

如您所见,您不必再显式调用该关系。

希望这会有所帮助。

祝你有美好的一天。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/-100006711

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档