0
votes

I am modelling a report which depending on its type (missing person, wanted, etc) could contain different fields but each type shares a number of fields. This I think is what differentiates this question from say: this question where the fields are common across all types.

At the moment I have created a report model with an integer field indicating its type which references a type table. The advantage is that this is an easy model to understand and implement. It means that I can also easily search for objects. On the other hand, this means that some fields do not make sense for some models and thus are always null. As I add fields unique to the individual types I end up with many columns in the table of which many are null.

I would like some advice on using Laravel's (5.2) polymorphic relationships. The way I envision this is that I will have a base report model that contains all the shared fields and have the MorphTo fields; then have the different types separate containing their unique fields in a one-to-one relationship with the reports model. Is this possible and does this even make sense? The problems I see are that I lose the ability to search across all "reports" regardless of type. Or is there a way around this like say Java where inheritance allows for sub-classes to be considered members of the superclass?

A rough diagram of such relationships is shown below. Reports holds the shared fields while Wanted and Missing have unique fields.

Relationship between wanted and missing reports, and the base report

1

1 Answers

1
votes

From the diagram representing the relations in your question above, I think it is a straight forward case of parent - child.

Here, your BaseReport or Report is the parent model so to say and the WantedReport and MissingReport are the child - so to say.

Only thing which needs to be changed in your diagram is that you need to define the foreign key of report_id in your child tables to point to the parent record in the base reports table.

Table-reports
id    // primary key
date
description

Table - wanted_reports
id    //primary key
report_id    //foreign key linking to the reports table
status_at
is_captured   //maybe a boolean field
charge

Table - missing_reports
id    //primary key
report_id       //foreign key linking to the reports table 
status_at
is_found
last_seen_date
last_seen_at  

The you can define the corresponding models as - Report

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;

class Report extends Model
{
    protected $table = 'reports';

    protected $fillable = ['report_date', 'description'];

    public function wanted_reports()
    {
        return $this->hasMany(WantedReport::class);
    }

    public function missing_reports()
    {
         return $this->hasMany(MissingReport::class);
    }
}  

WantedReport

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;

class WantedReport extends Model
{

    protected $table = 'wanted_reports';

    protected $fillable = ['report_id', 'status_at', 'is_captured', 'charge'];


    public function report()
    {
        return $this->belongsTo(Report::class);
    }
}  

MissingReport

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;

class MissingReport extends Model
{

    protected $table = 'missing_reports';

    protected $fillable = ['report_id', 'status_at', 'is_found', 'last_seen_date', 'last_seen_at];


    public function report()
    {
        return $this->belongsTo(Report::class);
    }
}  

Then anywhere in your application you can access the relations like you normally do, for example

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;

class ReportsController
{

    public function store(Request $$request)
    {
        $report = $this->model->create([
            'report_date' => Carbon:::now(),
            'description' => $request->get('description')
        ]);

        if($report)
        {
            $wantedReport = $report->wanted_reports()->create([
                'status_at' => $request->get('status'),
                ...
            ]);

            $missingReport = $report->missing_reports()->create([
                'status_at' => $request->get('status'),
                ...
            ]); 
        }  

    }
}  

Hope this helps