I am trying to search multiple data from two related tables. To be specific I want to get only "name column" from the users table and the rest of the columns from the posts table. But whenever I tried to search it prints the following error "Trying to get property 'name' of non-object"
Below is my user model
<?php
namespace App;
use App\Mail\NewUserWelcomeMail;
use Illuminate\Notifications\Notifiable;
use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Support\Facades\Mail;
class User extends Authenticatable
{
use Notifiable;
protected $fillable = [
'name', 'email','phone', 'username', 'password',
'admin', 'address', 'description', 'approved_at',
];
protected $hidden = [
'password', 'remember_token',
];
public function posts()
{
return $this->hasMany(Post::class)->orderBy('created_at', 'DESC');
}
}
And post model
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Post extends Model
{
protected $guarded = [];
public function user()
{
return $this->belongsTo(User::class);
}
}
And my Controller
public function showcampaign(User $user) {
$q = Input::get( 'q' );
if( !empty( $q ) ) {
$showcampaign = User::join('posts','posts.user_id','users.id')
->where('name','LIKE','%'.$q.'%')
->orWhere('caption','LIKE','%'.$q.'%')
->orWhere('description','LIKE','%'.$q.'%')
->orWhere('duration','LIKE','%'.$q.'%')
->orWhere('amount','LIKE','%'.$q.'%')
->get();
if(count($showcampaign) > 0) {
return view('admin.campaignreport', ['show' => $showcampaign]);
} else {
return redirect('/campaignreport')->with('status', 'No Details found. Try to search again !');
}
} else {
$showcampaign = Post::all();
return view('admin.campaignreport')->with('show', $showcampaign);
}
}
Please help thanks
As you have already declared the relations within the Model So you can use whereHas and also orWhereHas
So
$showcampaign = SampleReception::query()
->whereHas('posts',function(\Illuminate\Database\Eloquent\Builder $query) use ($q){
return $query->where('caption', 'LIKE','%'.$q.'%')
->orWhere('description', 'LIKE','%'.$q.'%')
->orWhere('duration', 'LIKE','%'.$q.'%')
->orWhere('amount', 'LIKE','%'.$q.'%');
})
->orWhere('name','LIKE','%'.$q.'%')
->get();
For any issues leave a comment
Try.. use where instead of orwhere
$showcampaign = User::join('posts','posts.user_id','users.id')
->where('name','LIKE','%'.$q.'%')
->Where('caption','LIKE','%'.$q.'%')
->Where('description','LIKE','%'.$q.'%')
->Where('duration','LIKE','%'.$q.'%')
->Where('amount','LIKE','%'.$q.'%')->get();
I think you need to use a reference table for where clause.
$showcampaign = User::join('posts','posts.user_id', '=', 'users.id')
->where('users.name','LIKE', '%'.$q.'%')
->orWhere('posts.caption', 'LIKE','%'.$q.'%')
->orWhere('posts.description', 'LIKE','%'.$q.'%')
->orWhere('posts.duration', 'LIKE','%'.$q.'%')
->orWhere('posts.amount', 'LIKE','%'.$q.'%')
->get();
If you define relationship correctly then use:
$showcampaign = SampleReception::with(['posts' => function($query) use($q) {
return $query->where('caption', 'LIKE','%'.$q.'%')
->orWhere('description', 'LIKE','%'.$q.'%')
->orWhere('duration', 'LIKE','%'.$q.'%')
->orWhere('amount', 'LIKE','%'.$q.'%');
}])
->orWhere('name','LIKE','%'.$q.'%')
->get();
I use scope query to create search functions. It makes my code more flexible and easy to understand.
Here is how you can do this.
In your "user" Model, you have to write "scopeFunctionName". you can write any functionName with scope. And in your Controller, you can simply call this function whenever you need as functionName(). and pass here your search term from request as functionName(request(['search']))
And now as you have declared relations for these tables to search data from related tables, try using this code in your user Model
public function scopeFilter($query, array $filters)
{
/*
Hey $query! whenever u get 'search term' in URL, call the function.
If ['search'] exists or != null, then pass its value to the function
else return false and don't execute the $query. If value exists,
Then the function will execute the query and returns a result.
*/
$query->when(
$filters['search'] ?? false,
fn ($query, $search) =>
$query
->whereHas('users', function ($query) use ($search) {
return $query
->where('name', 'like', '%' . $search . '%')
})
->where('name', 'like', '%' . $search . '%')
->orWhere('caption', 'like', '%', . $search . '%')
->orWhere('description', 'like', '%', . $search . '%')
->orWhere('id', $search)
);
}
And in Controller, you can pass the value to the scope function as:
public function index()
{
return view('posts.index', [
'show' => Post::all()->filter(request(['search']))->with('user')
]);
}
Note: The code above has not been tested but it might solve your problem.
Related
I wanna ask about some nested relation using whereHas query in laravel, well for the first I will explain the model first before I going through into my main case.
this is my model :
StockIn.php
class StockIn extends Model {
protected $primaryKey = "id_stock_in";
/* this only column that I wanna show, and skip the else column */
protected $fillable = ['stock_in_id_type'];
public function type_of_items() {
return $this->belongsTo('App\TypeOfitem', 'stock_in_id_type');
}
}
TypeOfItem.php
class TypeOfItem extends Model {
protected $primaryKey = "id_type_item";
/* this only column that I wanna show, and skip the else column */
protected $fillable = ['type_id_item'];
public function items() {
return $this->belongsTo('App\Item', 'type_id_item');
}
public function stock_ins() {
return $this->hasMany('App\StockIn');
}
}
Item.php
class Item extends Model {
protected $primaryKey = "id_item";
/* this only column that I wanna show, and skip the else column */
protected $fillable = ['item_id_common_unit'];
public function common_units() {
return $this->belongsTo('App\CommonUnit', 'item_id_common_unit');
}
public function type_of_items() {
return $this->hasMany('App\TypeOfItem');
}
}
CommonUnit.php
class CommonUnit extends Model {
protected $primaryKey = "id_common_unit";
/* this only column that I wanna show, and skip the else column */
protected $fillable = [/* describe column */];
public function items() {
return $this->hasMany('App\Item');
}
}
I already describe all of my model, as you can see all table (child) have some relation to each parent like :
stockIn -> typeOfItem (relation between child and parent)
typeOfItem -> Item (relation between child and parent)
Item -> CommonUnit (relation between child and parent)
so for the question is how to make some query to getting data in nesting relationship when I do search for all data in child or parent? I already made the query but the result is not same with my expectation or null, it can be said that.
StockInController
$getData = StockIn::with(['type_of_items' => function ($query) {
$query->select('id_type_item', 'type_id_item', 'code_type_of_item', 'type_of_item')
->with(['items' => function ($query) {
$query->select('id_item', 'item_id_common_unit', 'name_item')
->with(['common_units' => function ($query) {
$query->select('id_common_unit', 'name_unit');
}]);
}]);
}])
->with(['stock_out_left_join' => function ($query) {
$query->select('id_stock_out', 'stock_out_id_stock_in');
}])
->whereHas('type_of_items', function ($query) use ($search) {
$query->where('code_type_of_item', 'like', "%{$search}%");
})
->whereHas('type_of_items.items', function ($query) use ($search) {
$query->orWhere('name_item', 'like', "%{$search}%");
})
->whereHas('type_of_items.items.common_units', function ($query) use ($search) {
$query->orWhere('name_unit', 'like', "%{$search}%");
})
->orWhere('created_by', 'like', "%{$search}%")
->orWhere('edited_by', 'like', "%{$search}%")
->get()
->toArray();
Oh ya I will send example data for my query in this bellow :
but when I do search with some keyword is not worked, for example when I do type "adaptor", the result is empty or nothing show on my data, so what I must to do? Thank you
Okay for a while I was think about my problem finally I got the answer. Okay for sharing to everyone I will explain a little bit for the answer.
So the query what I wrote on the controller, I change into this :
$getData = StockIn::with(['type_of_items' => function ($type_of_item) {
$type_of_item->select('id_type_item', 'type_id_item', 'code_type_of_item', 'type_of_item')
->with(['items' => function ($item) {
$item->select('id_item', 'item_id_common_unit', 'name_item')
->with(['common_units' => function ($common_unit) {
$common_unit->select('id_common_unit', 'name_unit');
}]);
}]);
}])
->with(['stock_out_left_join' => function ($stock_out_left_join) {
$stock_out_left_join->select('id_stock_out', 'stock_out_id_stock_in');
}])
->whereHas('type_of_items', function ($type_of_items_search) use ($search) {
$type_of_items_search->where('code_type_of_item', 'like', "%{$search}%")
->orWhere('type_of_item', 'like', "%{$search}%");
})
->orWhereHas('type_of_items.items', function ($items_search) use ($search) {
$items_search->where('name_item', 'like', "%{$search}%");
})
->orWhereHas('type_of_items.items.common_units', function ($common_units_search) use ($search) {
$common_units_search->where('name_unit', 'like', "%{$search}%");
})
->orWhere('created_by', 'like', "%{$search}%")
->orWhere('edited_by', 'like', "%{$search}%")
->get()
->toArray();
As you can see my new query has a new parameter in every with function and I was naming all the parameter with different name, and not like first name before query, so the problem is the ambiguous paramater in every single with function because this query based on nested relation so I must make the parameter name different each other. Or you want make them into split one by one and not using the nested with function you can use this query too, I put on this bellow :
$getData = StockIn::with(['type_of_items' => function ($query) {
$query->select('id_type_item', 'type_id_item', 'code_type_of_item', 'type_of_item');
}])
->with(['type_of_items.items' => function ($query) {
$query->select('id_item', 'item_id_common_unit', 'name_item');
}])
->with(['type_of_items.items.common_units' => function ($query) {
$query->select('id_common_unit', 'name_unit');
}])
->with(['stock_out_left_join' => function ($query) {
$query->select('id_stock_out', 'stock_out_id_stock_in');
}])
->whereHas('type_of_items', function ($query) use ($search) {
$query->where('code_type_of_item', 'like', "%{$search}%")
->orWhere('type_of_item', 'like', "%{$search}%");
})
->orWhereHas('type_of_items.items', function ($query) use ($search) {
$query->where('name_item', 'like', "%{$search}%");
})
->orWhereHas('type_of_items.items.common_units', function ($query) use ($search) {
$query->where('name_unit', 'like', "%{$search}%");
})
->orWhere('created_by', 'like', "%{$search}%")
->orWhere('edited_by', 'like', "%{$search}%")
->get()
->toArray();
I already tried that query and it's work too (with the same name parameter in every single with function).
Sorry for my bad english. This is my first post here and I'm a kind of noob in developpment..
Thanks to a lot of reading and some tutorials, I managed to build a small Laravel application.
For various reasons, I decided to include Livewire and it's great.
However, I'm facing some issues in searching and filtering entries from different models and relationships.
Image of what I'm trying to do
I have a model called Seance and I can search through Grade, Theme and Product models (2, 3 & 5 on the image).
My Seance Model :
class Seance extends Model
{
use SoftDeletes;
protected $guarded = [];
public function product()
{
return $this->belongsTo('App\Product');
}
public function theme()
{
return $this->belongsTo('App\Theme');
}
public function specialty()
{
return $this->belongsTo('App\Specialty');
}
public function grade()
{
return $this->belongsTo('App\Grade');
}
public function courses()
{
return $this->hasMany('App\Course');
}
public function category()
{
return $this->belongsTo('App\Category')->withTrashed();
}
/**
* #return \Illuminate\Database\Eloquent\Relations\BelongsToMany
*/
public function specialties(): BelongsToMany
{
return $this->belongsToMany('App\Specialty', 'seance_specialty', 'seance_id', 'specialty_id');
}
public function scopeSearch($query, $term)
{
$term = "%$term%";
$query->where(function($query) use ($term){
$query->where('id', 'like', $term)
->orWhere('name', 'like', $term)
->orWhere('slug', 'like', $term)
->orWhere('subtitle', 'like', $term)
->orWhere('description', 'like', $term)
->orWhereHas('grade', function($query) use ($term){
$query->where('name', 'like', $term);
})
->orWhereHas('product', function($query) use ($term){
$query->where('name', 'like', $term);
})
->orWhereHas('theme', function($query) use ($term){
$query->where('name', 'like', $term);
})
->orWhereHas('category', function($query) use ($term){
$query->where('name', 'like', $term);
});
});
}
}
But I would like to search through the point 4 that is related to 3 and through the point 6 that is related to 5 and I don't know how to do that.
The point 3 is a Model called Theme and it belongs to a Model called Discipline (point 4)
public function discipline()
{
return $this->belongsTo('App\Discipline');
}
The point 5 is a model called Produt and it belongs to a model called Coursetype (point 6)
public function coursetype()
{
return $this->belongsTo('App\Coursetype');
}
I know there is join to do somewhere but I don't exactly know where...
Here's my Livewire component :
use WithPagination;
protected $paginationTheme = 'bootstrap';
public $search = "";
public $paginate = 5;
public $selectedGrade = null;
public $selectedProduct = null;
public $selectedCategory = null;
public $selectedTheme = null;
public $selectedDiscipline = null;
public function render()
{
return view('livewire.seances-table', [
'seances' => Seance::with('product', 'theme', 'specialty', 'grade', 'courses', 'category', 'specialties')
->when($this->selectedGrade, function($query){
$query->where('grade_id', $this->selectedGrade);
})
->when($this->selectedProduct, function($query){
$query->where('product_id', $this->selectedProduct);
})
->when($this->selectedCategory, function($query){
$query->where('category_id', $this->selectedCategory);
})
->when($this->selectedTheme, function($query){
$query->where('theme_id', $this->selectedTheme);
})
->when($this->selectedDiscipline, function($query){
$query->where('discipline_id', $this->selectedDiscipline);
})
->search(trim($this->search))
->paginate($this->paginate),
'grades' => Grade::all(),
'products' => Product::all(),
'categories' => Category::all(),
'themes' => Theme::all(),
'disciplines' => Discipline::all()
]);
}
Also, I would like to filter through the Disciplines (point 4) but I get this error.
SQLSTATE[42S22]: Column not found: 1054 Unknown column 'discipline_id' in 'where clause'
I know why I'm getting this error, but I don't know how to fix it.
Sorry if all this is not very clear.
Any help would be much appreciated.
Thanks you all and cheers from France
since discipline_id is under themes table which is related to Seance model.
I suggest doing
$query->where('theme.discipline_id', $this->selectedDiscipline);
How to get value relationships in eloquent laravel
here is my model Food
class food extends Model
{
protected $table = 'food';
protected $fillable = [
'name'
];
public function foodType()
{
return $this->belongsTo(Food_type::class, 'food_type_id');
}
}
here is my food_type model
class food_type extends Model
{
protected $table = 'food_type';
protected $fillable = [
'name', 'description'
];
public function getFood()
{
return $this->hasMany(Food::class);
}
}
I want to get food_type.name in food_type table .How can I query like this
$search = $request->search
$food = Food::with(['foodType'])
->where('name', 'like', '%'.$search.'%')
->orWhere('foodType.name', 'like', '%'.$search.'%')->get();
Relationships are not included with joins when you use eager loading. Review the documentation as it covers how to use whereHas and other relationship related methods.
$food = Food::with(['foodType'])
->where('name', 'like', '%'.$search.'%')
->orWhereHas('foodType' function($q) {
$q->where('name', 'like', '%'.$search.'%');
})
->get();
My code is like this :
public function getFavoriteStore($param)
{
$num = 20;
$q = $param['q'];
$location = $param['location'];
$result = $this->store_repository->whereHas('favorites', function ($query) use($q, $location) {
$query->select('stores.id', 'stores.name', 'stores.photo','stores.address')
->where('stores.status', '=', 1)
->where('favorites.favoritable_type', 'like', 'App\\\Models\\\Store');
if($location)
$query->where('stores.address', 'like', "%$location%");
if($q) {
$query->where('stores.name', 'like', "%$q%")
->where('stores.address', 'like', "%$q%", 'or');
}
$query->orderBy('favorites.updated_at', 'desc');
})->paginate($num);
return $result;
}
It works
But, order by does not work
Besides, the above query, I only select some field. But when I debug the query, the result display all field
It seems there are still wrong
Is there anyone who can help me?
I follow this tutorial : https://laravel.com/docs/5.3/eloquent-relationships#querying-relationship-existence
UPDATE
My favorite model is like this :
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class Favorite extends Model
{
protected $fillable = ['user_id', 'favoritable_id', 'favoritable_type'];
public function favoritable()
{
return $this->morphTo();
}
}
My store model is like this :
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class Store extends Model
{
protected $fillable = ['name', 'address', 'phones', 'address', 'email'];
public function favorites()
{
return $this->morphMany(Favorite::class, 'favoritable');
}
}
Favorites table has field id, user_id, favoritable_id, favoritable_type
Stores table has field id, name, address, phones, addres, email, photo
The relation between store and favorite are id (stores table) and favoritable_id (favorites table)
whereHas() is only used to check the existence of a relation so, you have to use join() to order the results with related table
$query = $this->store_repository
->join('favorites', function ($join) {
$join->on('stores.id', '=', 'favorites.favoritable_id')
->where('favorites.favoritable_type', 'like', 'App\\\Models\\\Store');
})
->where('stores.status', '=', 1)
->select('stores.id', 'stores.name', 'stores.photo','stores.address');
if($location)
$query->where('stores.address', 'like', "%$location%");
if($q) {
$query->where('stores.name', 'like', "%$q%")
->where('stores.address', 'like', "%$q%", 'or');
}
$result = $query->orderBy('favorites.updated_at', 'desc')->paginate($num);
I have not tested it but I am pretty sure it will work.
Currently my HomeController looks like this:
class HomeController extends BaseController {
public function getHome()
{
$scripts = Script::select('script.*', DB::raw('COALESCE(SUM(vote.rating), 0) as rating'))
->leftJoin('script_vote as vote', 'vote.script_id', '=', 'script.id')
->with('tags')
->orderBy('rating', 'desc')
->orderBy('views', 'desc')
->groupBy('id')
->paginate(8);
return View::make('home')->with('scripts', $scripts);
}
public function postSearch()
{
$input = array(
'query' => Input::get('query'),
'sort_col' => Input::get('sort_col'),
'sort_dir' => Input::get('sort_dir'),
);
$scripts = Script::select('script.*', DB::raw('COALESCE(SUM(vote.rating), 0) as rating'))
->leftJoin('script_vote as vote', 'vote.script_id', '=', 'script.id')
->where('title', 'LIKE', '%' . $input['query'] . '%')
->orderBy($input['sort_col'], $input['sort_dir'])
->orderBy('views', 'desc')
->groupBy('id')
->with('tags')
->paginate(8);
Input::flash();
return View::make('home')->with('scripts', $scripts);
}
}
As you can see, I'm using (almost) the same big query twice. I would like to call the postSearch() function within the getHome() function and give the three parameters (query = '', sort_col = 'rating', sort_dir = 'desc') with it. Is this possible?
If you plan on using this frequently I would move this out of your controller and put it in your Model as a Custom Query Scope. This really doesn't have a place in the Controller even as a private function.
public function scopeRating($query)
{
return $query->select('script.*', DB::raw('COALESCE(SUM(vote.rating), 0) as rating'))
->leftJoin('script_vote as vote', 'vote.script_id', '=', 'script.id')
->with('tags')
->orderBy('rating', 'desc')
->orderBy('views', 'desc')
->groupBy('id');
}
This could then be called like this
Script::rating();
here are a few possibilities:
write a private function getScripts(...) within the controller (not so sexy)
add a getScripts(...) function on your Scripts model (so-lala sexy)
create a service provider to encapsulate the model(s) and inject them into the controller