Implementing many to many relationships with custom Pivot table name is giving error.
Service.php Model
class Service extends Model
{
public function categories()
{
return $this->belongsToMany('App\ServiceCategory', 'category_service');
}
}
ServiceCategory.php Model
class ServiceCategory extends Model
{
public function services()
{
return $this->belongsToMany('App\Service', 'category_service');
}
}
Table Names
services
service_categories
category_service (Pivot Table Name)
Test
class RelationshipTest extends TestCase
{
use RefreshDatabase;
/** #test */
public function a_service_can_belong_to_many_categories()
{
$service = factory(Service::class)->create();
$category = factory(ServiceCategory::class)->create();
$service->categories()->sync($category);
$this->assertEquals(1, $service->first()->categories()->count());
$this->assertInstanceOf('Illuminate\Database\Eloquent\Collection', $service->categories);
}
}
The test is giving this error.
PDOException: SQLSTATE[HY000]: General error: 1 no such table: main.categories
How to use custom pivot table name without getting this error.
I had the same error message and the issue came from my migration's foreign key constrains.
I forgot to override the default constrained() table name ("categories") to this:
Schema::create('category_service', function (Blueprint $table) {
// ...
$table->foreignId('category_id')->constrained('service_categories')->onDelete('cascade');
// ..
});
Related
I have the following models in a many-to-many relationship:
class Event extends Model
{
public function positions() {
return $this->belongsToMany(Position::class, 'position_events');
}
}
class Position extends Model
{
public function events() {
return $this->belongsToMany(Event::class, 'position_events');
}
}
class PositionEvent extends Model
{
public function position() {
return $this->hasOne(Position::class, 'id', 'position_id');
}
public function event() {
return $this->hasOne(Event::class, 'id', 'event_id');
}
}
The position_events table looks like:
id | event_id | position_id
If $event is an instance of Event, I can get the related positions as:
$event->positions;
This gives me something like the following for each related Position:
{"id":4,"name":"Striker","created_at":"2019-04-02 16:19:57","updated_at":"2019-04-02 16:19:57","pivot":{"event_id":27,"position_id":4}}
Notice the pivot element. It only has event_id and position_id as properties, these are columns from the position_events table. How do I get it to have the id column from that table as well?
Have you tried using withPivot(), for example:
$this->belongsToMany(Position::class, 'position_events')->withPivot('id');
I have been trying to solve a problem for couple hours.
Basically I'm getting:
SQLSTATE[42S02]: Base table or view not found: 1146 Table 'tp-laravel.image_location' doesn't exist (SQL: select location_id from image_location where image_id = 3) error.
Is this coming from a bad controller/model/migration? This is happening when I try to add an image in my website.
I have been trying to change stuff, add stuff and look on google a lot, but nothing solved it.
Image.php
namespace App;
use Illuminate\Database\Eloquent\Model;
use Carbon\Carbon;
class Image extends Model
{
protected $fillable = ['name'];
public function locations()
{
return $this->belongsToMany(Location::class);
}
public function getUpdatedAtAttribute($date)
{
return Carbon::parse($date)->locale('fr')->diffForHumans(Carbon::now());
}
}
Location.php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Location extends Model
{
protected $fillable = ['name'];
public function locations()
{
return $this->belongsToMany(Image::class);
}
}
Here are the create and store methods from my controller:
public function create()
{
$locations = Location::pluck('name', 'id');
$users = User::pluck('name', 'id');
return view('posts.create', compact('locations'));
}
public function store(Request $request)
{
$image = Image::create(request()->all());
$image->locations()->sync(request()->get('locations'));
$user->users()->sync(request()->get('users'));
return redirect('/accueil');
}
And finally my image migration
Schema::create('images', function (Blueprint $table) {
$table->bigIncrements('id');
$table->BigInteger('location_id')->unsigned()->index();
$table->BigInteger('user_id')->unsigned()->index();
$table->foreign('location_id')->references('id')->on('locations')->onDelete('cascade');
$table->foreign('user_id')->references('id')->on('users')->onDelete('cascade');
$table->string('name', 100);
$table->timestamps();
});
When I press the create button in my view, the submit it's supposed to add the image in the database with user and location linked to it as a foreign key but the above error pops up.
Thanks!
The error is coming from
public function locations()
{
return $this->belongsToMany(Location::class);
}
Laravel assumes that you have intermediate table named alphabetically, for that is image_location and this table does not exist on your database.
The only way is to create such table, or if you have created the table with different name you can pass second parameter as table name. So it became:
public function locations()
{
return $this->belongsToMany(Location::class, 'TABLE_NAME');
}
I have the following models. Event belongs to a Casefile. Casefile and User are many-to-many.
class Casefile extends Model
{
public function users()
{
return $this->belongsToMany(User::class)->withTimestamps();
}
public function events()
{
return $this->morphMany('App\Event', 'casefile');
}
}
class User extends Authenticatable
{
public function casefiles()
{
return $this->belongsToMany(Casefile::class)->withTimestamps();
}
}
class Event extends Model
{
public function casefile()
{
return $this->belongsTo('App\Casefile');
}
public function users()
{
return $this->hasManyThrough('App\User', 'App\Casefile');
}
}
When I try to:
App\Event::find(526)->users()->get();
It gives:
Illuminate/Database/QueryException with message 'SQLSTATE[42S22]:
Column not found: 1054 Unknown column 'casefiles.event_id' in 'field
list' (SQL: select users.*, casefiles.event_id from users
inner join casefiles on casefiles.id = users.casefile_id
where casefiles.event_id = 526)'
How can I define the "Event has many Users" relation through Casefile?
It's not possible to use HasManyThrough here without a pivot model for the casefile_user table.
You can define a BelongsToMany relationship instead:
public function users()
{
return $this->belongsToMany('App\User', 'casefile_user', 'casefile_id', null, 'casefile_id');
}
If you not followed laravel naming convention for column name. Then you can specify your column name like this
public function users()
{
return $this->hasManyThrough(
'App\User',
'App\Casefile',
'event_id', // Foreign key on casefiles table...
'user_id', // Foreign key on users table...
);
}
For more Laravel HasManyThrough Relationship
I'm trying to implement a morphable table for categories, right now I've the following.
// Snippet Table
- id
- title
- body
// Post Table
- id
- title
- body
// Category Table
- id
- name
I want to be able to morph the posts and snippets to have only one category, something like this:
// Categorizable Table
- category_id
- categorizable_id
- categorizable_type
Do I have to have another model for this categorizable table? Or there is a way to set it without another model?
So far I have this
class Snippet extends Model
{
public function category()
{
return $this->morphOne(Category::class, 'categorizable');
}
}
class Post extends Model
{
public function category()
{
return $this->morphOne(Category::class, 'categorizable');
}
}
class Category extends Model
{
public function categorizable()
{
return $this->morphTo();
}
}
And I have 4 tables, snippets, posts, categories, categorizables, the last one the migration looks like this.
Schema::create('categorizables', function (Blueprint $table) {
$table->increments('id');
$table->unsignedInteger('category_id');
$table->morphs('categorizable');
$table->timestamps();
});
The thing is, what is the correct way to save this relationship, I'm testing it on tinker and bothattach($category_id) and sync($category_id) aren't saving the relationship they return the error BadMethodCallException with message 'Call to undefined method Illuminate\Database\Query\Builder::categorizable()', What I'm missing?
Sorry I thought you wanted many-to-many relationship. morphOne relationship API is the same as morphMany from the docs
Post extends Model
{
public function category() {
return $this->morphOne(Category::class, 'categorizable');
}
}
Category extends Model
{
public function categorizable() {
return $this->morphTo();
}
}
EDIT
When using morphOne you don't need a pivot table categorizables table must be deleted and change your categories table to include the morph fields
// Category Table
- id
- name
- categorizable_id
- categorizable_type
The question in short:
"pages" and "tasks" have a many-to-many relationship linked by the pivot table "page_tasks". The table "responses" is linked to that pivot table by the foreign key "page_task_id".
Now I want to be able to access the page and the task a response belongs to directly with Eloquent. However the hasManyThrough function does not work, as it exspects the foreign_keys at different places:
public function task(){
return $this->hasManyThrough('PageTask', 'Task', 'page_task_id', 'task_id');
}
Unknown column 'tasks.page_task_id' in 'field list'
This means that eloquent exspects the task table having a foreign key page_task_id pointing to page_tasks. But in my model the page_tasks table has a foreign key task_id pointing to tasks. How do I tell eloquent that fact?
An other approach I tried was to use existing relations that were previously defined:
public function task(){
return $this->page_task->task();
}
This however tells me that there is no methoid called "task".
What would the recommended way be to achieve this? What am I doing wrong?
Here are some more details if needed:
"pages" and "tasks" have a many-to-many relationship with pivot table page_tasks linking it.
Page-Model:
class Page extends Model {
public function tasks(){
return $this->belongsToMany('Task', 'page_tasks');
}
}
Task-Model:
class Task extends Model {
public function pages()
{
return $this->belongsToMany('Page', 'page_tasks');
}
}
This works fine.
Response-Model looks like this
class Response extends Model {
protected $fillable = [
'page_task_id',
];
public function page_task(){
return $this->belongsTo('App\PageTask', 'page_tasks');
}
public function task(){
??????
}
}
PageTask-Model looks like this:
class PageTask extends Model {
protected $fillable = [
'page_id',
'task_id',
];
public function page(){
return $this->belongsTo('Page');
}
public function task(){
return $this->belongsTo('Task');
}
public function responses(){
return $this->hasMany('Response');
}
}