Polymorphic, get user liked activities - php

I have a polymorphic one-to-many realtionship defined between Activity and Like.
A User can like the activity but
how can I get all activities liked by a user?
class Activity extends Model
{
public function likes(){
return $this->morphMany('App\Like', 'likeable');
}
public function like($user = 0){
$this->likes()->updateOrCreate([
'user_id' => $user ? $user->id : Auth::id(),
], [
'liked' => true
]);
}
}
class Like extends Model
{
public function likeable(){
return $this->morphTo();
}
}
class User extends Authenticatable
{
public function likes(){
// Get all liked activities by a user.
}
}

Updated
In User model:
public function likes(){
return $this->hasMany('App\Like');
}
And retrieving likes would be; $user->likes->where('liked', true);
My first answer was wrong.
Or you can use package for likes:
https://github.com/overtrue/laravel-like

I came up with:
public function likedActivities(){
$collection = collect();
foreach ($this->likes as $like) {
$collection = $collection->add($like->likeable);
}
return $collection;
}
This returns all Activities liked by a user.
Is there maybe a more elegant way to do so?

Related

Cannot access Intermediate table in HasManyThrough relationship

My DB schema looks like this.
Now, in artisan tinker mode, When I try to query Details table from user Model, it shows me the records of the details table but I cannot access the the Cases Model for some reason, it always returns NULL in tinker.
This is my User Model
public function details()
{
return $this->hasManyThrough('App\Models\Detail', 'App\Models\Cases', 'user_id', 'case_id', 'id', 'id');
}
What am I doing wrong?
If for convenience you want to access Details directly from the User model then you can define relations as - (may seem like a little duplication but worth if it results in ease)
class User extends Model
{
public function cases()
{
return $this->hasMany(Case::class);
}
public function details()
{
return $this->hasManyThrough(Detail::class, Case::class);
}
}
class Case extends Model
{
public function details()
{
return $this->hasMany(Detail::class);
}
public function user()
{
return $this->belongsTo(User::class);
}
}
class Detail extends Model
{
public function case()
{
return $this->belongsTo(Case::class);
}
}
Now both cases and details can be directly accessed via User record
$user->cases;
$user->details;
The idea of hasManyThrough is to skip the intermediate table. If you need to look at the cases and the details maybe you should define other relations for it.
// User model
public function cases()
{
return $this->hasMany(Cases::class, 'user_id');
}
// Cases model
public function details()
{
return $this->hasMany(Detail::class, 'user_id');
}
$users = User::with('cases.details')->get();
foreach ($users as $user) {
// an user
foreach ($user->cases as case) {
// a case
foreach ($case->details as $detail) {
// the details of a case
}
}
}

Laravel 5.6: Relationship with multiple tables and conditions

