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.
Related
In my application there are users making pictures of items. The relationship structure is as follows:
Categories -> SubCategories -> Items -> Pictures -> Users
Now, there's also a shortcut relationship called itemPics between categories <--> pictures so that the number of pictures uploaded by a user can be quickly counted per category using withCount().
These are the relationships on the Category model:
public function subcategories()
{
return $this->hasMany('App\SubCategory');
}
public function items()
{
return $this->hasManyThrough('App\Item', 'App\SubCategory');
}
public function itemPics()
{
return $this->hasManyThrough('App\Item', 'App\SubCategory')
->join('pictures','items.id','=','pictures.item_id')
->select('pictures.*');
}
My problem is getting the number of pictures that a user has gathered per category. The itemPics_count column created by withCount() always has the same value as items_count, even though the number of related models for both relations given by with() are different in the JSON output.
$authorPics = Category::with(['SubCategories', 'SubCategories.items' => function ($q) use ($author_id) {
$q->with(['pictures' => function ($q) use ($author_id) {
$q->where('user_id', $author_id);
}]);
}])
->with('itemPics') /* added this to check related models in output */
->withCount(['items','itemPics'])
->get();
dd($authorPics);
This does not make sense to me. Any help is greatly appreciated.
Withcount() function is not work properly if relations include join. it works only table to table relations.
public function itemPics()
{
return $this->hasManyThrough('App\Item', 'App\SubCategory')
->select('pictures.*');
}
This solution was worked for me:
//...
public function itemPics()
{
return $this->hasManyThrough('App\Item', 'App\SubCategory');
}
Then you can do something like this:
$authorPics = Category::with(['SubCategories', 'SubCategories.items' => function ($q) use ($author_id) {
$q->with(['pictures' => function ($q) use ($author_id) {
$q->where('user_id', $author_id);
}]);
}])
->with('itemPics') /* added this to check related models in output */
->withCount(['items','itemPics' => function($query){
$query->join('pictures','items.id','=','pictures.item_id')
->select('pictures.*');
}])
->get();
dd($authorPics);
Link to more information about Laravel withCount function here https://laravel.com/docs/8.x/eloquent-relationships#counting-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();
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();
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
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);