Using group by and count with laravel eloquent - php

I have a Forum and Forum Response Model with following database tables:
forum.id
forum_response.id
forum_response.forum_id
forum_response.user_id
forum_response.text
The Forum Model relationship is:
public function responses()
{
return $this->belongsToMany(ForumResponse::class, 'forum__responses');
}
and the Forum Response relationship:
public function Forum()
{
return $this->belongsTo(Forum::class);
}
I would like to get the number of unique responses for a specific Forum, grouped by the user_id. I have tried the following return $this->hasMany(ForumResponse::class)->groupBy('user_id')->count(); but this is returning a higher value than I'm expecting.

Even though, I feel you have something wrong in your structure. But for now, you have an error in your relationships. Just change belongsToMany to hasMany
change this
public function responses()
{
return $this->belongsToMany(ForumResponse::class, 'forum__responses');
}
to this
public function responses()
{
return $this->hasMany(ForumResponse::class, 'forum__responses');
}

Related

Laravel relationships: How do I retrieve all courses to which a collection of assessment tests belong?

Am not a pro in neither PHP nor Laravel and I think I am cornered. In my assessment app, I have courses, lessons and assessment tests. An assessment_test has many to one relationship with lesson. lesson also has many to one relationship with course.
Now here is the problem, How do I retrieve all courses to which a collection of assessment_tests belong?
As shown in the code snippets provides, I tried to get around this by manually looping through the collection and saving the courses to an array but I got some weird error.
Trying to get property 'course' of non-object
Here is my problematic function
public function index()
{
$attempts=AssessmentAttempt::all();
$i=0;
$courses=array();
foreach ($attempts as $attempt) {
// dd($attempt->lesson->course);
$courses[$i++]=$attempt->lesson->course;
}
dd(array_unique($courses));
return view('achievements.index', ['attempts'=>$attempts, 'courses'=>$courses]);
}
AssessmentAttempt model
public function lesson()
{
return $this->belongsTo(Lesson::class);
}
Lesson model
public function course()
{
return $this->belongsTo(Course::class);
}
public function assessmentAttempts()
{
return $this->hasMany(AssessmentAttempt::class);
}
in the assesment_modal define the relation ship with course and make the course id column as a foreign_key in the assesment_model table
return $this->hasMany(Course::class, 'foreign_key');
also design the relation in course model
return $this->belongsTo(Assesment_Model::class);

Make Laravel Accessor return query results

UPDATED:
I'm trying to add my own attribute with subquery results to the results of main query.
Now, I have Many-To-Many relation between three tables: Tournaments, Participants and Users.
Here is the defining of relation in Tournaments model:
public function users() {
return $this->belongsToMany('App\User', 'Participants', 'Id_tourn', 'Id_user')->withPivot('Rating');
}
The structure of tables is:
Users:
-Id
-Name
Participants:
-Id
-Id_user
-Id_tournament
-Final
-Final_place
Tournaments:
-Id
-Name
I need to have extra Winners attribute in my final query result where I'll have info of first three places.
Following the documentation, I've created an accessor and tried different variants:
That just freeze the system. Nothing happenes and in 30 second I get timeout error.
public function getWinnersAttribute() {
return Tournaments::where("Id","=",$this->attributes['Id'])->where("Finals","=",1)->limit(3)->orderBy("Final_place","asc")->get();
}
This returns an error that "finals" column is not fount in Tournaments table, so $this doesn't have relation:
public function getWinnersAttribute()
{
return $this->where("Finals","=",1)->limit(3)->orderBy("final_place","asc")->get();
}
This returns blank white page without anything:
public function getWinnersAttribute()
{
return $this->with('users')->where("Finals","=",1)->limit(3)->orderBy("final_place","asc")->get();
}
This return "Winners" attribute empty:
public function getWinnersAttribute()
{
return $this->with("users")->where("Finals","=",1)->limit(3)->orderBy("final_place","asc");
}
I've created $appends variable to apply the accessor: protected $appends = ['Winners'];
However, I've checked the accessor, it works. If I return just:
public function getWinnersAttribute()
{
return "123";
}
it works fine and I get "123" inside "winners" attribute of main query result.
The main query is:
Tournaments::with(['users'])->get();
The Finals column is in pivot table of Many-To-Many relation.
UPDATED:
When I try to return query to that Model without relation:
public function getWinnersAttribute($value)
{
return $this->where("Finals",'=',2);
}
I get nothing in winners attribute as well. Like the subquery is not executed.
And if I add get() in the end of return:
return $this->where("Finals",'=',2)->get();
I get blank white page.
How can I solve that problem?
Thanks a lot.
If the getWinnersAttribute is on the Tournament model that means you already have a Tournament model you are calling by doing for example Tournament::find(1)->winners In your attribute you are trying too find the model again, and that could make it a forever loop trying to find a new one already having one etc. try using $this instead
public function getWinnersAttribute()
{
return $this->where("finals","=",1)->limit(3)->orderBy("final_place","asc")->get();
}

Laravel belongsToMany not returning results

