简体   繁体   中英

Get title based on relationship (laravel)

So I have the following taxonomy:

  • School
  • Department
  • Class

A school hasMany departments. A department hasMany classes.

A department belongsTo a school. A class belongsTo a department and a school.

A school, department, or a class can have a test assigned to it. This is determined via pivot tables like so:

  • school_test
  • department_test
  • class_test

This all works absolutely perfectly, but on a test page, I want to be able to display the following info:

School Name | Department Name | Class Name

If it's school-wide then it should just show the school name.

If it's department-wide then it should show: School Name | Department Name School Name | Department Name .

And if it's for a class then it should show: School Name | Department Name | Class Name School Name | Department Name | Class Name School Name | Department Name | Class Name .

My blade code looks like this:

{{$test->school->first()->name}}
        @if($test->department->isNotEmpty())
              |  
            {{$test->department->first()->name}}
        @if($test->class->isNotEmpty())
              |  
            {{$test->class->first()->name}}
        @endif
        @endif

This works fine for when it's a school-wide test but it will break when I'm trying to load up a test for a class as it obviously doesn't have a relationship to a department via the pivot tables. Instead I would need to do something like this:

{{$test->class->first()->department->school->name}}

That traverses the relationships, but how do I incorporate this neatly in my view to account for the different scenarios?

All help welcome!

Get all the tests $tests = Test::all() (or add query scopes if needed)

Loop through each test using @foreach($tests as $test)

Add relationships to the Test model class for School, Department, Class

function school() {
    $this->belongsTo(School::class);
}

Create a helper function to determine what the Test directly belongs to

function isFor($parent) {
    switch($parent) {
        case 'school':
            return $this->school;

        case 'department':
            return $this->department;

        case 'class':
            return $this->class;
    }
}

Then you can use that in your view to check what the test directly belongs to

@if($test->isFor('school'))

If you don't want to switch/case then use if/elseif to do something like

function isFor() {
    if($this->school) {
        return 'school';
    }        
    elseif($this->department) {
        return 'department';
    }
    elseif($this->class) {
        return 'class';
    }
}

And then in the view something like:

@if($test->isFor() == 'school')

Once you determine what the direct parent is you can carry on accessing the names directly from the parent, instead of having to go through another relationship so:

@if($test->isFor('department'))

{{ $test->department->name }}

I'd also advise creating different partials/views for each different view

@if($test->isFor('department'))
    @include('partials.test-department')
@endif

And put exactly what that view should contain in that partial

To get school by its test ID:

School::whereHas('tests', function($q) use($testId) {
    $q->where('id', $testId);
})->first();

tests here is many-to-many relationship.

The same way you can get department and class.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM