How can I with pivot table get related creator of table? - laravel

In laravel 9 app I create many top many relation with table
return new class extends Migration {
public function up()
{
Schema::create('article_vote', function (Blueprint $table) {
$table->id();
$table->foreignId('article_id')->references('id')->on('articles')->onUpdate('RESTRICT')->onDelete('CASCADE');
$table->foreignId('vote_id')->references('id')->on('votes')->onUpdate('RESTRICT')->onDelete('CASCADE');
$table->boolean('active')->default(false);
$table->date('expired_at')->nullable();
$table->integer('supervisor_id')->nullable()->unsigned();
$table->foreign('supervisor_id')->references('id')->on('users')->onDelete('CASCADE');
$table->mediumText('supervisor_notes')->nullable();
$table->timestamp('created_at')->useCurrent();
$table->timestamp('updated_at')->nullable();
$table->unique(['vote_id', 'article_id'], 'article_vote_vote_id_article_id_index');
$table->index(['vote_id', 'article_id', 'active', 'expired_at'], 'article_vote_vote_id_article_id_active_expired_at_index');
$table->index([ 'expired_at', 'active',], 'article_vote_expired_at_active_index');
$table->index(['created_at'], 'article_vote_created_at_index');
});
Artisan::call('db:seed', array('--class' => 'articleVotesWithInitData'));
}
In app/Models/Vote.php I also have creator method :
public function articles(): BelongsToMany
{
return $this->belongsToMany(Article::class, 'article_vote', 'vote_id')
->withTimestamps()
->withPivot(['active', 'expired_at', 'supervisor_id', 'supervisor_notes']);
}
public function creator(): BelongsTo
{
return $this->belongsTo(User::class, 'creator_id', 'id');
}
and in app/Models/Article.php :
public function votes(): BelongsToMany
{
return $this->belongsToMany(Vote::class, 'article_vote', 'article_id')
->withTimestamps()
->withPivot(['active', 'expired_at', 'supervisor_id', 'supervisor_notes']);
}
Getting votes by article I also would like to get related creator of any vote li8ke :
$articleVotes = $article->votes->with('creator');
But I got error:
BadMethodCallException: Method Illuminate\Database\Eloquent\Collection::with does not exist. in /mnt/_work_sdb8/wwwroot/lar/MS/MS_Votes/vendor/laravel/framework/src/Illuminate/Macroable/Traits/Macroable.php:113
Can I do it in some or other way ?
Thanks!

I think you need to change the relationship method for load creator in votes.
For that you need to change your code to :
$articleVotes = $article->votes;
$articleVotes->load('creator');

Related

Completion system with Laravel + VueJS

I've been tring for hours to define my relations for a completion system but I failed.
I have a table Users and a table Episodes, and I would like to get in my views if the User has completed an episode.
I created a "completions" table with user_id and episode_id and a boolean field called "completed"
Is it a manytomany relation ? I'd like to have something like $episode->completed which gave me True if the logged in user finished the course, but I can't find my way... I just wanna know how to define my relations, not a whole work done.
Thank you very much !!!!
I believe you can tell Laravel what table to use and also query the pivot column.
//user model
public function episodes(){
return $this->belongsToMany( 'App\Episode', 'completions', 'user_id', 'episode_id' );
}
public function completedEpisodes(){
return $this->belongsToMany( 'App\Episode', 'completions', 'user_id', 'episode_id' )
->wherePivot('completed','=', true)->get();
}
//episode model
public function users(){
return $this->belongsToMany( 'App\User', 'completions', 'episode_id', 'user_id' );
}
The alternative would be to create your pivot as episode_user and laravel will auto detect it as the pivot, add a completed boolean to that table and it would function with just:
//user model
public function episodes(){
return $this->belongsToMany('App\Episode');
}
public function completedEpisodes(){
return $this->belongsToMany('App\Episode')
->wherePivot('completed','=', true)->get();
}
//episode model
public function users(){
return $this->belongsToMany('App\User');
}
Query if episode is complete:
//maybe, haven't tried this
//user
public function hasCompletedEpisode($id){
return $this->belongsToMany('App\Episode')->wherePivot('episode_id','=', $id)
->wherePivot('completed','=', true)->get();
}
//episode
public function hasCompletedEpisode($id){
$user_id = Auth::id();
return $this->belongsToMany('App\User')->wherePivot('user_id','=', $user_id)
->wherePivot('completed', true)->get();
}
If I was you, I would use a custom intermediate table. You can implement this as follows:
Migrations
Schema::create('users', function (Blueprint $table) {
$table->bigIncrements('id');
$table->string('name');
$table->timestamps();
});
Schema::create('episodes', function (Blueprint $table) {
$table->bigIncrements('id');
$table->string('name');
$table->timestamps();
});
Schema::create('watches', function (Blueprint $table) {
$table->bigIncrements('id');
$table->unsignedBigInteger('user_id');
$table->unsignedBigInteger('epsiode_id');
$table->boolean('completed');
$table->timestamps();
});
Models
class User extends Model
{
protected $guarded = [];
public function watchedEpisodes()
{
return $this->hasMany(Episode::class)->using(Watch::class);
}
public function watches()
{
return $this->hasMany(Watch::class);
}
}
class Episode extends Model
{
protected $guarded = [];
public function users()
{
return $this->hasMany(User::class)->using(Watch::class);
}
}
class Watch extends \Illuminate\Database\Eloquent\Relations\Pivot
{
protected $table = 'watches';
protected $guarded = [];
public static function create(User $user, Episode $episode, bool $completed = false)
{
$watch = new self();
$watch->user_id = $user->id;
$watch->epsiode_id = $episode->id;
$watch->completed = $completed;
$watch->save();
return $watch;
}
public function user()
{
return $this->hasOne(User::class);
}
public function episode()
{
return $this->hasOne(User::class);
}
}
Example Use
$user = User::create(['name' => 'Big Watcher']);
$episode1 = Episode::create(['name' => 'Episode 1']);
$episode2 = Episode::create(['name' => 'Episode 2']);
$episode3 = Episode::create(['name' => 'Episode 3']);
$episode4 = Episode::create(['name' => 'Episode 4']);
Watch::create($user, $episode1);
Watch::create($user, $episode2);
Watch::create($user, $episode3);
return $user->watchedEpisodes;

I want to return a user with a list of all the people they have referred by there username

I am developing a referral system in my software. I have gotten the referral right but I want to list all users the auth users have referred.
Note: I am writing an API endpoint so I cant use a relationship to display their name.
Here is my user model
public function referrals()
{
return $this->hasMany(Referral::class, 'user_id', 'id');
}
public function referrer()
{
return $this->hasOne(Referral::class, 'referred_by', 'id');
}
Note: referred_by is the person that has referred someone and user_id is the person referred
Here is my referral model
protected $fillable = ['user_id', 'referred_by', 'status'];
public function user()
{
return $this->belongsTo(User::class);
}
Here is my referrals migration
Schema::create('referrals', function (Blueprint $table) {
$table->id();
$table->integer('user_id')->unsigned()->references('id')->on('users');
$table->integer('referred_by')->unsigned()->references('id')->on('users');
$table->string('status')->nullable();
$table->timestamps();
});
User Model
// Referrals given by the user.
public function referralsGiven()
{
return $this->hasMany(App\Referral::class, 'referred_by', 'id');
}
Referral Model
//Person who got the referral
public function user()
{
return $this->belongsTo(App\User::class, 'user_id', 'id');
}
public function referredBy()
{
return $this->belongsTo(App\User::class, 'referred_by', 'id');
}
pluck collection method https://laravel.com/docs/7.x/collections#method-pluck
Controller
$user = User::with('referralsGiven.user')->find(Auth::user()->id);
$users_reffered_by_Auth_user = $user->referralsGiven->pluck('user');
OR
$referrals = Referral::with('user')->where('reffered_by', Auth::user()->id)->get();
$users_reffered_by_Auth_user = $referrals->pluck('user');

Laravel : get the top 10 users from answer's survey table

I want to display the top 10 users who are answering for the surveys
I tried this
public function topuser()
{
$bestuser = Answer::whereRaw('id = (select max(count(`id`)) from Answer)')->get();
return view('dashboard.top')->with('bestuser', $bestuser);
}
But it gives me an error.
Answer model:
class Answer extends Model
{
protected $fillable = ['answer'];
protected $table = 'answer';
public function survey() {
return $this->belongsTo(Survey::class);
}
public function question() {
return $this->belongsTo(Question::class);
}
}
Answer Migrate file :
public function up()
{
Schema::create('Answer', function (Blueprint $table) {
$table->increments('id');
$table->integer('user_id');
$table->integer('question_id');
$table->integer('survey_id');
$table->string('answer');
$table->timestamps();
});
}
How to fix that, please?
If you are looking for top users (those with the most posts), it would probably be easier to come from the User model angle. Thus, pull a count from the Answer relationship on the User model, something like this:
$bestuser = User::withCount('answers as answer_count')
->orderBy('answer_count', 'desc')
->take(10)
->get();
Or if you just want a simple list:
$bestuser = User::withCount('answers as answer_count')
->orderBy('answer_count', 'desc')
->take(10)
->pluck('answer_count', 'name');
you can do like this
public function topuser()
{
$bestuser = Answer::OrderBy('created_at', 'DESC')->take(10)->get();
return view('dashboard.top')->with('bestuser', $bestuser);
}

Retrieving relationships of relationships using Eloquent

I have a database with the following tables and relationships:
invoice ,order & product
each factor has several orders,and every orders point to a product.
Invoice Model:
class Invoice extends Model
{
public function orders()
{
return $this->hasMany(Order::class);
}
}
Order Model:
class order extends Model
{
public function invoice()
{
return $this->belongsTo(Invoice::class);
}
public function product()
{
return $this->belongsTo('App\Product');
}
}
Product Model:
class product extends Model
{
public function orders()
{
return $this->belongsToMany(Order::class);
}
}
the name of each order is foreign key to the product id,
$table->unsignedBigInteger('name')->references('id')->on('products')->default(0);
in my template i can showing the invoice with orders like this:
{{$invoice->title}}
{{$invoice->client_address}}
#foreach($invoice->orders as $order)
{{$order->name}}
${{$order->price}}
{{$order->qty}}
${{$order->qty * $order->price}}
#endforeach
with this function:
public function show($id)
{
$invoice = Invoice::with('orders')->findOrFail($id);
return view('admin.invoice.show.main', compact('invoice'));
}
how can show the name of product in orders recorde like this:
{{$order->product->name}}
im using before for single loop(e.g., product & category)
but in this example we have 3 relation and using a compact method before.
My product table is:
Schema::create('products', function (Blueprint $table) {
$table->bigIncrements('id');
$table->string('name');
$table->string('desc');
$table->string('price');
$table->string('image');
$table->string('count');
$table->string('status');
$table->unsignedBigInteger('category_id')->default(0);
$table->foreign('category_id')->references('id')->on('categories');
$table->timestamps();
});
Try this
$invoice = Invoice::with('orders.product')->findOrFail($id);
You can access using something like that
#foreach($invoice->orders as $order)
..
{{ $order->product->name }}
..
#endforeach
I think your relations is wrong...Each product can be within a few orders..so:
Product Model:
class product extends Model
{
public function orders()
{
return $this->belongsToMany('App\Order');
}
}
Order Model:
class order extends Model
{
public function product()
{
return $this->hasOne('App\Product');
}
}
right?
Then access with:
$invoices = Invoice::with('orders.product')->get();

Get property of relation in model

class Ingredient extends Eloquent {
public function unit() {
return $this->hasOne('IngredientUnit', 'id', 'unit_id');
}
}
class IngredientUnit extends Eloquent {
public function ingredient() {
return $this->belongsTo('Ingredient', 'unit_id', 'id');
}
public function getNamesAttribute() {
$quantity = $this->ingredient()->quantity; // <- ErrorException
...
}
}
ErrorException (E_UNKNOWN):
Undefined property: Illuminate\Database\Eloquent\Relations\BelongsTo::$quantity
If I remove brackets - $this->ingredient->quantity; - I get
ErrorException (E_UNKNOWN)
Trying to get property of non-object
How can I get property of relation object (belongsTo) ?
Schemas:
Schema::create('ingredients', function(Blueprint $table)
{
$table->increments('id');
$table->integer('recipe_id')->unsigned();
$table->integer('unit_id')->unsigned()->nullable();
$table->float('quantity')->unsigned();
...
});
Schema::create('ingredient_units', function(Blueprint $table)
{
$table->increments('id');
$table->string('name');
...
});
With these tables your relations are wrong.
You need to swap them, for it goes like this: unit hasOne/hasMany ingredients, ingredient belongsTo unit.
// Ingredient
public function unit()
{
return $this->belongsTo('IngredientUnit', 'unit_id', 'id');
}
// IngredientUnit - I don't think it's hasOne, rather hasMany
public function ingredients()
{
return $this->hasMany('Ingredient', 'unit_id', 'id');
}
Next, this can't work:
$this->ingredient()->quantity;
but this will work, as long as there is model returned from the relation:
$this->ingredient->quantity;
So basically you don't have related ingredient, that's why it returns null and your get the error.
First you should change:
$quantity = $this->ingredient()->quantity;
into
$quantity = $this->ingredient->quantity;
But in case no Ingredient is found, you get exception, so you should better change it into:
$ingredient = $this->ingredient;
$quantity = ($ingredient) ? $ingredient->quantity : 0;
to assign 0 if no ingredient is found;

Resources