Laravel Many To Many Polymorphic Relation doesn't work - php

hi I'm trying to use many to many polymorphic but somehow it doesnt work I attach my code can you find out what I do wrong?
my migration :
Schema::create('stickers', function (Blueprint $table) {
$table->increments('id');
$table->string('name');
$table->string('type');
$table->timestamps();
});
Schema::create('stickables', function (Blueprint $table) {
$table->integer('sticker_id')->nullable();
$table->integer('stickable_id');
$table->string('stickable_type');
$table->primary(['sticker_id', 'stickable_id', 'stickable_type']);
$table->foreign('sticker_id')
->references('id')->on('stickers')
->onDelete('cascade');
$table->timestamps();
});
and my models
Trip model:
public function stickables()
{
return $this->morphToMany(Stickable::class, 'stickable');
}
Stickable model:
public function trips()
{
return $this->morphedByMany(Trip::class, 'stickable');
}
controller:
public function store(Request $request)
{
$trip = new Trip();
$trip->name = $request->name;
$trip->desc = $request->desc;
$trip->creator_id = Auth::user()->id;
$trip->save();
$tags=$request->tags;
$trip->stickables()->attach($tags);
$trip->save();
return redirect('/trip');
}

Here is how you should define your relationship:
Trip Model:
public function stickers()
{
return $this->morphToMany(Sticker::class, 'stickable');
}
Sticker Model:
public function trips()
{
return $this->morphedByMany(Trip::class, 'stickable');
}
You don't need a model for your relationship (Stickable).You should create a model for stickers and define your relationship on that.
Stickable can refer to Trip or any other type of model you need to create a relationship with stickers. However in your code you have a stickable method on the Trip model, which does not make sense.
Eloquent Many to Many Polymorphic Relationships

Related

Why does hasOne and BelongTo relationships load only ids but not the models

I've got a problem with relations in Laravel 9.14 Eloquent.
I have two models File and Project with coresponding tables in MySql database files and projects.
Project migration
Schema::create('projects', static function (Blueprint $table) {
$table->id();
$table->string('name');
$table->string('code');
$table->string('theme');
$table->foreignId('discipline_id')->constrained('disciplines');
$table->foreignId('user_id')->constrained('users');
$table->string('external_id');
$table->foreignId('preview')->nullable()->constrained('files');
$table->date('publish_date');
$table->timestamps();
});
File migration
Schema::create('files', static function (Blueprint $table) {
$table->id();
$table->string('original_name');
$table->string('extension');
$table->string('mime_type');
$table->integer('size')->unsigned();
$table->timestamps();
});
Project has field which is related to the File model called 'preview'. Project, basically can have only one preview file. So I did these relatioins in models:
class Project extends Model
public function preview(): BelongsTo
{
return $this->belongsTo(File::class, 'preview', 'id');
}
class File extends Model
public function previewProject(): HasOne
{
return $this->hasOne(Project::class, 'preview', 'id');
}
When i try to get preview of a project this way (controller method):
public function index(): Factory|View|Application
{
$userId = auth()->user()->id;
$projects = User::find($userId)->projects()->with(['user', 'preview'])->get();
//dd($projects->first()->user);
ddd($projects->first()->preview);
return view('user.index', [
'projects' => $projects
]);
}
Instead of File model object I get only integer id of File. Queries, however, look right:
queries image
What is the problem here?
There is no error, the integer your are getting is the value of the attribute but by "chance" both your attribute and relation have the same name.
Either change the relation name:
class Project extends Model
public function previewFile(): BelongsTo
{
return $this->belongsTo(File::class, 'preview', 'id');
}
public function index(): Factory|View|Application
{
$projects = auth()->user()->projects()->with(['user', 'previewFile'])->get();
//dd($projects->first()->user);
ddd($projects->first()->previewFile);
return view('user.index', [
'projects' => $projects
]);
}
Or change the attribute name
Schema::create('projects', static function (Blueprint $table) {
$table->id();
$table->string('name');
$table->string('code');
$table->string('theme');
$table->foreignId('discipline_id')->constrained('disciplines');
$table->foreignId('user_id')->constrained('users');
$table->string('external_id');
$table->foreignId('preview_id')->nullable()->constrained('files');
$table->date('publish_date');
$table->timestamps();
});
class Project extends Model
public function preview(): BelongsTo
{
return $this->belongsTo(File::class, 'preview_id', 'id');
}

Laravel: Order a model by "Has One Of Many" relationship

