merge models octoberCMS, including attached files - laravel

How can I merge two models including attached files?
$hotels = collect([Hotel::get()]);
$tours = collect([Tours::get()]);
$merged = $hotels->merge($tours);
this works and merges collections, but it's doesnt include attacheOne/attachMany
How can I do this?
Thanks

Two things.
Firstly, when you execute an Eloquent query, it returns a Collection instance automatically. You don't need to wrap the result inside a Collection yourself.
Second, to eager load model relations, you need to specify them using with.
E.g.
$hotels = Hotels::with('location', 'rooms')->get();
$tours = Tours::with('location')->get();
$merged = $hotels->merge($tours);

It doesn't include relations because you haven't loaded any.
Rewrite it like this (replace the contents of with(...) with relations you want to load):
$hotels = Hotel::with(['relation1', 'relation2'])->get();
$tours = Tours::with(['relation1', 'relation2'])->get();
$merged = $hotels->merge($tours)->all();
Also results of model queries are automatically put in a collection, so you don't need to do the collect(...) part.

Related

Best approcah for getting the object in the foreach loop in laravel using eloquent?

I have some properties and i want to get the object for each property, currently, I am using the eloquent in the foreach loop like this as shown in the image that will describe the best..
but it is really not a good approach because if I have 100 published property I will making 100 calls to the DB... and that is not correct?
I need a suggestion and a proper solution to this query?
Thanks in advance
Before foreach you can get all the RentalProperty items from db like this:
$allRentalProperties = RentalProperty::all();
and in foreach loop you can get those items without connecting database like this:
$propertyObj = $allRenatalProperties -> where('id', $property['id']) -> first();
Also, you can use array shorthand.
$newArray = [];
it's much simple and readable.
You can do array pluck before loop:
$propertyIds = Arr::pluck($published_properties, 'id');
Then you can make a whereIn query to get only those data which are in $published_properties object
$propertyObj = RentalProperty::whereIn('id', $propertyIds);
Then you can access that object with id if you change array key with record id.

ManyToMany with and whereIn

I have a ManyToMany relationship between AdInterest and AdInterestGroup models, with a belongsToMany() method in each model so I can use dynamic properties:
AdInterest->groups
AdInterestGroup->interests
I can find all the "interests" in a single group like this:
$interests = AdInterestGroup::find(1)->interests->pluck('foo');
What I need is a merged, deduplicated array of the related 'foo' field from multiple groups.
I imagine I can deduplicate with ->unique(), but first, as you'd expect, this:
AdInterestGroup::whereIn('id',[1,2])->interests->get();
throws:
Property [interests] does not exist on the Eloquent builder instance.
The advice seems to be to use eager loading via with():
AdInterestGroup::with('interests')->whereIn('id',[1,2])->get();
Firstly, as you'd expect that's giving me an array of two values though (one for each ID).
Also, if I try and pluck('foo') again, it's looking in the wrong database table: from the AdInterestGroup table, rather than the relationship (AdInterest).
Is there a nice, neat Collection method / pipeline I can use to combine the data and get access to the relationship fields?
Use pluck() and flatten():
$groups = AdInterestGroup::with('interests')->whereIn('id', [1, 2])->get();
$interests = $groups->pluck('interests')->flatten();
$foos = $interests->pluck('foo')->unique();

MINUS operation in Eloquent ORM

Is there any equivalent MINUS operation from SQL using Eloquent ORM?
For example
$model1 = Model::where('some constraints applied')
$model2 = Model::where('some constraints applied')
I want to get all models that exist in $model1 but not in $model2
seblaze's answer looks good, though it will run 3 queries. Another option is diff() method of the Collection object:
$result = $model1->diff($model2);
This works after fetching data from the db with 2 queries, but complete set of data (unless there are more depending on your 'constraints applied').
The easiest way i see it is :
//Get the id's of first model as array
$ids1 = $model1->lists('id');
//get the id's of second models as array
$ids2 = $model2->lists('id');
//get the models
$models = Model::whereIn('id',$ids1)->whereNotIn('id',$ids2)->get();
This is not tested code, please read more about eloquent queries here

Is it possible to eager load arbitrary queries in Eloquent?

I'm working in Laravel 4, and I have a Child model with multiple EducationProfiles:
class Child extends EloquentVersioned
{
public function educationProfiles()
{
return $this->hasMany('EducationProfile');
}
}
If I wanted to get all the EducationProfiles for each kid under age 10 it would be easy:
Child::where('date_of_birth','>','2004-03-27')->with('educationProfiles')->all();
But say (as I do) that I would like to use with() to grab a calculated value for the Education Profiles of each of those kids, something like:
SELECT `education_profiles`.`child_id`, GROUP_CONCAT(`education_profiles`.`district`) as `district_list`
In theory with() only works with relationships, so do I have any options for associating the district_list fields to my Child models?
EDIT: Actually, I was wondering whether with('educationProfiles') generates SQL equivalent to:
EducationProfile::whereIn('id',array(1,2,3,4))
or whether it's actually equivalent to
DB::table('education_profiles')->whereIn('id',array(1,2,3,4))
The reason I ask is that in the former I'm getting models, if it's the latter I'm getting unmodeled data, and thus I can probably mess it up as much as I want. I assume with() generates an additional set models, though. Anybody care to correct or confirm?
Ok, I think I've cracked this nut. No, it is NOT possible to eager load arbitrary queries. However, the tools have been provided by the Fluent query builder to make it relatively easy to replicate eager loading manually.
First, we leverage the original query:
$query = Child::where('date_of_birth','>','2004-03-27')->with('educationProfiles');
$children = $query->get();
$eagerIds = $query->lists('id');
Next, use the $eagerIds to filterDB::table('education_profile') in the same way that with('educationProfiles') would filter EducationProfile::...
$query2 = DB::table('education_profile')->whereIn('child_id',$eagerIds)->select('child_id', 'GROUP_CONCAT(`education_profiles`.`district`) as `district_list`')->groupBy('child_id');
$educationProfiles = $query2->lists('district_list','child_id');
Now we can iterate through $children and just look up the $educationProfiles[$children->id] values for each entry.
Ok, yes, it's an obvious construction, but I haven't seen it laid out explicitly anywhere before as a means of eager loading arbitrary calculations.
You can add a where clause to your hasMany() call like this:
public function educationProfilesUnderTen() {
$ten_years_ago = (new DateTime('10 years ago'))->format('Y-m-d');
return $this->hasMany('EducationProfile')->where('date_of_birth', '>', $ten_years_ago)
}

Querying a one to one relationship from a collection

The problem is I need to pull a collection from a collection. I have already set up the models and database so these relationships work:
A User can have many Negotiations
A Negotiation has one RiderNegotiation
However I can't perform this query:
$user->negotiations->riderNegotiation
I thought I could get around this in my view file if I just passed off $user->negotiation and then parse through the negotiations. I discovered I can't use isEmpty() this way however.
#if($negotiations->riderNegotiation->isEmpty()
Is there some kind of nifty trick in Laravel to do this kind of relationship querying? I feel like this is a common issue.
hasMany returns a Collection of elements and you can't call hasOne on a Collection.
You should be able to do:
$negociations = User::find(1)->negotiations;
#foreach($negociations as $negociation)
echo get_class($negociation->riderNegotiation); //riderNegotiation
#endforeach
$negotiations = User::find(Auth::user()->id)->negotiations;
$temp = array();
foreach($negotiations as $negotiation ) {
$temp = array_merge($temp,$negotiaton->riderNegotiation->toArray());
};
A little resource expensive but $temp should contain all rider negotiations for that user.

Resources