laravel hasMany polymorphic relationship in where clause - laravel

I am trying to select the picture with the most likes within a specific category from my database. I have a database table storing the pictures and a table storing the likes. The pictures table is related to likeable table through a hasMany polymorphic relationship.
Like model:
public function likeable()
{
return $this->morphTo();
}
Picture model:
public function likes()
{
return $this->morphMany('App\Like', 'likeable');
}
Home Controller:
Picture::where('picture_type', 'food')->orderBy(likes(), 'desc')->first();
Likeable Migration:
public function up()
{
Schema::create('likeable', function (Blueprint $table) {
$table->increments('id');
$table->integer('user_id');
$table->integer('likeable_id');
$table->string('likeable_type');
$table->timestamps();
});
}
So far, the above line of code, in my home controller returns an error. From what I understand, the likes method has to be called on a specific instance. However, I do not know how to implement this all the while keeping my where clause.
Thank you for your help.

I assume you are wanting to order pictures by the most likes.
In which case, you want something like this:
Picture::withCount('likes')->where('picture_type', 'food')->orderBy('likes_count', 'desc')->first();

Related

How make eloquent laravel relathionship migration with the same table?

if instead of having a users table where one user can follow many users. I would have a cows table where each cow has a single father and a single mother, where the parents can have many children. do I require an external table to store that or can I just add in my cows table the fields cow_father_id and cow_mother_id?
-referring to making 2 eloquent relationships of cows table with same cows table
and what this migration would look like?
You could do this. I've tested as well.
Migration
Schema::create('cows', function (Blueprint $table) {
$table->id();
$table->string('name');
$table->integer('father_id')->nullable();
$table->integer('mother_id')->nullable();
$table->timestamps();
});
Model
class Cow extends Model
{
use HasFactory;
public function father()
{
return $this->belongsTo(self::class, 'father_id');
}
public function mother()
{
return $this->belongsTo(self::class, 'mother_id');
}
public function children()
{
return $this->hasMany(self::class, 'father_id')->orWhere('mother_id', $this->id);
}
}

Laravel relationship one to one doesnt work with single page view

