How to get 1 row in pivot table? - laravel

In laravel 9 I have table pivot table defined :
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');
...
});
and having in both models methods with belongsToMany
I can refer articles of a vote as :
$voteArticles = $vote->articles;
I got all related articles, but how can O get only 1 row if I have $articleId ?
Thanks!

That can be achieved in a number of ways by querying the relations:
$vote->articles()->where('id', $articleId)->first();
$vote->articles()->whereKey($articleId)->first();
$vote->articles()->find($articleId);
$vote->articles()->findOrFail($articleId);
Or in your example, you already have a collection of articles. We can also do this:
$vote->articles->find($articleId);
$vote->articles->findOrFail($articleId);

Related

Laravel query where column value is greater than sum of related model column values

I have two tables transactions and transaction_allocations. One transaction can have many allocations.
Transaction Model
Schema::create('transactions', function (Blueprint $table) {
$table->bigIncrements('id');
$table->timestamps();
$table->foreignId('contact_id')->constrained();
$table->decimal('amount',19,4)->nullable();
});
Allocation Model
Schema::create('transaction_allocations', function (Blueprint $table) {
$table->bigIncrements('id');
$table->timestamp('created_at');
$table->foreignId('transaction_id')->nullable()->constrained();
$table->foreignId('bill_id')->nullable()->references('id')->on('bills');
$table->decimal('amount',19,4)->nullable();
});
Relationship in Transaction Model
public function allocations(){
return $this->hasMany(TransactionAllocation::class);
}
I need to query all transactions where the transaction amount is greater than the sum of all allocated amounts for that transaction. (Basically finding transaction which has unallocated balances).
Transaction::where('contact_id',$id)->where('amount','>',sum of allocations)->get();
How do I achieve it?
I was able to create an accessor to do this calculation and find an unallocated amount. But seems like accessors cannot be used in where. I don't want to load all transactions and then filter it as it will be too much.
I want to query and get filtered lines directly. How do I do it?
I think Having Raw is better to compare two column.
Transaction::where('contact_id',$id)
->with('allocations')
->whereHas("allocations",function ($query){
$query->havingRaw('transactions.credit>sum(amount)');
$query->groupBy('transaction_id');
})->orDoesntHave("allocations")
->get();
if query fails then try to 'strict' => false in database.php for mysql connection

Check if parent category hasn't been published when calling its related articles?

