How to get data from foreign key in laravel 5.1? - php

I am using laravel 5.1 for my new project smart search.
My problem is to get data from foreign key using like query for search of that table.
My database tables are:
category->id, name
search->id, category_id (foreign_key), question, answer, tags
My model code is:
category model
public function helpcenter() {
return $this->belongsTo('App\HelpCenter');
}
helpcenter model
public function category() {
return $this->hasOne('App\HelpCenterCategory', 'id', 'category_id');
}
My controller function for search query is
$queries = HelpCenter::has('category')
->where('questions', 'LIKE', '%'.$term.'%')
->orwhere('category_id.name','LIKE','%'.$term.'%')
->take(5)->get();

You will want to use whereHas() to subquery a relationship:
$queries = HelpCenter::whereHas('category', function($category) use ($term)
{
$category->where('name','LIKE','%'.$term.'%');
})
->orWhere('questions', 'LIKE', '%'.$term.'%')
->take(5)->get();
whereHas() is documented here: http://laravel.com/docs/5.1/eloquent-relationships#querying-relations

Related

Laravel 5.6.8 Eloquent and many to many + many to one joins

I have many to many connect with between user - cityarea.
I have also area which connect cityarea (One cityarea can connect only one area).
I have this database structure:
users
id
username
password
cityareas
id
name
area_id
cityarea_user
id
cityarea_id
user_id
areas
id
name
Next I have Models
User
public function cityareas()
{
return $this->belongsToMany('App\Cityarea');
}
Cityarea
public function area()
{
return $this->belongsTo('App\Area');
}
public function users()
{
return $this->belongsToMany('\App\User');
}
Area
public function cityareas()
{
return $this->hasMany('App\Cityarea');
}
QUESTION:
How I can get all users where areas.name = "South" with Eloquent ?
Thanks!!
By using whereHas, you can do:
$users = User::whereHas('cityareas.area', function ($query) {
$query->where('name', 'South');
})->get();
Jeune Guerrier solution is perfect, but you can use with() method of eloquent If you also need cityarea collection along with users collection.
$users = User::with('cityareas')->whereHas('cityareas.area', function ($query) {
$query->where('name', 'South');
})->get();
This is exactly what the belongs to many relationships is built for.
You simply have to do, Cityarea::where('name', 'South')->first()->users;
If you want to do something further with the query, e.g. sort by users created at, you can do
Cityarea::where('name', 'South')->first()->users()->orderBy('creaated_at', desc')->get();
Note that if there is no such Cityarea with name 'South', the ->first() query above will return null and therefore will fail to fetch the users.
A more performant way to do it programmatically is to use the whereHas approach as discussed in the comments below.

Laravel querying multiple related models

For example: I have these models in my application.
User, Profile, Interest.
I linked the users table with the profiles table by adding the user_id column in the profiles table. And I linked profiles and interests by using a pivot table (interest_profile), Which is (as obvious) will have two columns (profile_id, interest_id).
However, I want to query the users who are associated with a profile, too see who is associated with a particular interest, In other words: "select all users who are having (in their profiles) that particular interest".
I know that I can do this with raw SQL by joining the four tables and then use (where clause).. But I want to do it the Laravel way.
Thanks in advance.
First make sure you have your relationships setup correctly on your models like:
class User extends Model
{
public function profile()
{
return $this->hasOne(Profile::class);
}
}
class Profile extends Model
{
public function user()
{
return $this->belongsTo(User::class);
}
public function interests()
{
return $this->belongsToMany(Interest::class, 'interest_profile');
}
}
class Interest extends Model
{
public function profiles()
{
return $this->belongsToMany(Profile::class, 'interest_profile');
}
}
Then you can use whereHas() to constrain a query by a related model and dot notation for nested relations. So your query would be:
User::whereHas('profile.interests', function($query) use ($interestName) {
return $query->where('name', $interestName);
})->get();
That would just return a collection of users. If you wanted to return their profiles and interests as well you would use with():
User::whereHas('profile.interests', function($query) use ($interestName) {
return $query->where('name', $interestName);
})
->with('profile.interests')
->get();
Assuming the User model has a relationship profile and the Profile model has a relationship interests, you can do this.
$interest_id = 1;
$users = User::whereHas('profile', function ($query) use ($interest_id) {
$query->whereHas('interests', function ($query) use ($interest_id) {
$query->where('id', $interest_id);
});
})->get();

Laravel querying data through a pivot table

I have a table called 'projects' and a table called 'tags'. These 2 are connected through a pivot table named 'project_tag' so for example like this:
There is 1 record in the projects table with project_id 1
then in the 'project_tag' table there is this :
project_id 1 and tag_id 1
and tag_id 1 is "sometag" for example
Now my problem is I want to query all the projects that has "sometag" as name in the tags table.
Is there a way to do this? Or should I work with the id's instead of the tag values?
What my models look like:
Project model:
public function tags()
{
return $this->belongsToMany('App\Tag')->withTimestamps();
}
Tag model:
public function projects()
{
return $this->belongsToMany('App\Project');
}
I am a bit lost in my database structure :) I am fairly new to laravel
Many thanks in advance!
Assuming your model is called Project and your project-tag relationship is called tags(), this should work out for you:
Project::whereHas('tags', function ($query) {
$query->where('name', 'like', '%sometag%');
})->get();
To query projects by certain tags you ca do like this:
// Get projects by a single tag
$tag = 'mytag';
Project::whereHas('tags', function ($q) use ($tag) {
$q->whereName($tag);
// or $q->whereSlug($tag);
})->get();
// Get projects by multiple tags
$tags = ['mytag', 'othertag', 'iamtag'];
Project::whereHas('tags', function ($q) use ($tags) {
$q->whereIn('name', $tags);
})->get();
Or you can query projects from pivot table like this:
// Get projects by a single tag
$tag_id = 1;
Project::whereIn('id', function($q) use ($tag_id) {
$q->select('project_id')->from('project_tag')->where('tag_id', $tag_id);
})->get();
// Get projects by multiple tags
$tag_ids = [1, 2, 3];
Project::whereIn('id', function($q) use ($tag_ids) {
$q->select('project_id')->from('project_tag')->whereIn('tag_id', $tag_ids);
})->get();
Adding to what #TheFallen has said your models should look like this
class Tag extends Model
{
/**
* Get all of the tags project
*/
public function projects()
{
return $this->belongsToMany('App\Project');
}
}
class Project extends Model
{
/**
* Get all of the project's tag
*/
public function tags()
{
return $this->belongsToMany('App\Tag');
}
}
Then you can do this
Project::whereHas('tags', function ($query) {
$query->where('name', 'like', '%sometag%');
})->get();

