get count in relation table in yii2 Activerecord - php

I have two table for post and user. I want to show post count of user in users list gridview. In yii 1 I use this in model to define a relation for this purpose:
'postCount' => array(self::STAT, 'Post', 'author',
'condition' => 'status = ' . Post::ACTIVE),
...
User:find...().with('postCount').....
But i don't know how to implement this in Yii2 to get count of post in User:find():with('...') to show in gridview.
Anyone try this in yii2?

Here is an example of what I did and it seems to work fine so far. It was used to get a count of comments on a post. I simply used a standard active record count and created the relation with the where statement using $this->id and the primary key of the entry its getting a count for.
public function getComment_count()
{
return Comment::find()->where(['post' => $this->id])->count();
}
Just a passing it along...

You can try the code below:
User::find()->joinWith('posts',true,'RIGHT JOIN')->where(['user.id'=>'posts.id'])->count();
Or if you want to specify a user count:
//user id 2 for example
User::find()->joinWith('posts',true,'RIGHT JOIN')->where(['user.id'=>'posts.id','user.id'=>2])->count();
Please note that, posts is a relation defined in your User model like below:
public function getPosts()
{
return $this->hasMany(Post::className(), ['user_id' => 'id']);
}

Well still I think for those who it may concern, if you JUST want the count a select and not the data it will be better use this instead imho:
$count = (new \yii\db\Query())
->select('count(*)')
->from('table')
->where(['condition'=>'value'])
->scalar();
echo $count;

Related

Laravel : How to get all the rows from a table except the first one?

I want to select all the users in my table "User" except the first One cause its the admin,
im using this function index in my controller but it doesn't work .
public function index()
{
// this '!=' for handling the 1 row
$user = User::where('id', '!=', auth()->id())->get();
return view('admin.payroll',compact('user'))->with(['employees' => User::all()]);
}
Better to used here whereNotIn Method
Note: first you find the admin role users and create a static array
$exceptThisUserIds = [1];
$user = User::whereNotIn('id', $exceptThisUserIds)->get();
It's not a good idea to specify the admin user with just id. A better design would be using some sort of a flag like is_admin as a property of your User model.
Still you can use the following code to get the users who have an id greater than 1:
User::where('id', '>', 1)->get()
For getting data skipping the first one you should use skip() method and follow the code like below
public function index()
{
$user = User::orderBy('id','asc')->skip(1)->get();
return view('admin.payroll',compact('user'))->with(['employees' => User::all()]);
}

Eloquent limit relationship fields

I have the following relationships:
TheEpisodeJob hasOne TheEpisode
TheEpisodeJob hasMany TheJobs
I am successfuly retrieving all TheEpisodesJobs and TheSeriesEpisodes with all the fields in database (including sensitive information) using this command:
$jobs = TheEpisodeJob::with('TheEpisode')->get();
I would like to limit TheEpisode fields shown only for this case (public $hidden will not work)
EDIT
Let's say I need only title and description field from TheEpisode.
How can I achieve that?
As #Buglinjo pointed out you can scope the relationship when eager loading, however, if you're going to be doing this to only select specific columns you must included the related column in the select so that Eloquent knows which Model to attach the related data to.
This should give you what you want:
$jobs = TheEpisodeJob::with(['TheEpisode' => function ($query) {
$query->select('jobID', 'title', 'description');
}])->get();
Furthermore, if you then wanted to to get rid of the jobID as well you could do something like:
$jobs->transform(function ($job) {
$job->TheEpisode->transform(function ($item) {
unset($item->jobID);
return $item;
});
return $job;
});
Hope this helps!
As far as I understood you, you want to limit the results according to some more parameters. If I am right, you should add more queries, like:
->where, ->orwhere, ->select, ->whereNull
Here is the link for more queries. Hope it will help )
I saw an update, so then you need
->pluck('title', 'description');
for more information, go to the link above
You should do like this:
$jobs = TheEpisodeJob::with(['TheEpisode' => function($q){
$q->get(['title', 'description']);
//or
$q->pluck('title', 'description');
}])->get();
Note: pluck is getting as array not as Eloquent Object.

Laravel get one value from eager load

