Laravel simplify a database query with relations - php

I'm just started to work with Laravel and think its a pretty good framework.
But there is a lot to learn and i can mostly find everything in the user guide except this part:
I'm trying to get items from my database they are sorted with a category id that relates to a other table item_catagories in this table are stored:
id
name
parent
In my url of the website I use the name of the category instead of the id.
http://example.com/catagory/subcatagory
when subcatagory has a value I want to search for the related items.
I now have it like this:
if($subcategory){
$foo = ItemCategories::where(['group' => $category, 'name'=> $subcategory])
->get()[0]->id;
$data['products'] = Items::where('category_id', $foo)->get();
}
but there must be a much simpler way to get the same results.
I hope someone can help me to understand how I can do it better
Edit
I forgot to add the relation code:
The item class:
public function categorie(){
return $this->hasOne('App\ItemCategories');
}
The categorie class:
public function items(){
return $this->belongsTo('App\Items');
}

You can use Laravel Eloquent's relationships for this. On your category model:
public function items() { return $this->hasMany('Items'); }
Once you've done that, on a category, you can do $category->items to fetch all of its related items.
Incidentally, when you do this:
->get()[0]
you can just do this:
->first()

If you wish to bring your results already populated, one way to do this is:
$foo = ItemCategories::where(['group' => $category, 'name'=> $subcategory])->with('items')->first();

Related

yii gridview filter with external api and one to many

I am struggling with gridview filter. In my code I have two getters.
public function getPhone()
{
return UserPhone::find()->where(['user_id' => $this->id])->orderBy('updated_at DESC')->one();
}
public function getDevice()
{
return ExternalAPiHelper::getDeviceInfo($this->id); // this will make a call to external db, and fetching result from there.
}
I am trying to do a filter for $user->phone->country and $user->device->type I am not sure how I can get the results from both of these in a clean manner. Currently, I am fetching the id from the above 2 and then using the result array in $query->where(['in', 'id', $ids]);
Is there any better way to do this?
use hasMany or hasOne method for relation as per requirement
public function getPhone(){
return $this->hasOne(UserPhone::className(),['user_id' => 'id'])
->orderBy('updated_at DESC');
}
than add this relation in main query where you want to apply filter
$query = ....Model query where you define above relations
$query->joinWith('phone')
$query->andWhere(['LIKE','country',$countryName])
explore more about yii2 relations

YII2 how do i handle many to many relationships?

I am new to YII2 and I have a problem with my relationships:
I have Users and Category. They have a m-m relationship. Now i would like to see the Categories a user has. For that I made a table named "user_category" which looks as follows:
In my models i have the following code as suggested in
How do I work with many-to-many relations in Yii2 :
public function getUsers(){
return $this->hasMany(TabUser::className(), ['intUserID' => 'intUserID'])
->viaTable('user_category', ['intCategoryID' => 'intCategoryID']);
}
public function getCategories(){
return $this->hasMany(TabCategory::className(), ['intCategoryID' => 'intCategoryID'])
->viaTable('user_category', ['intUserID' => 'intUserID']);
}
Then i linked them together:
if($user->validate()) {
$user->link('categories', $category);
}
var_dump($user->getCategories());
But this does not return my categories it returns the following:
Does anybody know what I do wrong?
Thanks for your time and help!!
Try to divide your expression like this, should work:
$categories = $user->categories;
var_dump($categories);
Method getCategories() returns ActiveQuery object instead of models. If you need to get an array of category models you must use magical property categories. For example:
var_dump($user->categories);

How to return model rows where id is equal to id on other table with relations in laravel?

For example I have:
// Returns all projects
$projects = Projects::all();
To return categories, belonging to project, I use relationships and can do something like:
foreach($projects as $project) { ...show $project->categories... }
I need only specific projects, which are followed by specific user. On my projects_followers table I have user_id and project_id.
To retrieve projects which were followed I have this peace of code:
$projects = Project::rightJoin(DB::raw('(select * from projects_followers group by project_id) projects_followers'),'projects_followers.project_id','=','projects.id')->get();
// Note: This code doesn't include specifuc user_id.
It does retrieve specific rows, but the problem with this code is that laravel relationhips dont work on them. For example $project->categories return empty.
// Relationship
public function categories()
{
return $this->belongsToMany('App\Category');
}
How do I retrieve my model specific rows and make relationships to work?
Actually your question is:
How do I get projects liked/followed by Auth/Logged in User ?
Unfortunately you described it in such a way that it looks something else, anyways. Lets try to find the solution and for this I would like to use something like this:
$projects = Auth::user()->favorite_projects;
So how we can implement this to work, first of all the User Model should contain the method favoriteProjects so lets create it:
public function favoriteProjects()
{
return $this->belongsToMany(
'App\Project',
'projects_followers', // This table already exists as you mentioned
'user_id',
'project_id'
);
}
That's it. You will be able to load the projects followed by the current user and other relationship methods will work on every single project as well.
My workaround:
// I don't know how to create empty collection, so impossible conditions here.
$projects = Project::where('id', 0)->get();
$follows = DB::table('projects_followers')->where('follower_id', Auth::user()->id)->get();
foreach($follows as $follow) {
$project = Project::where('id', $follow->project_id)->first();
$projects = $projects->add($project);
}