Laravel search 'LIKE' query in two tables

I'm currently trying to set up a search bar that filters the results of two tables, books and categories.
I have setup relationships for both models where:
Book.php (Model) (table: id, b_name, b_author, cat_id)
public function bookCategory()
{
return $this->belongsTo('Category', 'cat_id', 'id');
}
Category.php (Model) (table: id, cat_name)
public function book()
{
return $this->hasMany('Book', 'cat_id', 'id');
}
BookController.php
public function getFilterBooks($input)
{
$books = Book::with('bookCategory')->where('**cat_name at category table**. 'LIKE', '%' . $input . '%'')->get();
return Response::json($books);
}
But obviously this won't work. The reason I'm doing this is because I want to allow users to use the same search bar to filter different columns (which I know how to do it in one table, but not two or more).
You can use that.
Book::whereHas('bookCategory', function($q) use ($input)
{
$q->where('cat_name', 'like', '%'.$input.'%');
})->get();
See more in http://laravel.com/docs/4.2/eloquent#querying-relations
EDIT:
Book::with('bookCategory')->whereHas('bookCategory', function($q) use ($input)
{
$q->where('cat_name', 'like', '%'.$input.'%');
})->get();
You get cat_name from relation.

Laravel 5 Model::with() behavior

I'm trying to get a simple list of products with a given category, using Laravel 5's (L5) Model::with() method. But it seems that L5 ignores the category where clause.
The relation in my Product model:
public function categories(){
return $this->belongsToMany('App\Category', 'categories_products');
}
In my Controller:
public function getByCategory($slug){
$return = Product::with(array('categories' => function($query) use ($slug){
$query->where('slug', 'like', $slug);
}))->paginate(60);
dd($return);
}
The result is a list of every product in my database, instead of just a list of those with the given category slug.
I'v tried to hardcode in some different where clauses, but all seems to be ignored. Am I missing something?
Eloquent doesn't use joins to query related data when using with(), but instead uses separate queries. In your example, it first fetches products and then fetches related categories.
You need to use has() or whereHas() to return only those products that have categories (slugs?).
public function getByCategory($slug){
$return = Product::has('categories')->with(array('categories' => function($query) use ($slug){
$query->where('slug', 'like', $slug);
}))->paginate(60);
dd($return);
}
Or:
public function getByCategory($slug){
$return = Product::whereHas('categories', function($query) use ($slug){
$query->where('slug', 'like', $slug);
})->paginate(60);
dd($return);
}
whereHas() adds a subquery that counts the number of relations. You should use DB::getQueryLog() to see the SQL that Eloquent produces. Makes it a lot easier to figure out what's going on!
Do you need to have an advanced subquery? If slug is defined as a column in product you can do this:
$return = Product::where('slug', 'like', $slug)->paginate(60);
dd($return);
Or if using the relations your query would look like this:
$return = Product::where('slug', 'like', $slug)->categories->paginate(60);
dd($return);

Categories