Consider I'm a hotel owner, and I have to know the bookings related to my hotel.
I need all bookings that which associated with my hotel.
Is there any eloquent functions to join? How?
How to get bookings of a hotel with owner(userid) with using eloquent relationship functions?
Hotel.php
class Hotel extends Model
{
public function userId(){
return $this->belongsTo(User::class,'user_id');
}
public function rooms(){
return $this->hasMany(Room::class,'hotel_id','id');
}
}
Room.php
class Room extends Model
{
public function hotelId(){
return $this->belongsTo(Hotel::class,'hotel_id');
}
public function bookings(){
return $this->hasMany(Booking::class,'room_id','id');
}
}
User.php
class User extends Model
{
public function hotels(){
return $this->hasMany(Hotel::class,'user_id','id');
}
}
Below code add in your respective controller.
$user = \App\User::find(Auth::id());
$hotels = $user->hotels;
foreach ($hotels as $hotel) {
$rooms = $hotel->rooms;
foreach ($rooms as $room) {
print_r($room->bookings);
}
}
Define the relationship with user in model
class Booking extends Model{
/**
* Get the user that owns the booking.
*/
public function owner()
{
return $this->belongsTo(App\User::class,'user_id,'id');
}
}
Then in your controller
$bookings = Booking::with('owner')->all(); // or get() or whatever to get
the booking list
foreach($bookings as $booking){
echo $booking->user->name; // you have access to owner fields
}
Finally i found this.
Booking model
public function room( )
{ return $this->belongsTo('App\room');
}
public function hotel( )
{
return $this->room()->with(['hotel'=> function($query){
$query->with('user');
}]);
}
BookingController
public function owner(Booking $booking ) {
return $booking->with('hotel')->get()
Next thing is Filter with owner

Aggregate distant relationship with eloquent

I have two models User and Child.
class User extends Model {
public function children() {
return $this->belongsToMany('App\Child', 'user_child')->withPivot('relation_id');
}
public function connections() {
// How to get the distinctly aggregate of my children.friends.contacts as a relationship here?
}
}
class Child extends Model {
public function contacts() {
return $this->belongsToMany('App\User', 'user_child')->withPivot('relation_id');
}
public function friends() {
return $this->belongsToMany('App\Child', 'child_connection', 'child_id1', 'child_id2');
}
}
I would like to eagerly load the distant relationship which I name 'connections' which are the contacts (users) of my children's friends.
$user = User::with('children', 'children.friends', 'connections');
Any ideas how to do this elegantly?
Thank you!
Try
public function connections() {
return $this->belongsToMany('App\Child', 'user_id')->with('friends.contacts;);
}
OMG What a long shot!
If by any miracle that works, then doing
$user = User::find(1);
$user->connections(); //should bring 'children', 'friends' and 'contacts' in one query.
Well it should.
If you find an answer, please post it. I'm really interested in this.

How can I make a row of relations in laravel?

I am struggling with this for a while now, but I can't figure it out how it works.
In laravel I have a few models with relationships. I wan't to have al the accounts based on the logged in user and the passed parameter for the workspace.
This is how the models looks like: (I only coppied the methods to keep it short)
The user Model:
class User extends Eloquent implements UserInterface, RemindableInterface {
public function workspaces()
{
return $this->hasMany('Workspace', 'user_id');
}
public function account()
{
return $this->hasManyThrough('account', 'Workspace', 'id', 'workspace_id');
}
}
The workspace model:
class Workspace extends Eloquent implements UserInterface, RemindableInterface {
public function account()
{
return $this->hasMany('account', 'workspace_id', 'id');
}
public function user()
{
return $this->belongsTo('User', 'user_id', 'id');
}
}
The account model
class account extends Eloquent implements UserInterface, RemindableInterface {
public function account_url()
{
return $this->hasOne('acountUrl', 'id', 'account_url_id');
}
public function workspace()
{
return $this->belongsTo('Workspace', 'workspace_id', 'id');
}
}
The account_url model
class account_url extends \Eloquent implements UserInterface, RemindableInterface {
public function account()
{
return $this->belongsToMany('account', 'id', 'account_url_id');
}
}
So I want from the logged-in user with a specific workspace all the account with the account_urls
something like this: user->workspace->account->account_url
I tried the following things but it don't work:
$account_urls = user::find( Auth::user()->id)->first()->workspaces()->where('id', '=', 1)->account()->account_url()->select('url')->get();
and:
$account_urls = account::where('workspace_id', '=', '1')->account_url()->select('url')->get();
Only when I do it like this:
$account_urls = account::find(1)->account_url()->select('url')->get();
But then I get only 1 url, but when I replase find(1) for all() I get an error?
Is there someone who can help me with this?
Tanks,
Your relations are wrong, change them to:
// User
public function account()
{
return $this->hasManyThrough('Account', 'Workspace', 'user_id', 'workspace_id');
}
// Account
// use camelCase for relations
public function accountUrl()
{
// I assume you have account_url_id on accounts table
// If it's opposite, then use hasOne
return $this->belongsTo('AcountUrl', 'account_url_id', 'id');
}
// AccountUrl (use camelCase)
public function account()
{
// if above is hasOne, then here belongsTo instead.
return $this->hasOne('account', 'account_url_id', 'id');
}
Now, fetching models:
// this part is .. amazing ;)
user::find( Auth::user()->id )->first();
// it does this:
Auth::user()->id // fetch user and get his id
user::find( .. ) // fetch user with given id, you have this user already above...
->first() // fetch first row from users table (not the one with id provided before)
so you want:
$account_urls = Auth::user()->workspaces()
->where('id', '=', 1)->first() // first fetches the result
// or simply
// ->find(1)
->accounts()->first()->accountUrl()
->pluck('url'); // this does 'SELECT url' and returns only this field instead of model
Just remember that:
$user->workspaces
$workspace->accounts
these are collections, so you can't call anything of the model on them, you need to get single model first.

Laravel 4 eager loading

I have a User model, a Recipe model, and a Cookbook model.
A User can 'own' many recipes. (User -OneToMany- Recipe)
A user has 'only one' Cookbook. (User -OneToOne- Cookbook)
Recipes that a user owns belong to his Cookbook.
One Recipe can belong to many Cookbook. (Recipe sharing) (Cookbook -ManyToMany- Recipe)
Many Users may LIKE Many Recipe. (User -ManyToMany- Recipe)
Many Users can follow Many Cookbook. (User -ManyToMany- Cookbook)
One User can have many friends who are Users (User -OneToMany- User)
What I want to do is load recipes for the currently logged in user.
I want to load the recipes owned by his friends and the recipes of all the cookbooks the logged in user is following.
class User extends Eloquent {
public function friends() {
return $this->belongsToMany('User', 'user_friends', 'user_id', 'friend_id');
}
public function cookbook() {
return $this->hasOne('Cookbook', 'owner_id', 'id');
}
public function recipes() {
return $this->hasMany('Recipe', 'owner_id', 'id');
}
public function followedCookbooks() {
return $this->belongsToMany('Cookbook','cb_followers', 'follower_id', 'cb_id');
}
}
class Recipe extends Eloquent() {
public function owner() {
return $this->belongsTo('User', 'owner_id', 'id');
}
public function cookbooks() {
return $this->belongsToMany('Cookbook', 'cb_recipes', 'recipe_id', 'cb_id');
}
}
class Cookbook extends Eloquent() {
public function owner() {
return $this->belongsTo('User', 'owner_id', 'id');
}
public function recipes() {
return $this->belongsToMany('Recipe', 'cookbooks_recipes', 'cookbook_id', 'recipe_id');
}
public function followers() {
return $this->belongsToMany('User', 'cb_followers', 'cb_id', 'follower_id');
}
}
What I did is this:
$user = Auth::user();
$friends = $user->friends();
$cookbooks = $user->followedCookbooks();
$recipes = array();
foreach($friends as $friend) {
$recipe = $friend->recipes();
array_push($recipes, $recipe);
}
foreach($cookbooks as $cookbook) {
$cbRecipes = $cookbook->recipes()
foreach($cbRecipes as $cbRecipe) {
array_push($recipes, $cbRecipe);
}
}
But this method would run a lot of SQL queries. How can I use eager loading to reduce the number of queries?
How about
$user = Auth::user();
$recipesFriends = $user->friends()->with('friends.recipes')->get();
$recipesCookbooks = $user->with('followedCookbooks')->with('followedCookbooks.recipes')->get();
If you want to go a bit further you can take a look at this answer: How to list out all items in a nested table in Laravel
You may try this:
$userData = Auth::user()->load('cookbook.recipes')
->load('friends.cookbook.recipes');
If you want to load friends recipes in a different variable then you may try this:
$userData = Auth::user()->load('cookbook.recipes')
->load('friends.cookbook.recipes');
$friendsData = $userData->friends;

Categories