I have created two models called video and file using Laravel 6.
A video can have only one file.
This is the relationship I created:
Video
public function file() {
return $this->hasOne('App\File');
}
File model
public function video() {
return $this->hasOne('App\Video');
}
If I loop all videos then I get the related media
#foreach($videos as $video)
{{$video->link->media}}
#endforeach
If I go to the related video single page it doesnt work.
{{$video->link->media}
Here the route:
Route::get('/video/{slug}', 'HomeController#singleVideo')->name('single');
I get following error:
Trying to get property 'media' of non-object
I also add the table Schema:
Schema::create('files', function (Blueprint $table) {
$table->bigIncrements('id');
$table->string('media')->default('none');
$table->unsignedBigInteger('video_id');
$table->timestamps();
});
Schema::create('videos', function (Blueprint $table) {
$table->bigIncrements('id');
$table->string('title',128);
$table->string('slug')->unique();
$table->text('description');
$table->string('url',247);
$table->string('category',128);
$table->unsignedBigInteger('views')->default(200);
$table->string('video_youtube_status')->default('off');
$table->string('video_status')->default('off');
$table->string('status')->default('off');
$table->timestamps();
});
Model Video
protected $guarded = [];
public function file() {
return $this->hasOne('App\File');
}
....
According to the Laravel documentation, the relation "hasOne" is not applied in this way, the primary model(let's say it's File) will have hasOne like in your code, but the secondary Model will have the Inverse Of The Relationship, which is 'belongsTo' so, in your video Model you should write:
public function file() {
return $this->belongsTo('App\File','file_id');
}
This will allows you to access to the entities like:
$video->file->some_property
$file->video->another_property
and another major problem in your videos table:
this table must have a foreign key to files table, which means:
in your videos migration you should add :
$table->unsignedBigInteger('file_id')->nullable(false);
$table->foreign('file_id')->references('id')->on('files');
According to Laravel documentation
You should implement the use of belognsTo relationship
and your query to get your results set must include the use of method with()
$users = User::with('podcasts')->get();
foreach ($users->flatMap->podcasts as $podcast) {
echo $podcast->subscription->created_at;
}

How to delete categories of user?

I try to delete categories of user like as:
Category::with('user', Auth::user()->id)->where("user_id", $id)->delete();
Category model has relationship:
public function user()
{
return $this->belongsTo('App\User', 'user_id', 'id');
}
But it does not work for me
User model:
public function categories()
{
return $this->belongsToMany('App\Category');
}
Try without with():
Category::where("user_id", $id)->delete();
Update after the User model code addition:
The inverse of a belongsToMany relation is another belongsToMany, the inverse of a belongsTo is a hasMany or a hasOne.
You have to decide which relations between User and Category you want, because a belongsTo doesn't work with an inverse belongsToMany.
From what you wrote in answer and comments seems that you want a Many to many relationship (you have an intermediate table) in this case you have to use belongsToMany in both models and then you can use this code to delete user categories assignement:
$user->categories()->detach()
I think you need to flesh out how they will relate. Right now, based on your relationship code, the Categories table should have an user_id in it.
This is what the relationship on the Category model should look like:
public function users()
{
return $this->belongsToMany(User::class);
}
And you need a table with the name category_user to make the relationship work. Here's an example of what the migration would look like:
Schema::create('category_user', function (Blueprint $table) {
$table->increments('id');
$table->integer('category_id')->unsigned();
$table->integer('user_id')->unsigned();
$table->timestamps();
$table->foreign('category_id')->references('id')->on('categories');
$table->foreign('user_id')->references('id')->on('users');
})
Then you'd be able to add users to categories in the following ways:
$category->users()->attach(Auth::id());
Auth::user()->categories()->attach([ 1, 2, 3 ... ]);
And remove:
$category->users()->detach(Auth::id());
Auth::user()->categories()->detach([ 1, 2, 3 ... ]);
You can also use sync which would detach any element not on your array and attach any element not currently attached:
Auth::user()->categories()->sync([ 1, 2, 3, ... ]);

Eloquent Relationships Not Working as Expected

I am trying to understand what I am missing here.
Apps migration
Schema::create('apps', function (Blueprint $table) {
$table->increments('id');
$table->integer('show_id')->unsigned()->index();
$table->string('name');
$table->integer('provider_id')->unsigned()->index();
$table->timestamps();
});
Show migration
Schema::create('shows', function (Blueprint $table) {
$table->increments('id');
$table->string('name');
$table->timestamps();
});
So I create an apps model that has the following function
public function Show() {
return $this->hasOne(Show::class);
}
But in php artisan tinker when I do $app->Show; I get the following error:
Illuminate\Database\QueryException with message 'SQLSTATE[HY000]: General error: 1 no such column: shows.app_id (SQL: select * from "shows" where "shows"."app_id" = 1 and "shows"."app_id" is not null limit 1)'
Am I mis-understanding the relationships?
Your relation should be as:
Apps model:
public function show() {
return $this->hasOne(Show::class, 'id', 'show_id');
}
Or it can be:
public function show() {
return $this->belongsTo(Show::class);
}
Docs
You do not have an app_id in your shows migration.
edit: Taking from the Laravel Docs and changing it to fit your situation
Eloquent determines the foreign key of the relationship based on the model name. In this case, the show model is automatically assumed to have a app_id foreign key.
A one-to-one relationship consists of a hasOne and a belongsTo. The table that contains the foreign key field must be on the belongsTo side of the relationship.
Since your apps table contains the show_id field, it is stated that apps belong to shows, and shows has one (or many) apps.
Given this, you need to change your Show relationship on your Apps model to use the belongsTo relationship.
public function Show() {
return $this->belongsTo(Show::class, 'show_id');
}
Unless you rename your relationship method so that it is lowercase (function show()), the second parameter is required. If you renamed the relationship, Laravel could build the proper key name and you could leave off the second parameter:
public function show() {
// For belongsTo, second parameter defaults to {function_name}_id.
return $this->belongsTo(Show::class);
}
In your apps model :
public function Show() {
return $this->belongsTo('yourmodelnamespace\Show','id','show_id');
}
And you need create Show model too ..
Hope it will works~~
You can use relation like this
public function Show() {
return $this->hasOne(Show::class, 'id','id');
}

Laravel Eloquent Relationship Many to Many Naming Convention

I am creating a purchased table in my application. So I have 2 tables : User and Product. Its a many to many relationship.
I know we have to create a new table for this. The naming convention for table is plural as users and products.
How would we call this purchase table? user_product or users_products?
Also I think I would need a model for this correct? If I do need a model should the naming convention for this model be User_Product?
From the documentation:
As mentioned previously, to determine the table name of the relationship's joining table, Eloquent will join the two related model names in alphabetical order. However, you are free to override this convention. You may do so by passing a second argument to the belongsToMany method
In your case, Laravel assumes that your joining table would be named product_user. No extra model is needed:
User.php
class User extends Model
{
//...
public function products()
{
return $this->belongsToMany(Product::class);
}
//...
}
Product.php
class Product extends Model
{
//...
public function users()
{
return $this->belongsToMany(User::class);
}
//...
}
And your schemas would look like so:
users table migration
Schema::create('users', function (Blueprint $table) {
$table->increments('id');
//...
});
products table migration
Schema::create('products', function (Blueprint $table) {
$table->increments('id');
//...
});
product_user table migration
Schema::create('product_user', function (Blueprint $table) {
$table->integer('product_id');
$table->integer('user_id');
//...
});
About the naming Convention, thats just something that will make your code more readable i think, so you can name it as you like(in case you are new and learning , my opinion is that its better to avoid being stuck in conventions at first , im still learning my self)
anyway a pivot model is not required, unless you simply need some custom behaviour
I think this would help you
class User extends Model
{
/**
* The products that belong to the shop.
*/
public function products()
{
return $this->belongsToMany('App\Products');
}
}
you can do this : $user->products or to query $product->users, or both.
Now, with such declaration of relationships Laravel “assumes” that pivot table name obeys the rules and is user_product. But, if it’s actually different (for example, it’s plural), you can provide it as a second parameter:
return $this->belongsToMany('App\Products', 'products_users');
If you want to know how to manage these you can find more in here

Resources