Laravel 获取相关数据

Laravel 获取相关数据,laravel,eloquent,Laravel,Eloquent,我正在学习拉威尔,非常初级。因此,我们的想法是实现slugurl。有类别型号。该模型可以有无限多个段塞。如果我要求最后一页,我会得到合适的一页。如果我请求另一个slug(oblolete),我将获得301重定向到最后一个slug 类别是父子层次结构模型。我需要与CategorySlugmodel建立一对一的关系,因为我不关心以前所有的slug值 迁移: 类createCategateStable扩展了迁移 { 公共职能 { Schema::create('categories',函数(Bluep

我正在学习拉威尔,非常初级。因此,我们的想法是实现
slug
url。有
类别
型号。该模型可以有无限多个段塞。如果我要求最后一页,我会得到合适的一页。如果我请求另一个slug(oblolete),我将获得301重定向到最后一个slug

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

迁移:

类createCategateStable扩展了迁移
{
公共职能
{
Schema::create('categories',函数(Blueprint$表){
$table->bigIncrements('id');
$table->string('title');
});
Schema::table('categories',函数(Blueprint$table){
$table->unsignedBigInteger('parent_id')->nullable()->after('id');;
$table->foreign('parent_id')->references('id')->on('categories')->onUpdate('cascade')->onDelete('cascade');
});
}
}
class CreateCategoriesLugtable扩展了迁移
{
公共职能
{
Schema::create('categories_slug',函数(Blueprint$table){
$table->bigIncrements('id');
$table->string('value')->unique()->index()->nullable(false);
$table->timestamp('created_at')->useCurrent();
});
Schema::table('categories_slug',函数(Blueprint$table){
$table->unsignedBigInteger('category_id')->nullable()->after('id');
$table->foreign('category_id')->references('id')->on('categories')->onUpdate('cascade')->onDelete('cascade');
});
}
}
型号:

类类别扩展模型
{
公共职能儿童(){
return$this->hasMany('App\Category','parent\u id','id')->
orderBy('order')->
与(‘儿童’);
}
公共函数slug(){
返回$this->hasOne('App\CategorySlug','category\u id','id')->
orderBy('created_at','desc')->limit(1);
}
}
class CategorySlug扩展了模型
{
/**
*@return App\Category
*/
公共职能类别(){
返回$this->belongsTo('App\Category','Category\u id','id')->带('slug');
}
}
当我在控制器中运行下一个代码时,我希望每个
类别
都会填充
slug
属性

$categories = Category::where('parent_id', null)->with('children', 'slug')->get();
但事实上,只有第一个具有适当的
slug
。其他的slug属性等于null。所有
子属性
都加载良好

我将源代码放入存储库。除此之外,还有种子文件

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

类类别扩展模型
{
...
公共函数slug(){
返回$this->hasOne('App\CategorySlug','category_id','id')->latest();
}
}
现在,一切正常!我更喜欢使用
hasOne
,因为我不喜欢写
$category->slug[0]->value
而不是
$category->slug->value
。可以吗

为什么我不能将
latest()
替换为
limit(1)+orderBy('created_at')

只返回所有类别树(根目录和子目录)的最后一个类别 这是我的建议:

关于类别模型:

public function slug() {
    return $this->hasMany('App\CategorySlug', 'category_id', 'id')->latest();
}
public function children() {
    return $this->hasMany('App\Category', 'parent_id', 'id')->
            orderBy('order')->
            with('children', 'slug');
}
  • 按原样设置slug关系:一对多(类别有多个slug)
  • 调用
    latest()
    方法只提供最新的slug
  • 使用这种方法,当您调用
    slug()
    relationship时,它将只检索最新的CategorySlug记录

    关于类别模型:

    public function slug() {
        return $this->hasMany('App\CategorySlug', 'category_id', 'id')->latest();
    }
    
    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

    警告-无限渴望加载 在我向您提供了我的解决方案之后,我想谈谈一些通常很多Laravel/有口才的开发人员都不知道的事情

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

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

    Categories => Categories (children)
               => CategorySlug (slug)
    
    这是您的CategorySlug模型及其关系:

    CategorySlug => Category
    
  • 使用返回类别模型的方法创建CategorySlug模型

  • 在这个相同的方法中,您使用关联的slug返回您的类别关系

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

    这是没有意义的,而且会产生无限的渴望加载。示例说明:

    Category::find(1)->slug();
    
    这里将发生的是:

    category will load slug -> slug will load category -> category will load slug -> ...
    
    这是一种无限的渴望。它将导致数据库超时异常

    要避免这种情况,只需删除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
    
    这两种方法都接受字符串作为参数,以确定必须对哪个字段进行排序

    默认值是在
    处创建的

    • 范围策略使用
    作用域是创建自定义可重用实现的好方法

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

    关于范畴模型-

    class Category extends Model
    {
        ...
    
        public function scopeWithoutParent($query) {
            return $query->whereNull('parent_id');
        }
    }
    
    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()->with('children', 'slug')->get();
    
    $categories = Category::withoutParent()->get();
    
    • 总是渴望加载你的关系
    这是一个可能在你的项目中使用的技巧

    基本上,您可以强制Elount加载关系,而无需显式调用它

    关于范畴模型-

    class Category extends Model
    {
        ...
    
        public function scopeWithoutParent($query) {
            return $query->whereNull('parent_id');
        }
    }
    
    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()->with('children', 'slug')->get();
    
    $categories = Category::withoutParent()->get();
    
    正如你所看到的,你不必再显式地调用关系

    希望这会有帮助

    祝你度过愉快的一天。

    你能详细说明一下吗