Laravel Pivot Tables - accessing from inverse relation-table

UPDATE: Apparently $problem->userRatings()->count(); returns 1, so a record does exist, but the script still doesn't enter the foreach loop for some reason...
UPDATE 2/Solution: I feel incredibly foolish, but the reason it isn't working, is that I was calling foreach($problem->userRatings() as $rating){ when it should be foreach($problem->userRatings as $rating){ (dynamic property)
In my database I have problem_ratings, problems, and users. I have models for users and problems, and problems_ratings is a pivot table between problems and users with an extra 'content' column that stores the numeric rating value (1-5).
The many-to-many relation in my Problem model:
public function userRatings(){
return $this->belongsToMany('User', 'problem_ratings', 'author_id', 'problem_id')->withPivot('content');
}
The many-to-many relation in my User model:
public function problemRatings(){
return $this->belongsToMany('Problem', 'problem_ratings', 'author_id', 'problem_id')->withPivot('content');
}
When creating a problem_ratings element, I attach it to my user model like so:
$user->problemRatings()->attach($problem->id, array('content' => $val));
I can access the pivot table through the user, but when I try this:
foreach($problem->userRatings() as $rating){
echo "In average loop";
$newAverage = ($rating->pivot->content) + $newAverage;
}
it doesn't find any records, even though some exist in the database. Am I using these relations correctly?
Thanks in advance!
In the Problem model I think your relationship should looks something like :
public function userRatings(){
return $this->belongsToMany('User', 'problem_ratings', 'problem_id', 'author_id')->withPivot('content');
}
When using a foreach loop over something like this, you need to use dynamic properties (ie. without parentheses):
foreach($problem->userRatings as $rating){ instead of foreach($problem->userRatings() as $rating){

Laravel: Eloquent, many to many relationship, how do I eager load only the id of related model?

I'm using Eloquent to select a single row from a table called "businesses". Any business can be associated with one or more "Industries". I've set this up in the business model such that:
public function industries() {
return $this->belongsToMany('Industry');
}
In the controller I am eager loading the industries when I select the model:
$mdl = Business::find($business_id);
$mdl->load('industries');
return Response::json($mdl);
This returns something like this:
{"id":123,"name":"My Business","address":"123 Easy Street","industries":[{"id":1,"name":"Technology"},{"id":7,"name":"Research"}]}
This is almost what I need. I'm looking to just have the response look like this instead:
{"id":123,"name":"My Business","address":"123 Easy Street","industries":[1,7]}
I know I could just do something like this:
$ind = array();
foreach($mdl->industries as $industry) $ind[] = $industry->id;
$mdl->industries = $ind;
I'd rather not do that though. It's ugly and it makes my code look very non-laravel.
The reason I'd like to do it this way in the first place is because when I SAVE the business I am going to use something like this:
$mdl->industries()->sync(Input::get('industries'));
The SYNC method only accepts an array of IDs so I'd rather the JSON object going to and from the server have the same format. I'd really rather not an array of objects when I load it and an array of ids when I save. Is there a best practice for this sort of thing or an easier way to accomplish what I'm trying to do?
Thanks!
$mdl = Business::with('industries')->find($business_id)->toArray();
$mdl['industries'] = array_pluck($mdl['industries'], 'id');
return $mdl;
If you use this a lot, add the following method to your Business model:
public static function getWithIdustryIds ($business_id)
{
$mdl = Business::with('industries')->find($business_id)->toArray();
$mdl['industries'] = array_pluck($mdl['industries'], 'id');
return $mdl;
}
Your model relationship should be
public function industries() {
return $this->belongsToMany(Industry::class);
}
Assuming that your pivot table has an industry_id column you can eager load only the industry_ids using
$mdl = Business::with(['industries' => function($query){
$query->select('industry_id');
}])->get()

Categories