I have a customer model that has many contacts. I defined a relationship to get the most recent contact of the customer using the "Has One Of Many" relationship in Laravel 8:
Models
class Customer extends Model
{
use HasFactory;
public function contacts()
{
return $this->hasMany(Contact::class);
}
public function latestContact()
{
return $this->hasOne(Contact::class)->ofMany('contacted_at', 'max')->withDefault();
}
}
class Contact extends Model
{
use HasFactory;
protected $casts = [
'contacted_at' => 'datetime',
];
public function customer()
{
return $this->belongsTo(Customer::class);
}
}
Migration (contact model)
class CreateContactsTable extends Migration
{
public function up()
{
Schema::create('contacts', function (Blueprint $table) {
$table->id();
$table->timestamps();
$table->softDeletes();
$table->foreignID('customer_id');
$table->string('type');
$table->dateTime('contacted_at');
});
}
}
In my view, I want to show all customers and order them by their latest contact. However, I can't figure out how to do that.
I tried to achieve it via the join method but then I obviously get various entries per customer.
$query = Customer::select('customers.*', 'contacts.contacted_at as contacted_at')
->join('contacts', 'customers.id', '=', 'contacts.customer_id')
->orderby('contacts.contacted_at')
->with('latestContact')
Knowing Laravel there must be a nice way or helper to achieve this. Any ideas?
I think the cleanest way to do this is by using a subquery join:
$latestContacts = Contact::select('customer_id',DB::raw('max(contacted_at) as latest_contact'))->groupBy('customer_id');
$query = Customer::select('customers.*', 'latest_contacts.latest_contact')
->joinSub($latestContacts, 'latest_contacts', function ($join){
$join->on([['customer.id', 'latest_contacts.customer_id']]);
})
->orderBy('latest_contacts.latest_contact')
->get();
More info: https://laravel.com/docs/8.x/queries#subquery-joins
I suspect there is an issue with your migration, the foreign key constraint is defined like this:
Check the documentation:
https://laravel.com/docs/8.x/migrations#foreign-key-constraints
Method 1: define foreign key constraint
public function up()
{
Schema::create('contacts', function (Blueprint $table) {
$table->id();
$table->foreignId('consumer_id')->constrained();
$table->string('type');
$table->dateTime('contacted_at');
$table->timestamps();
$table->softDeletes();
});
}
Method 2: define foreign key constraint
public function up()
{
Schema::create('contacts', function (Blueprint $table) {
$table->id();
$table->unsignedBigInteger('customer_id');
$table->foreign('customer_id')->references('id')->on('customers');
$table->string('type');
$table->dateTime('contacted_at');
$table->timestamps();
$table->softDeletes();
});
}

Booking system ala airbnb many to many laravel relationship?

I'm trying to create a system to log all bookings for a few airbnb hosts, at first I had two models Home and Guest, where a home can have many guests and a guest could book for many homes,
then I thought about creating a guest_home pivot table to link both tables... then things got complicated in my head, what about a Booking model, and (have that booking model act as a pivot table ?) , to me doing new Booking() seemed better than attaching ids to home model?
How could you guys go about this, it's making my brain malt right now...
I thought of doing something like this in my BookingController:
public function createBooking(Request $request)
{
$guestIds = Guest::latest()->take(3)->pluck('id');
$home = Home::findOrFail($request->input('home_id', 2));
$booking = new Booking();
$booking->home_id = $home->id;
$booking->guests()->attach($guestIds);
$booking->save();
return response()->json([
'booking' => $booking,
]);
}
Should I create home_guest pivot table, is a pivot table even needed? what models would I link, please bear with me, so far this is what I got:
Models
class Guest extends Model
{
public function bookings()
{
return $this->belongsToMany('App\Models\Home', 'bookings', 'guest_id', 'home_id');
}
}
class Home extends Model
{
public function guests()
{
return $this->belongsToMany('App\Models\Guest', 'bookings', 'home_id', 'guest_id');
}
public function bookings()
{
return $this->hasMany('App\Models\Booking');
}
}
class Booking extends Model
{
//Is Booking needed or I could make a pivot table like home_guest called 'bookings' ?
public function guests()
{
return $this->belongsToMany('App\Models\Guest', 'booking_guest', 'booking_id', 'guest_id');
}
}
Migrations:
Schema::create('bookings', function (Blueprint $table) {
$table->increments('id');
$table->unsignedInteger('home_id')->index();
$table->foreign('home_id')->references('id')->on('homes')->onDelete('cascade')->onUpdate('cascade');
$table->unsignedInteger('guest_id')->nullable()->index();
$table->foreign('guest_id')->references('id')->on('guests')->onDelete('cascade')->onUpdate('cascade');
$table->timestamps();
});
Schema::create('homes', function (Blueprint $table) {
$table->increments('id');
$table->unsignedInteger('host_id')->index();
$table->foreign('host_id')->references('id')->on('hosts')->onDelete('cascade')->onUpdate('cascade');
$table->string('fullAddress')->unique();
$table->integer('rooms')->unique();
$table->timestamps();
});
Schema::create('guests', function (Blueprint $table) {
$table->increments('id');
$table->string('fullName')->unique();
$table->string('identificationType')->unique();
$table->text('country')->nullable();
$table->timestamps();
});

