I have some customfield functionality on my site where users can add custom fields to a model.
I've just found that if you enter data into one of the fields the same field won't show up for another model because of the way I get the empty fields for a model
public function Customfield()
{
return $this->hasMany(Customfield::class);
}
public function getEmptyCustomfields($model)
{
return $this->has('customfield', '<', 1)
->select('customfieldslabels.id as label_id', 'customfieldslabels.datatype as datatype', 'customfieldslabels.label_name as label_name',
'customfieldslabels.customfield_tab_id as customfield_tab_id', 'customfieldstabs.name as name')
->join('customfieldstabs', 'customfieldstabs.id', '=', 'customfieldslabels.customfield_tab_id')
->where('customfieldstabs.model', '=', $model)
->get();
}
public function getEmptyCustomfieldsByTab($tabIDm)
{
return $this->has('customfield', '<', 1)->where('customfield_tab_id', '=', $tabID)->get();
}
This is what I had originally and I realised that if a label has a field that is assigned to another model then the relationship exists and won't return as empty for another model.
So I'm trying to also check against the model ID now but I'm not quite sure how to use the model ID while checking the relationship
public function Customfield()
{
return $this->hasMany(Customfield::class);
}
public function customfieldByModel($modelID)
{
return $this->has('customfield' => function ($query) use ($modelID){
$query->where('model_id', '=', $modelID);
})->get();
}
public function getEmptyCustomfields($model, $modelID)
{
return $this->has($this->customfieldByModel($modelID), '<', 1)
->select('customfieldslabels.id as label_id', 'customfieldslabels.datatype as datatype', 'customfieldslabels.label_name as label_name',
'customfieldslabels.customfield_tab_id as customfield_tab_id', 'customfieldstabs.name as name')
->join('customfieldstabs', 'customfieldstabs.id', '=', 'customfieldslabels.customfield_tab_id')
->where('customfieldstabs.model', '=', $model)
->get();
}
public function getEmptyCustomfieldsByTab($tabIDm, $modelID)
{
return $this->has($this->customfieldByModel($modelID), '<', 1)->where('customfield_tab_id', '=', $tabID)->get();
}
I would like to return empty fields for one model that they haven't been filled in for yet.
They return just find once there is data for a model assigned to a field as it doesn't need to check for empty fields anymore.
UPDATE
I've tried using a left join which I think will work but I can't get to the method because I get an error saying: 'The method name must be a string'
I changed this
public function getEmptyCustomfieldsByTab($tabID, $modelID)
{
return $this->has($this->customfieldByModel($modelID), '<', 1)->where('customfield_tab_id', '=', $tabID)->get();
}
To this:
public function getEmptyCustomfieldsByTab($tabID, $modelID)
{
return $this->has('customfieldbymodel', '<', 1)->where('customfield_tab_id', '=', $tabID)->get();
}
But now I can't send the $modelID as a parameter. Is it possible to sned a parameter while doing a has?
MY SOLUTION
I have created a protected variable on the model that just gets reassigned everytime.
protected $modelID;
public function customfieldByModel()
{
return $this->hasMany(Customfield::class)->where('model_id', '=', $this->modelID);
}
public function getEmptyCustomfields($model, $modelID)
{
$this->modelID = $modelID;
return $this->has('customfieldByModel', '<', 1)
->select('customfieldslabels.id as label_id', 'customfieldslabels.datatype as datatype', 'customfieldslabels.label_name as label_name',
'customfieldslabels.customfield_tab_id as customfield_tab_id', 'customfieldstabs.name as name')
->join('customfieldstabs', 'customfieldstabs.id', '=', 'customfieldslabels.customfield_tab_id')
->where('customfieldstabs.model', '=', $model)
->get();
}
public function getEmptyCustomfieldsByTab($tabID, $modelID)
{
$this->modelID = $modelID;
return $this->has('customfieldByModel', '<', 1)->where('customfield_tab_id', '=', $tabID)->get();
}
Related
i have this index function that will show data from two different tables:
public function index()
{
$complaints = DB::table('complaint')
->select(['complaint.id','complaint.createdDate','complaint.user_id','complaint.createdDate','complaint.complaint_title','tbl_users.phone','tbl_users.email'])
->join('tbl_users', 'complaint.user_id', '=', 'tbl_users.id')
->get();
return view('admin.complaints',compact('complaints'));
}
and in the next function i want to show a single row using the same thing above by 'id'
i tired this:
public function show($id)
{
$complaints = DB::table('complaint')
->select(['complaint.id','complaint.createdDate','complaint.user_id','complaint.createdDate','complaint.complaint_title','tbl_users.phone','tbl_users.email'])
->join('tbl_users', 'complaint.user_id', '=', 'tbl_users.id')
->where('id', $id)->first()
->get();
return $complaints;
}
but i'm getting this error
Call to undefined method stdClass::get()
For creating where statements, you can use get() and first() methods. The first() method will return only one record, while the get() method will return an array of records , so you should delete first() , so the code should be like that .
public function show($id)
{
$complaints = DB::table('complaint')
->select(['complaint.id','complaint.createdDate','complaint.user_id','complaint.createdDate','complaint.complaint_title','tbl_users.phone','tbl_users.email'])
->join('tbl_users', 'complaint.user_id', '=', 'tbl_users.id')
->where('id', $id)
->get();
return $complaints;
}
For example I can use:
$address = $user->address
which will return the addresses for the user.
// User.php (model)
public function address()
{
return $this->hasMany(Address::class, 'refer_id', 'id');
}
public function billingAddress()
{
return $this->address()
->where('type', '=', 1)
->where('refer_id', '=', $this->id)
->first();
}
However, I would like to return the BillingAddress for the user depending on this where clause. How do I do it?
EDIT:
If I use this inside... OrderController#index it returns correctly
$orders = Order::with('order_fulfillment', 'cart.product', 'user.address', 'payment')->get();
return new OrderResource($orders);
However, If I change it to:
$orders = Order::with('order_fulfillment', 'cart.product', 'user.billingAddress', 'payment')->get();
return new OrderResource($orders);
I get this error:
Symfony\Component\Debug\Exception\FatalThrowableError
Call to a member function addEagerConstraints() on null
One option is you can use whereHas in your query. For example,
$orders = Order::with('order_fulfillment', 'cart.product', 'user.address', 'payment')
->whereHas(
'address', function ($query) {
$query->where('type', '=', 1)
->first();
}
)->get();
return new OrderResource($orders);
This is one option. try to dd($orders) an find if its working.
You had an another option like this, in your model
public function address()
{
return $this->hasMany(Address::class, 'refer_id', 'id');
}
Add relations like
public function billingAddress()
{
return $this->hasOne(Address::class, 'refer_id', 'id')->where('type', 1);
}
And
public function shippingAddress()
{
return $this->hasOne(Address::class, 'refer_id', 'id')->where('type', 2);
}
Then in your query,
$orders = Order::with('order_fulfillment', 'cart.product', 'user.address','user.billingAddress', 'user.shippingAddress', 'payment')->get(); return new OrderResource($orders);
How do I create brackets around my orWhere:
public function categories()
{
return $this->belongsToMany('App\Category', 'user_category')->orWhere('default', 1);
}
So it is converted to this:
where (`user_category`.`user_id` = ? or `default` = 1)
Currently the brackets here are missing and mess up the whole query. I tried for example:
public function categories()
{
$join = $this->belongsToMany('App\Category', 'user_category')
->orWhere('default', 1);
return $this->where(function ($query) use ($join) {
return $join;
});
}
But here I am loosing my model and getting Call to undefined method Illuminate\Database\Query\Builder::...
You can use advanced where clause like:
Model::where(function ($query) {
$query->where('a', '=', 1)
->orWhere('b', '=', 1);
})->where(function ($query) {
$query->where('c', '=', 1)
->orWhere('d', '=', 1);
});
Or nested clause like:
Model::where(function($query)
{
$query->where('a', 'like', 'keyword');
$query->or_where('b', 'like', 'keyword');
})
->where('c', '=', '1');
Are you trying to get all the categories related to an user and the categories where the default field is 1?
If that is the case:
public function categories()
{
return $this->belongsToMany('App\Category');
}
public function relatedCategories()
{
return App\Category::all()->where('default',1)->merge($this->categories);
}
The relatedCategories() method should return a collection with the desired categories. Take in care that the non-related categories but with default=1 will not have the pivot object, because these categories doesn't exist in your pivot table.
I can get the list of Likes that User 1 did on a Media from Store 1
$medias = User::find(1)->likes()->with('media')->whereHas('media', function($q) {
$q->where('store_id', '=', 1);
})->get();
But i need to retrieve the list of medias, so i tried
$medias = User::find(1)->likes()->with('media')->whereHas('media', function($q) {
$q->where('store_id', '=', 1);
})->get()->media;
But then i get
Undefined property: Illuminate\Database\Eloquent\Collection::$media
class User extends Model
{
public function likes()
{
return $this->hasMany('App\Like');
}
}
class Media extends Model
{
public function store()
{
return $this->belongsTo('App\Store');
}
public function likes()
{
return $this->hasMany('App\Like');
}
}
class Like extends Model
{
public function user()
{
return $this->belongsTo('App\User');
}
public function media()
{
return $this->belongsTo('App\Media');
}
}
This is because you get media separate for each like. You should use:
$likes = User::find(1)->likes()->with('media')->whereHas('media', function($q) {
$q->where('store_id', '=', 1);
})->get();
foreach ($likes as $like) {
$media = $like->media;
// now you can do something with your media
}
EDIT
If you want to get only media, you should add to your User model the following relationship:
public function medias()
{
return $this->hasManyThrough('App\Media','App\Like');
}
Now to get your media, you should do :
$medias = User::find(1)->medias()->where('store_id', '=', 1)->get();
Made it work with
$store->medias()->whereHas('likes', function($q) use($user) {
return $q->where('user_id', '=', $user->id);
});
I'm having trouble on the eager loading.
Let's say I have models of Members, TrainingCategory, TrainingCategoryResult and Registration
Member Model:
public function registration() {
return $this->hasMany('Registration', 'member_id');
}
public function trainingResults(){
return $this->hasMany('trainingResult', 'member_id');
}
public function trainingCategoryResults() {
return $this->hasMany('TrainingCategoryResult', 'member_id');
}
TrainingCategory Model:
public function trainings() {
return $this->hasMany('Training', 'id');
}
public function trainingCategoryResults() {
return $this->hasMany('trainingCategoryResult', 'category_id');
}
TraningCategoryResult Model:
public function category() {
return $this->belongsTo('TrainingCategory', 'id');
}
public function member() {
return $this->belongsTo('Member', 'id');
}
Registration Model:
public function course() {
return $this->belongsTo('Course', 'course_id');
}
public function member() {
return $this->belongsTo('Member', 'id');
}
I am trying to eager load all the registration info and its related info including the TraningCategoryResult info but I not sure how to get that TraningCategoryResult which required two foreign keys (category_id and member_id), is there any way to do that?
Here is my code atm:
$members= Member::where(function($query) use ($id, $site) {
$query
->where('id', '=', $id)
->where('site', '=', $site);
});
$members= $members
->with('registration.course',
'registration.course.traningCategories',
->get(['member.id']);
Thank you.
This will not work Member::with('categoryResult')->with('registration')->get()
You can make a new relation in Member Model
public function categoryResult()
{
return $this->belongsTo('Category')->with('Registration');
}
//and then call
Member::with('categoryResult')->get();
You could use a few options to achieve that:
OPTION 1: create a variable relationship
Change your relation in the Member model
public function trainingCategoryResults($category_id = null) {
if(empty($category_id))
return $this->hasMany('TrainingCategoryResult', 'member_id');
else
return $this->hasMany('TrainingCategoryResult', 'member_id')
->where('category_id', $category_id);
}
The code above might have limitations and it doesn't take advantage of many laravel features, but it will work.
OPTION 2: Access from relationship
You can keep everything as is, and load as follow:
$members= Member::where(function($query) use ($id, $site) {
$query
->where('id', '=', $id)
->where('site', '=', $site);
})
->where('id', $member_id) // set the id of the memeber
->with(array(
'traningCategoryResults' => function($q)use($category_id){
$q->where('category_id', $category_id); // This makes sure you get only desired results
}
))
In this way you will have only what you need, assuming you know the $category_id