I use laravel-nestedset for creating the category of articles.
Laravel: 8 / laravel-nestedset: 5.0.3
Table categories
Schema::create('categories', function (Blueprint $table) {
$table->increments('id');
NestedSet::columns($table);
$table->boolean('publish')->default(true);
...
Table articles
Schema::create('articles', function (Blueprint $table) {
$table->increments('id');
$table->integer('category_id')->unsigned()->nullable();
$table->foreign('category_id')->references('id')->on('categories');
...
I have created a branch and a sub-branch in the category table like this:
news > politics
I have also created two articles and insert them into the 'news' branch and 'politics' branch.
article1 in news
article2 in politics
Everything works!
Now I have a scenario. I want to get all the articles that are only in the published categories. (publish = 1).
I try this:
$query = \App\Article;
$query->where(function($query)
{
$query->whereHas('category' , function ($query) {$query->where('publish' , true ); });
});
However, this code works only for the current article category (not for the parent of that category).
Let me explain more with an example.
pulish in "news" is false. (pulish = 0)
pulish in "politics" is true. (pulish = 1)
Now I want to get all articles with (pulish=1) in its category. The above query code returns me 'article2.' I expect no article to be returned to me. Because even "politics" is publish=1, its parent (news) is publish=0, so related articles should not be published. How can change the query code to support the parent (or even more its top parents)?

Instert data in two tables with relation Laravel

I want to insert with a form into two tables that are related with a foreign key,
First you need to create an order with customername, and then be forwarded to next form to insert multiple articles.
This is how my tables are made:
Schema::create('returnorders', function (Blueprint $table) {
$table->increments('id');
$table->string('firmaname');
$table->string('contacperson');
$table->string('email')->unique();
$table->string('ordernumber');
$table->string('customername');
$table->timestamps();
});
Schema::create('returnarticles', function (Blueprint $table) {
$table->increments('id');
$table->integer('order_id')->unsigned();
$table->foreign('order_id')->references('id')->on('returnorders');
$table->string('articlenumber');
$table->string('return_quantity');
$table->string('return_quality');
$table->string('return_reason');
$table->string('images');
});
My question is now, can i make one form where i can put multiple articles or should I make two forms, and that you will be forwarded from the first one to the next one?
My second question is, can I do this in one function in my controller or should i make two functions?
Help me out please, and if it's possible show me how to make my function.
Thanks
If your question is how to save these related models, then you should look at the documentation on Inserting and Updating related models:
Documentation
Your code could look something like this:
$returnOrder = ReturnOrder::create([
'firmaname' => $validatedInput['firmaname'],
'contactperson' => $validatedInput['contactperson'],
....
]);
$returnOrder->returnArticles()->save(ReturnArticle::create([
'articlenumber' => $validatedInput['articleNumber'],
...
]));

Grouping rows which has same value in same column

I am having a hard to achieve this grouping issue. I have a master table that contains names in name column. And there is another table connected to master table by belongsTo relationship and contains plans for each names.
The problem is, in master table some names repeating a couple of times. The structure is like below.
| name |
--------------------
| Mark
| Mark
| Jack
| Alistair
| Oliver
| Jack
I want to group rows if has same value(name). At the same time try to avoid to lose connected tables data. Because each names has own plan in another table.
Master::select('name')
->groupBy('name')
->get();
If I do something like above I am grouping names. But this time of course I am losing the connected table's data.
Is there anyway to achieve, what I wanted here.
Here is the table structure and Models for the connection between tables.
master table
Schema::create('masters', function (Blueprint $table) {
$table->bigIncrements('id');
$table->string('name');
$table->timestamps();
});
plan table
Schema::create('plans', function (Blueprint $table) {
$table->bigIncrements('id');
$table->integer('master_id');
$table->string('website');
$table->string('url');
$table->string('plan_name');
$table->timestamps();
});
master model
public $with = ["plan];
public function plan()
{
return $this->hasMany("App\Plan");
}
plan model
public function master()
{
return $this->belongsTo("App\Master");
}
Group by doesnot allows us to select all the column so you can join and use order by.
DB::table('masters as m')->select(m.*,p.*)
->join('plans as p', 'p.master_id', '=','m.id')
->orderBy('m.name', 'asc')
->orderBy('p.id', 'asc')

One to Many relationship in Laravel Eloquent giving undefine method

I am having the said problem when defining one to many relationship with two models, the Student and Enrollment. When accessing the table from another table using:
$enrollment = App\Enrollment::first();
$enrollment->students()->first_name;
Im getting :
Illuminate\Database\QueryException with message 'SQLSTATE[42S22]: Column not found: 1054 Unknown column 'students.enrollment_id' in 'where clause' (SQL: select * from `students` where `students`.`enrollment_id` = 1 and `students`.`enrollment_id` is not null)'
However when I use :
$enrollment = App\Enrollment::first();
$enrollment->students()->first_name;
Im getting :
PHP error: Undefined property: Illuminate\Database\Eloquent\Relations\HasMany::$first_name on line 1
Can someone help me on this?
Enrollment
protected $fillable = [
'subject_code',
'subject_description',
'section',
'schedule',
'room_no',
'no_of_units'
];
public function students()
{
return $this->hasMany('App\Student');
}
Student
protected $fillable = [
'enrollments_id',
'student_no',
'first_name',
'last_name',
'middle_name',
'birthdate',
'fathers_name',
'mothers_name',
'phone_no',
'degree_id',
'city_id',
'address'
];
public function enrollment()
{
return $this->belongsTo('App\Enrollment');
}
Here's the table for the students and enrollment accordingly
Schema::create('students', function (Blueprint $table) {
$table->increments('id')->unsigned();
$table->integer('enrollments_id')->unsigned();
$table->integer('student_no');
$table->foreign('enrollments_id')->references('id')->on('enrollments')->unsigned();
$table->string('first_name');
$table->string('last_name');
$table->string('middle_name');
$table->date('birthdate');
$table->string('fathers_name');
$table->string('mothers_name');
$table->string('phone_no');
$table->string('address');
$table->integer('city_id');
$table->integer('degree_id');
$table->timestamps();
});
Schema::create('enrollments', function (Blueprint $table) {
$table->increments('id');
$table->string('subject_description');
$table->string('subject_code');
$table->time('schedule');
$table->string('room_no');
$table->integer('no_of_units');
$table->string('section');
$table->timestamps();
});
First of all what you exactly want
as per your question i am assuming you want 'enrollment has many students', for this relationship you need enrolment_id in students table not student_id in enrollment table.
and after that use
$students= Enrolment::find(id)->students;
it will return all students with the required enrollment id
That normal since you're trying to get property first_name from hasMany object, you should use get() method if you want to get Collection of objects (in your case collection of students) :
$enrollment->students()->get();
And if you want to get the first name you should specify the object you want to get the first_name from it, e.g :
$enrollment->students()->first()->first_name;
$enrollment->students()->last()->first_name;
If you want to get the attribute first_name of all the students you should use lists method, e.g :
$enrollment->students()->lists('first_name');
Output: collection of all students first names.
Hope this helps.
Update :
Try to remove ->unsigned() in :
$table->increments('id')->unsigned();
and also in :
$table->foreign('enrollments_id')->references('id')->on('enrollments')->unsigned();
When you call relations on an eloquent object it actually return you the relation not the exact objects
for eg: in your case
$enrollment->students() will return the relation
where as
$enrollment->students will return the eloquent object ( in belongs to, has one relations ) and collection/array of eloquent object/objects(in one to many , many to many relations )
simply if you are using it as an attribute you will get the actual result and relation query if it is called as a function
even if you get the relation you can get the results by calling get on top of that
$enrollment->students()->get()

Resources