Eloquent many to many relationship is always empty

I know this question has been asked a lot but all answers didn't seem to work for me - or at least the questions I found were about the pivot table.
I have a many to many relationship (User - Appointment) which is joined by the pivot table "apointment_user", see migrations below.
Schema::create('appointment_user', function (Blueprint $table) {
$table->unsignedInteger('user_id')->nullable();
$table->foreign('user_id')->references('id')->on('users');
$table->unsignedInteger('appointment_id')->nullable();
$table->foreign('appointment_id')->references('id')->on('appointments');
$table->primary(['user_id','appointment_id']);
$table->timestamps();
});
Schema::create('appointments', function (Blueprint $table) {
$table->increments('id');
$table->string('title');
$table->dateTime('date');
$table->string('location');
$table->dateTime('departure');
$table->timestamps();
});
Schema::create('users', function (Blueprint $table) {
$table->increments('id');
$table->string('name');
$table->string('email')->unique();
$table->string('password');
$table->date('last_login')->nullable();
$table->rememberToken();
$table->timestamps();
$table->softDeletes();
});
class User extends Model {
protected $with = ['appointments'];
public function appointments() : BelongsToMany {
return $this->belongsToMany(Appointment::class);
}
}
class Appointment extends Model {
public function users() : BelongsToMany {
return $this->belongsToMany(User::class);
}
}
I have a user with the ID 1 and about 10 appointments, which I do attach to the relationship in a seeder. The pivot table has 10 records, as intended (User ID is always 1).
However, if I dump my User object using dd(User::find(1)), the relationship is always an empty collection. However, a 1:n relationship (between a role works well).
Does anybody see what I'm missing? Any help is appreciated.
Many thanks and kind regards
Edit
I just tried some other kind of dumping. I've simply returned my User-Object as JSON-response and there the relationship is filled with 10 appointments... strange.
Though it seems that your table and column names are as Laravel would guess, have you tried expliciting the names?
class User extends Model {
protected $with = ['appointments'];
public function appointments() : BelongsToMany {
return $this->belongsToMany(Appointment::class, 'appointment_user', 'user_id', 'appointment_id');
}
}
class Appointment extends Model {
public function users() : BelongsToMany {
return $this->belongsToMany(User::class, 'appointment_user', 'appointment_id', 'user_id');
}
}

Laravel 5 pivot table project<->user

I find the pivot tables pretty complicated and I don't see what to do next or what I am doing wrong, I've found some tutorials but didn't help me in my needs.
I have a projects and users with a many-to-many relation.
One project hasMany users and One user hasMany projects.
What I have now leaves projects without a relationship to a user.
This is what I have so far:
Projects table
class CreateProjectsTable extends Migration {
public function up()
{
Schema::create('projects', function(Blueprint $table)
{
$table->increments('id');
$table->string('name');
$table->date('completion_date');
$table->integer('completed')->default(0);
$table->integer('active')->default(0);
$table->timestamps();
});
}
Users table
class CreateUsersTable extends Migration {
public function up()
{
Schema::create('users', function(Blueprint $table)
{
$table->increments('id');
$table->integer('company_id');
$table->integer('project_id');
$table->integer('usertype_id')->default(0);
$table->string('username');
$table->string('password');
});
}
Project User table (pivot)
class CreateProjectUsersTable extends Migration {
public function up()
{
Schema::create('project_users', function(Blueprint $table)
{
$table->increments('id');
$table->integer('project_id')->references('id')->on('project');;
$table->integer('user_id')->references('id')->on('user');;
});
}
User model
public function projects() {
return $this->belongsToMany('App\Project', 'project_users', 'user_id', 'project_id');
}
Project model
public function users() {
return $this->belongsToMany('App\User', 'project_users', 'project_id', 'user_id');
}
Project controller
public function index(Project $project)
{
$projects = $project->with('users')->get();
dd($projects);
$currenttime = Carbon::now();
//return view('project.index', array('projects' => $projects, 'currenttime' => $currenttime));
return view('user.index', compact('projects'));
}
The relationship in your User model is not correct. You have to swap the keys.
public function projects() {
return $this->belongsToMany('App\Project', 'project_users', 'user_id', 'project_id');
}
Edit regarding latest comment:
Don't think about the pivot table, as long as you have your relations setup correctly, which I believe they are, Laravel handles all of that for you.
Now $projects->users does not make any sense because projects does not have users. projects is just a collection of Project. Each Project within that collection will have a users relation. You would have to iterate through the collection to view each Project's users.
foreach($projects as $project) {
foreach($project->users as $user) {
echo $user;
}
}

Categories