Reputation: 1679
I'm learning Laravel and my dummy app allows users to log issues against projects. A project can have many issues and an issue can have many tags assigned to it.
I'm currently working on projects/show.blade.php
which outputs all issues associated with a project in an HTML table with columns for name
and tags
.
I've setup 'belongs to many' relationships so that my issues
, tags
and issues_tags
(intermediary) tables can talk to each other but I've run into a problem whereby tags are being output against the wrong issues.
The problem stems from the fact that my issues
table (by design) includes an item_id
column, which is an index but not the primary key. I use item_id
for routing/display on the frontend because I wanted the issue ID that users see to start from 1 for every new project added instead of being sequential and everyone knowing how many there are in the database.
For example, tags assigned to issue #3 are called using issues.id
and not issues.item_id
.
What I want: Tag_id's 1, 2 and 3 to be assigned to issue 3 where issues.item_id
is the index upon which to match. E.g.
What I am getting: Tag_id's 1, 2 and 3 are assigned to issue 3 but are retrieved using issues.id
as the index to match against. E.g.
Issues migration
Schema::create('issues', function (Blueprint $table) {
$table->increments('id');
$table->integer('item_id')->index()->unsigned();
$table->integer('project_id')->unsigned();
$table->string('name');
$table->longText('description');
$table->tinyInteger('status')->default('1');
$table->integer('created_by');
$table->timestamps();
});
Tags migration
Schema::create('tags', function (Blueprint $table) {
$table->increments('id');
$table->string('name');
$table->timestamps();
});
Issues tags migration
Schema::create('issues_tags', function (Blueprint $table) {
$table->increments('id');
$table->integer('tag_id')->unsigned()->index();
$table->foreign('tag_id')->references('id')->on('tags');
$table->integer('issue_id')->unsigned()->index();
$table->foreign('issue_id')->references('item_id')->on('issues');
$table->timestamps();
});
Issue model
public function tags()
{
return $this->belongsToMany('App\Tag', 'issues_tags');
}
Tag model
public function issues()
{
return $this->belongsToMany('App\Issue', 'issues_tags', 'issue_id')->withPivot('item_id');
}
View (projects/show.blade.php)
<table>
<tr>
<th>ID</th>
<th>Item ID</th>
<th>Issue</th>
<th>Tags</th>
</tr>
@foreach($issues as $issue)
<tr>
<td>{{ $issue->id }}</td>
<td>{{ $issue->item_id }}</td>
<td>{{ $issue->name }}</td>
<td>
@foreach($issue->tags as $tag)
<span class="badge badge-primary">{{ $tag->name }}</span>
@endforeach
</td>
</tr>
@endforeach
</table>
How can I use issues.item_id
instead of issues.id
when using a belongsToMany relationship in Laravel?
Upvotes: 0
Views: 4832
Reputation: 646
Here I have put the model relationship code for the issues tags model
<?php
namespace App\Models;
use Eloquent;
class IssueTag extends Eloquent{
protected $table = 'issues_tags';
public function issues()
{
return $this->belongsTo('App\Models\Issue', 'issue_id', 'item_id');
}
public function tags()
{
return $this->belongsTo('App\Models\Tag', 'tag_id');
}
}
Upvotes: 0
Reputation: 1437
From source code:
/**
* Define a many-to-many relationship.
*
* @param string $related
* @param string $table
* @param string $foreignPivotKey
* @param string $relatedPivotKey
* @param string $parentKey
* @param string $relatedKey
* @param string $relation
* @return \Illuminate\Database\Eloquent\Relations\BelongsToMany
*/
public function belongsToMany($related, $table = null, $foreignPivotKey = null, $relatedPivotKey = null,
$parentKey = null, $relatedKey = null, $relation = null)
You can override any params, Laravel just puts defaults made from table names in there if you do not specify which one to use.
In your case it would be:
In Model/Issue.php
public function tags() {
return $this->belongsToMany(Tag::class, 'tag_id', 'issue_id');
}
In Model/Tag.php
public function issues() {
return $this->belongsToMany(Issue::class, 'issue_id', 'tag_id');
}
Upvotes: 1