How to update one to many polymorphic relationship? - laravel

How to update multiple records in One to many polymorphic relationship?
I want to update the fields as a group, but how?
Skill Model:
class Skill extends Model
{
use HasFactory;
protected $fillable = ['title', 'percentage'];
/**
* Get the owning skillable model.
*/
public function skillable(): MorphTo
{
return $this->morphTo();
}
}
User Model:
class User extends Model
{
use HasFactory;
/**
* Get all of the skill's user.
* #return MorphMany
*/
public function skills(): MorphMany
{
return $this->morphMany(Skill::class, 'skillable');
}
}

There are a number of ways to do so:
$user->skills->each(function ($skill) {
$skill->update([...]);
});
$user->skills->each(fn($skill) => $skill->update([...]));
$user->skills->each->update([...]);
$user->skills()->update([...]);
I recommend the first three approaches. Because if there are any model events, those will be fired. Model events won't be fired in the fourth one.
Specifically to your problem, you might want to do something like this in the controller:
public function update()
{
$skills = collect(request('skill_titles'))
->zip(request('skill_percentages'))
->map(function ($pair) {
return [
'title' => $pair[0],
'percentage' => $pair[1],
]
});
$skills->each(function ($skill) use ($user) {
$user->skills()->where('title', $skill['title'])
->update($skill['percentage']);
});
}

you can use update method
// make sure you have the desired attributes in fillable array property in your model class
$model->related_model->update([inputs]);
if you write the relationship methods "related_method" in model class correctly you can use them as properties of your model and access their attributes or update them.

Related

How to sort parent data based on child column detial in laravel 5.4?

