制作一个将从另一个模型获取数据的自定义模型 laravel 5.8

Make a custom model that will get data from another model laravel 5.8

我有一个模型,就是存储各种表的外键数据。这是模型的详细信息:

class InstituteStage extends Model
{
    protected $guarded = [];

    public function branch()
    {
        return $this->belongsTo('App\Model\Branch');
    }

    public function version()
    {
        return $this->belongsTo('App\Model\Version');
    }

    public function shift()
    {
        return $this->belongsTo('App\Model\Shift');
    }

    public function stage()
    {
        return $this->belongsTo('App\Model\Stage');
    }

    public function academic_year()
    {
        return $this->belongsTo('App\Model\AcademicYear');
    }

}

现在如果我获取数据,我会得到这些字段:

Array
(
    [0] => Array
        (
            [id] => 3
            [stage_for] => Teachers
            [branch_id] => 1
            [version_id] => 1
            [shift_id] => 1
            [stage_id] => 1
            [academic_year_id] => 1
        )

    [1] => Array
        (
            [id] => 4
            [stage_for] => Students
            [branch_id] => 2
            [version_id] => 2
            [shift_id] => 2
            [stage_id] => 2
            [academic_year_id] => 2
        )
)

现在我想要其他表的详细信息(例如名称)。我正在寻找的响应是:

Array
(
    [0] => Array
        (
            [id] => 3
            [stage_for] => Teachers
            [institute_stage_name] => "branch_name->version_name->shift_name->stage_name" 
        )

    [1] => Array
        (
            [id] => 4
            [stage_for] => Students
            [institute_stage_name] => "branch_name->version_name->shift_name->stage_name" 
        )
)

我可以使用预先加载获取数据并在前端连接它们。但我想使用一个自定义模型,它将 return 这个细节。有没有可能得到这个结构!

我在我的模型中创建了另一个静态方法并获取了所有数据:

public static function student_institute_stage_data()
{
    return static::where([
        ['stage_for', 'Students'],
        ['status', 'active']
    ])
    ->with(['branch', 'version', 'shift', 'stage'])
    ->get();
}

然后在我的控制器中:

$instituteStage = InstituteStage::student_institute_stage_data();

在那之后,在我的 blade 中,我正在这样做 ->

@foreach ($instituteStage as $stage)
    <option value="{{ $stage->id }}" {{ old('institute_stage_id') === $stage->id ? 'selected' : '' }} >{{ $stage->branch->name . "->" . $stage->version->name . "->" . $stage->shift->name . "->" . $stage->stage->name }}</option>
@endforeach

您可以在您的 InstituteStage 模型中使用访问器:

public funcion getInstituteStageNameAttribute($value)
{
    return sprintf(
        '%s->%s->%s->%s',
        $this->branch->name,
        $this->version->name,
        $this->shift->name,
        $this->stage->name
    );
}

这样,当您尝试在 Institute State 模型上访问 institute_stage_name 属性 时,将执行上述功能。

然后在你的控制器中你可以简单地做:

$stages = InstituteStage::where([
    ['stage_for', 'Student'],
    ['status', 'active']
])
->with('branch', 'version', 'shift', 'stage')
->get();

最后在您的 blade 视图中:

@foreach ($stages as $stage)
    <option value="{{ $stage->id }}" {{ old('institute_stage_id') === $stage->id ? 'selected' : '' }} >{{ $stage->institute_stage_name }}</option>
@endforeach

您可以深入研究一些有用的方法,例如 documentation 中的访问器。

更新

如果您还想将查询移出控制器,我个人会在模型中使用本地和动态范围(文档 here)。

为了获得最大的灵活性,我将在两个本地范围内将您需要的两个 where 条件分开:

public function scopeActive($query)
{
    return $query->where('status', 'active');
}

public function scopeFor($query, $type)
{
    return $query->with('branch', 'version', 'shift', 'stage')
        ->where('stage_for', $type);
}

然后您可以将这两种方法与查询构建器语法一起使用,如下所示:

$stages = InstituteStage::for('Student')->active()->get();

如果您在使用已定义的 for 本地作用域时始终需要活动阶段,则可以将 ->active() 方法调用移动到 scopeFor 方法中:

public function scopeFor($query, $type)
{
    return $query->with('branch', 'version', 'shift', 'stage')
        ->where('stage_for', $type)
        ->active();
}

查询将变为:

$stages = InstituteStage::for('Student')->get();

使用查询范围的强大之处在于它们不会阻止您进一步应用任何查询构建器方法 before/after 因此您有一个通用方法以更简单的方式应用基本过滤,然后您可以进一步自定义(如果需要)带有附加位置、连接等的查询,并最终得到结果。

更新:对存取器的澄清

Can you explain how we are getting the concated name by calling 'institute_stage_name' as it is not showing in the array?

这就是访问器的工作方式:您可以定义一个名为 getYourPropNameAttribute($value) 的方法,当您尝试访问其相对对象 属性 时,该方法将由 laravel 自动调用,在这种情况下: $model->your_prop_name(注意访问器函数名称中 属性 名称的 studly/pascal 大小写。

引自文档:

To define an accessor, create a getFooAttribute method on your model where Foo is the "studly" cased name of the column you wish to access.

它是如何工作的 code-wise
当您在您的一个模型(所有扩展 laravel 的模型 class)上访问 属性 时,将执行以下函数:

  • __get魔法方法(source code) will be executed and will call the getAttribute function (source code)
  • getAttribute 将调用 hasGetMutator (source code) 来检查模型中是否存在名为 get + ThePropYouAreAccessingName + Attribute 的方法 class
  • 如果您正在访问的 属性 具有访问器方法或者是模型的属性,则使用 getAttributeValue 调用(在 getAttribute 下方定义的几行)检索其值。
  • 如果 mutator 存在,那么它会被框架调用,并且它的值会返回到您最初访问 属性 的地方。