I have the following schema set up:
users:
id
departments:
id
department_user:
id
department_id
user_id
I also have the following relationships set up:
User Model
public function departments()
{
return $this->belongsToMany('App\Resources\Eloquent\Models\Department', 'department_users');
}
Department Model
public function users()
{
return $this->belongsToMany(User::class, 'department_users');
}
For some reason, when I am trying to access through the user model $user->departments, it doesn't work - but $department->users does.
Outputting the eloquent query is as follows:
select `departments`.*, `department_users`.`user_id` as `pivot_user_id`, `department_users`.`department_id` as `pivot_department_id` from `departments` inner join `department_users` on `departments`.`id` = `department_users`.`department_id` where `department_users`.`user_id` is null
I can't seem to figure out why it is looking to see if department_users.user_id is null, when it should be looking for the user's id.
Any ideas?
Why don't you set up your models like it is suggested in the documentation here:
So your models would look something like this:
User Model
public function departments()
{
return $this->belongsToMany('path\to\your\model\Department');
}
Department Model
public function users()
{
return $this->belongsToMany(path\to\your\model\User);
}
Eloquent will join the two related model names in alphabetical order.So you don't need extra arguments when defining your relationship and Laravel also by default, makes model keys present on the pivot object. And then you can do something like this:
$department = path\to\your\model\Department::find(1);
foreach ($department->users as $user) {
echo $user;
}
For some reason, if I make the relationship the following - it works.
return $this->belongsToMany(Department::class, 'department_users')->orWhere('department_users.user_id', $this->id);
If anyone knows why, please let me know

Eloquent model with multiple one to many to same table

I have an existing table structure I'm trying to model with Eloquent (Laravel 4) which has 3 one to many relationships to the same table. Basically, each unit can have a home location, a current location and a customer's location.
Note, I've simplified this for the question. The unit table has an unitid, and a homeid, currentid and customerid. Each of homeid, currentid and customerid is a foreign key in the mysql database to the location table on the locationid. The location table also has a name field.
In my Unit model, I have
public function home() { return $this->belongsTo('Location', 'homeid', 'locationid'); }
public function current() { return $this->belongsTo('Location', 'currentid', 'locationid'); }
public function customer() { return $this->belongsTo('Location', 'customerid', 'locationid'); }
In my Location model I have
public function homes() { return $this->hasMany('Unit', 'homeid', 'locationid'); }
public function currents() { return $this->hasMany('Unit', 'currentid', 'locationid'); }
public function customers() { return $this->hasMany('Unit', 'customerid', 'locationid'); }
Now, in my Units controller I have
$units = Unit::with(['home','current','customer'])->paginate(10);
return View::make('units.index')->with('units',$units);
In units.index view I can refer to
foreach ($units as $unit) {
...
$unit->home->name //<-- this works
$unit->current->name //<-- this doesn't
$unit->customer->name //<-- neither does this
...
}
As fas as I can tell from the documentation, I've done everything right. Why would the first FK work, but neither of the two others?
Edit: the error given on the lines marked as not working (when uncommented) is
"Trying to get property of non-object"
The models are correct, thanks #deczo for pointing out the obvious.
The error was mine - not checking for null on the relations before trying to reference the related records.
I.E. $unit->current->name needed to be is_null($unit->curent)?'':$unit->current->name
A stupid PEBKAC error :-)
--Quog

Semi-complex Eloquent query

I am working on a eloquent query to compile a newsletter but I have hit a brick wall.
What I'm trying to do is create a UI where the user can select a publication and date. Ideally it would then compile a list of that publication's categories (where stories > 0) and stories belonging to it.
Here are my 3 models:
Story
public function user()
{
return $this->belongsTo('User', 'user_id');
}
public function publication()
{
return $this->belongsTo('Workbench\Dailies\Publication', 'publication_id');
}
public function category()
{
return $this->belongsTo('Workbench\Dailies\Category', 'category_id');
}
Publication
public function story()
{
return $this->belongsTo('Workbench\Dailies\Story');
}
public function stories()
{
return $this->hasMany('Workbench\Dailies\Story', 'publication_id');
}
public function category()
{
return $this->belongsTo('Workbench\Dailies\Category', 'publication_id');
}
Category
public function story()
{
return $this->belongsTo('Workbench\Dailies\Story', 'category_id');
}
public function publications()
{
return $this->belongsTo('Workbench\Dailies\Publication', 'publication_id');
}
public function stories()
{
return $this->hasMany('Workbench\Dailies\Story', 'category_id');
}
Here is how my tables look:
Story
content
user_id
publication_id
category_id
publish_date
Publication
id
name
Category
id
name
publication_id
Here is what I currently have in my Repository.
public function compileStories($input)
{
return Category::has('stories', '>', 0)
->with('publications')
->whereHas('stories', function ($query) use ($input)
{
$query->where('publish_date', $input['publish_date']);
$query->where('publication_id', $input['publication_id']);
});
}
Am I headed in the right direction here or is there any way to improve the code above? It is not currently functioning as expected.
There are a couple of things I see here that may help straighten you out.
First - Some of the models have strange relationships without knowing more about your whole application. The Story model does not need the publication relationship since it can be retrieved through the category relationship, unless you have need of it otherwise. The Category model does not need both a story and a stories relationship, again, unless there's more to the story I don't know. In your example, you should only need the hasMany relationship. The Publication model only needs the categories relationship.
Now, after some cleanup of the models, let's look at your query. Using the category model to return your results seems completely appropriate for your desired results. You can check for the publication without having to dive into your stories, though. I haven't tested it, but you may not need the use $input line since $input is in the larger scope. You're also missing a conditional check in your where statments in the whereHas clause. The query should be able to be simplified as follows:
Category::where('publication_id', '=', $input['publication_id'])
->whereHas('stories', function($query)
{
$query->where('publish_date', '=', $input['publish_date']);
})
->get()

Categories