I have 3 way relationship firstl i have get code like this in a controller
Trial::with('subjects')->where('source_id', $sourceId)->get()->toArray()
Now I want to sort subject.reactions on desc order of subject.reactions.accounts.nb_followers column. I tried to use orderby on relationship but it does not work because it sorting account indsted on reactions. I want to sort reaction based on value of "nb_followes" column present inside account table.
Trail Model
class Trial extends Model
{
use HasFactory;
public $table = 'trials';
public function subjects()
{
return $this->hasMany(Subject::class, 'trial_id')->with(['reactions', 'news'])->withCount('reactions');
}
}
Subject Model
class Subject extends Model
{
use HasFactory;
public $table = 'subjects';
public function reactions()
{
return $this->hasMany(Reaction::class, 'subject_id', 'id')->with(['accounts' => function ($q) {$q->orderBy('nb_followers', 'DESC');}])->where('twitter_error', 0)->where('active', 1)->orderby('key_reaction', 'DESC');
}
public function news()
{
return $this->hasone(News::class, 'id', 'news_item_id');
}
Reaction Model
class Reaction extends Model
{
use HasFactory;
public $table = 'reactions';
public function accounts()
{
return $this->belongsTo(Account::class, 'account_id', 'id')->where('name', '!=', '');
}
Thank you in Advance.
I want to sort reactions based on account table's column yes i cant use simple eloquent query because it will not create a structure that i want so that's why i created these relationships.
first you need to loop over trails using map method
second you need to use transform method to transform your subject in
sorted manner
as show in Subject model you need sort reaction by key_reaction
feild
$trails = ViewTrial::with('subjects')->where('source_id', $sourceId)->get();
$trails->map(function($trails){
return $trails->subjects = $trails->subjects->transform(function (&$subject) {
return [
"column" => $subject->column,
"reactions" => $subject->reactions->sortByDesc(function ($reactions) {
return $reactions['accounts']['nb_followers'];
})->sortByDesc('key_reaction')->values()->all()
]
})->values();
});
return $trails->toArray();

Laravel model relationship method

I have 3 tables
User (id,name,mail,mobile)
Contest (id,contest_name,contest_description)
Contest_user (id,user_id,contest_id)
I want to write a has many contest user method in the contest model also I need the user details from the method.
Kindly tell me how can I get the desired result.
Model Screenshot
<?php
namespace App\Model\Contest;
use App\Model\Project\ContestUsers;
use Illuminate\Database\Eloquent\Model;
class Contest extends Model
{
protected $table = 'contest';
protected $fillable = ['name','description'];
public $dates = [
'created_at',
'updated_at',
'deleted_at',
];
//I want to get user details from this method
public function project_contest_users()
{
return $this->hasMany(ContestUsers::class, 'contest_id', 'id')->whereNull('deleted_at');
}
}
contest_user is a pivot table for users and contests and should not have a model class.
The nature of the relation between User and Contest is a many to many, so you need to use belongsToMany() relation in both sides
Contest.php
public function users()
{
return $this->belongsToMany(User::class);
}
User.php
public function contests()
{
return $this->belongsToMany(Contest::class);
}
From what you have done, based on my experience, it's already a good thing that you normalize the many to many relationship. But what N69S said is also correct, that pivot table should not have a Model class, so you need to make your own convention to not use the Model class to create/update/delete (read is fine by me) and if you still want to stick to this method, what you need to do now is just defining the relationships for each of the Models.
User.php:
public function contest_user()
{
return $this->hasMany(ContestUser::class);
}
ContestUser.php:
public function user()
{
return $this->belongsTo(User::class);
}
public function contest()
{
return $this->belongsTo(Contest::class);
}
Contest.php:
public function contest_user()
{
return $this->hasMany(ContestUser::class);
}

Laravel Eloquent How Can I Select Using Condition "where" for pivot table

I have three database tables called user(id,name), group(id,name) and user_group(user_id, group_id,valid_before) with relations many to many.
class User extends Model
{
protected $table = 'user';
public function groups()
{
return $this->belongsToMany(Group::class, 'user_group')
->withPivot('valid_before');
}
}
class Group extends Model
{
protected $table = 'group';
public $timestamps = false;
public function user()
{
return $this->belongsToMany(User::class, 'user_group');
}
}
How can I select all users (using Eloquent) who have
valid_before < $some_date
?
There are many ways to achieve this goal. I'll show you an example using query scopes.
In your User class you have to make a little update:
class User extends Model
{
protected $table = 'user';
public function groups()
{
return $this->belongsToMany(Group::class, 'user_group')
//->withPivot('valid_before'); <-- Remove this
}
}
and create a scope in your Group model:
class Group extends Model
{
protected $table = 'group';
public $timestamps = false;
public function user()
{
return $this->belongsToMany(User::class, 'user_group');
}
/**
* This scope gets as input the date you want to query and returns the users collection
*
* #param \Illuminate\Database\Eloquent\Builder $query
* #param string $date
* #return \Illuminate\Database\Eloquent\Builder
*/
public function scopeUsersValidBefore($query, $date)
{
return $query->users()->wherePivot('valid_before', '<', $date);
}
}
Now, I imagine you have a GroupController that somewhere creates a query to retrieve the valid before users. Something like:
// [...]
$users = Group::usersValidBefore($yourDate)->get();
// [...]
If you want to create the query from the other side, I mean you want to use the User model and list all the Users that has a pivot relation with valid_before populated, than the right approach is creating a UserGroup intermediate model that can be easily used to create a query.
If you are using Laravel 8.x.x
It's much easier with Inline Relationship Existence Queries
If you would like to query for a relationship's existence with a single, simple where condition attached to the relationship query, you may find it more convenient to use the whereRelation and whereMorphRelation methods. For example, we may query for all posts that have unapproved comments:
use App\Models\Post;
$posts = Post::whereRelation('comments', 'is_approved', false)->get();
Of course, like calls to the query builder's where method, you may also specify an operator:
$posts = Post::whereRelation(
'comments', 'created_at', '>=', now()->subHour()
)->get();

Laravel: Multiple tables in one model

I have the following model for Users:
class User extends Authenticatable
{
use Notifiable;
protected $table = 'login_info';
/**
* The attributes that are mass assignable.
*
* #var array
*/
protected $fillable = [
'name', 'email', 'password',
];
/**
* The attributes that should be hidden for arrays.
*
* #var array
*/
protected $hidden = [
'password', 'remember_token',
];
public function getDashboards()
{
return \DB::table('dashboard')
->select('type')
->where('id', Auth::id())
->orderBy('column', 'asc')
->get();
}
}
Users have different information in many tables
user info like name, office, dashboard,2FA etc
Is the way I do it now "best practice" (like the getDashboards function) for getting information from different tables?
Or should I create a model for each of the tables and then "join them" (hasMany, belongsToMany, and so on) for each of the tables?
EDIT:
I am now using models, but the result of the query is always an empty array.
class Dashboard extends Model
{
protected $table = 'dashboard';
public function user()
{
return $this->belongsTo(User::class,'user_id','id');
//user_id
}
}
user_id is the id of the user which is used in the login_info table.
And in the User class I have:
public function dashboards()
{
return $this->hasMany(Dashboard::class,'id','user_id');
}
In the login controller I have:
$user = \App\User::find(1);
$user->dashboards;
Anyone see what the problem could be?
Thanks for any help!
public function dashboards()
{return $this->hasMany(\App\Dashboard::class);
}
And in your Dashboard Model you do it this way
protected $casts = [
'user_id' => 'int',
];
public function user()
{
return $this->belongsTo(\App\User::class);
}
The more Laravel way is to rather created the related Dashboard model and use the eloquent relationships, and harness the features of the ORM. Nothing wrong to include an orderBy on the relationship if you always need ordering on that column.
class User extends Authenticatable
{
public function dashboards()
{
return $this->hasMany(Dashboard::class)
->orderBy('column', 'asc');
}
}
class Dashboard extends Model
{
public function user()
{
return $this->belongsTo(User::class);
}
}
You do not have to do anything in the model! Just refer to the model in the controller, for example:
User::where('id', Auth::id())->pluck('type');

Issues with Laravel hasManyThrough relationship

I'm having issues using the hasManythrough relationship in larval. Just following the documentation using the example there, which are:
countries
id - integer
name - string
users
id - integer
country_id - integer
name - string
posts
id - integer
user_id - integer
title - string
Here is how I set up the relationship in the models
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Country extends Model
{
public function posts() {
return $this->hasManyThrough('App\Post', 'App\User', 'user_id', 'country_id', 'id');
}
}
Here is the User model
class User extends Authenticatable
{
use Notifiable;
/**
* The attributes that are mass assignable.
*
* #var array
*/
protected $fillable = [
'name', 'email', 'password',
];
/**
* The attributes that should be hidden for arrays.
*
* #var array
*/
protected $hidden = [
'password', 'remember_token',
];
public function posts() {
return $this->hasMany('App\Post');
}
public function country() {
return $this->hasOne('App\User');
}
}
Here is the Posts model
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Post extends Model
{
public function user() {
return $this->belongsTo('App\User');
}
}
So, the website doesn't go through enough detail on how to extract the posts through the country model. Using the routes file, this is the query I used
Route::get('posts/countries/{id}', function($id) {
$countries = App\Country::where('id', $id)->get();
return $countries->posts;
});
It looks to me like I set up the relationship up correctly the way the docs say to. There is a country_id on the users table, so I'm not sure if the query is wrong or maybe I did set up the relationship incorrectly.
You aren't actually requesting the relationship, you are simply looking at the attribute on countries.
If you want to eagerload the posts in the query builder you will need to add with('posts') when you build the query. (Before you call ->get() which executes the query and turns it into a collection.)
Route::get('posts/countries/{id}', function($id) {
$country = App\Country::with('posts')->where('id', $id)->first();
return $country->posts;
});
Or if you want to lazyload you can ask for the relationship on the country model by doing ->posts() like this:
Route::get('posts/countries/{id}', function($id) {
$country = App\Country::with('posts')->where('id', $id)->first();
return $country->posts();
});
Notice: in both cases I changed the ->get() to ->first(). I assume you only want one country's posts returned.
->get() executes the query and returns the related models as a collection and ->first() takes the first model from the query.
#Nicklas Kevin Frank
Your solution didn't work for me. at least not completely, but you were right in some respects. I tinkered around, and discovered that the query worked like this better:
Route::get('posts/countries/{id}', function($id) {
$country = App\Country::where('id', $id)->first();
return view('country')->with('country', $country);
});
So, like you said, it diffidently needed the ->first() option, but it didn't need the with('posts') portion. But much thanks my friend. I couldn't have solved this without you.

Resources