I've got this query in Laravel that's returning all forums with some extra information:
return Forum::with(['messages.user' => function($query){
$query->select('id', 'name');
}])->withCount('messages')->paginate(10);
but now it eager loads all related messages as well but I only need the author from a message. How could I get this result?
Assuming the table you have for your Message model is messages and that it has the columns forum_id and user_id, and the table for your User model is users you could just define a belongsToMany and get the information that way:
public function users()
{
return $this->belongsToMany(User::class, 'messages')->distinct();
}
then:
return Forum::with(['users' => function($query){
$query->select('users.id', 'users.name');
}])->withCount('messages')->paginate(10);
Hope this helps!
Without eager loading,
//for a particular forum
//Get a forum entity
$forum = Forum::find($id);
// Get its messages as a Collection
$forumMessages = $forum->messages;
// Iterate over each message on the Collection to find its author. This will look for id in the User model based on the 'author_id' stored by you in the message table.The collection $forumMessages will now have the author's name. This is just to give you an idea. Structure accordingly to your needs.
$forumMessages->each(function ($message){
$message->author = User::find($message->author_id)->name;
});
Try using
return Forum::with([
'messages' => function ($messages) {
return $messages->with([
'user' => function ($user) {
return $user->select('id', 'name');
}
])->select('id', 'author'); // you get author from messages
}
])->withCount('messages')->paginate(10);
This also eager loads but you only get id and author. id is needed to make the relationship with user.

Pull out the specific data when the relation ship is many to many in laravel

I want to ask about how to pull out the specific data (some columns) from the Laravel database
Here is my code :
User Model :
public function events(){
return $this->belongsToMany('App\Events')->withTimestamps();
}
Event Controller :
public function showjson(){
$user_id=Auth::user()->id;
$events = DB::table('events')
->select(
'id',
'calendar_title as title',
'startdate as start',
'enddate as end',
'calendar_color as backgroundColor',
'calendar_color as borderColor')
->where('user_id',$user_id)
->get();
$user=Auth::user();
$eventData=$user->events;
return $eventData;
}
I have already the relationship between this two, I can get the data through this :
$user = Auth::user();
$eventData = $user->events;
But I want to get specific columns by name, like in select code above.
Would that be another way that I can call the specific data and change the column name?
i want display in json only the calendar_title, calendar_des only.
You can use lists to retrieve a list of column values, take a look at Database Query Builder Retrieving Results section :
$user->events->lists('calendar_title','calendar_des');
If you want to return Json format you can use toJson() method :
$user->events->lists('calendar_title','calendar_des')->toJson();
Hope this helps.

Laravel - Unnecessary columns still being loaded with select statement

I am wanting to limit a controller's function's result to only pass certain columns into the view.
It is necessary because it will be used within an API, and so I need the results to be as streamlined as possible.
I have done this successfully with the following function:
public function getIndex()
{
$alerts = Criteria::select('id', 'user_id', 'coordinate_id', 'alert_name')
->with(['coordinate' => function($q){
$q->select('name', 'id');
}])
->get();
}
So it only returns id, user_id and coordinate_id from the criteria table.
However on the function below, I am using a has query (to access a relationship), and thus, using with afterwards to limit the columns, but it's still returning all:
public function getMatches()
{
$matches = Criteria::select('id')
->has('alerts')
->with(['alerts' => function ($q){
$q->select('id', 'headline', 'price_value', 'price_type');
}])
->with('alerts.user.companies')
->get();
}
But, for example, it's still returning the description column, which is in the alert's table. The with query proceeding the has query clearly isn't working (but it's presenting no errors).
Also, the ->with('alerts.user.companies') query, is returning everything within the user's table, which is also unnecessary. How can I return just the companies table data, that's related to the user, who's related to the alert?
Your help would be greatly appreciated.
Depending what you want to achieve, you could use $hidden property to hide columns you don't want to return as json or arrays.
In your Alert model you could do:
protected $hidden = ['description'];
And this way description field won't be returned.
If it's not the way for you (sometimes you want to return description) you could create extra relationships where you limit fields from database.
You could for example create the following relationship:
public function alertsSimple() {
return $this->hasMany('Alert')->select('id', 'headline', 'price_value', 'price_type', 'criteria_id');
}
Also maybe in your select the problem is that you don't use foreign key at all. You could also try with:
$q->select('id', 'headline', 'price_value', 'price_type','criteria_id');
instead of
$q->select('id', 'headline', 'price_value', 'price_type');

Categories