Laravel eager loading a HasMany Relationship with all the ID present - laravel-8

There are 2 models Property and Relationship. I am trying to eagerload Relationship from Property whereIn relationship.id = array of ids.
My code is as follows:
Property Model
public function relationship_items()
{
return $this->hasMany(Relationship::class, 'property_id', 'id');
}
Relationship Model
public function property()
{
return $this->belongsTo(Property::class, 'id', 'property_id');
}
Eloquent
$properties = Property::when($request->relationship_id, function ($q) use ($request) {
$q->whereHas("relationship_items", function ($q) use ($request) {
$q->whereIn("relationship_id", $request->relationship_id);
});
})->get();
In my whereIn function, I think mysql is trying to do where in id = ([....]), etc. Because of this, If I input ids [1,2,3], eloquent will fetch relationship data even if it has only id "1". I want to only get all relationships if and only if it has all the ids.

Related

How to get the default $id from another table using laravel model relationship?

I am facing the problem whereby I don't know the syntax of letting the id of my property model equals to property_id value in property_doc table.
In PropertyDoc model
public function property()
{
return $this->belongsTo(Properties::class, 'property_id');
}
In Properties model
public function property_id()
{
return $this->hasMany(PropertyDoc::class, 'property_id');
}
In PropertyController
public function StoreInfoProperty(Request $request)
{
$propertyInfo = new PropertyDoc;
$propertyInfo->property_id = $property_id;
}
I am stuck at retrieving the default id value in properties database to be equal to the property_id in property_docs database. Thank you.
You should change the naming of the relationship, see my example below:
In Properties model
public function propertyDocs()
{
return $this->hasMany(PropertyDoc::class, 'property_id', 'id');
}
In PropertyDoc model
public function property()
{
return $this->belongsTo(Properties::class, 'property_id', 'id');
}
In controller
public function StoreInfoProperty(Request $request)
{
$propertyDoc = PropertyDoc::with(['property'])->where('...logic here');
$property_id = $propertyDoc->property->id;
}
hope can help you and happy coding !

Return result from pivot table

I have multiple campaigns, that can be assigned to multiple users. Basically, they have belongsToMany relation both ways.
I would like to print out the results on the page, that only belongs to that specific user, based on the pivot table.
Models:
User model:
public function campaign()
{
return $this->belongsToMany(Campaign::class, 'campaign_user');
}
Campaign model:
public function users()
{
return $this->belongsToMany(Gift::class, 'campaign_user');
}
Migration of pivot table:
public function up()
{
Schema::create('campaign_user', function (Blueprint $table) {
$table->foreignId('user_id')->constrained()->onDelete('cascade');;
$table->foreignId('campaign_id')->constrained()->onDelete('cascade');
});
}
Incorrect Controller:
public function index(Request $request)
{
$data = Campaign::withCount('gifts');
$data->where('user_id', $request->user()->id)->get();
return view('subscribes.index', ['data' => $data]);
}
Basically, all I need, is to return specific campaigns, that the client has subscribed only, based on the pivot table/user id. Thus, editing this Controller.
I still face lots of issues with Eloquent models and pivot tables, and I would be very thankful, for any assistance in regards to it.
This will make more sense if you rename the relationship campaign() to it's plural campaigns() on your User model.
Once you have the relationships set up, you can access campaigns for the user straight from the user object.
$user = $request->user();
$data = $user->campaigns;
Note also, if your user is authenticated, you can access them easily like:
$user = auth()->user();
So your index method in your controller would be
public function index(Request $request)
{
$user = $request->user();
$data = $user->campaigns;
return view('subscribes.index', ['data' => $data]);
}

Laravel Convert Mysql query to Eloquent

I'm new to Laravel and I can write simple eloquent queries but have no idea how to convert this query to eloquent. Can anyone give any idea, is it possible to convert this to eloquent or I have to write raw query?
"Select categories.id, categories.name, Sum(likes.liked) as liked
FROM categories, likes
WHERE likes.material_id IN (SELECT category_material.material_id
FROM category_material
WHERE category_material.category_id = categories.id)
GROUP BY categories.id";
Here my Models
class Material extends Model
{
public function categories(){
return $this->belongsToMany(Category::class,'category_material');
}
public function likes(){
return $this->hasMany(Like::class);
}
////////////////////////////////////////////////////////////
class Like extends Model
{
protected $table = 'likes';
public function user(){
return $this->belongsTo(User::class);
}
public function material(){
return $this->belongsTo(Material::class);
}
//////////////////////////////////////////////////////
class Category extends Model
{
public function materials(){
return $this->belongsToMany(Material::class,'category_material');
}
You can define a likes relationship in your Category model like so:
public function likes()
{
return $this->belongsToMany(Like::class, 'category_material', 'category_id', 'material_id', 'id', 'material_id');
}
Then to achieve what you're after with Eloquent you can use a mixture of has() and withCount, however, we're going to modify the withCount call to return a sum() instead:
$catrgories = Category::has('likes')->withCount([
'likes as liked' => function ($query) {
$query->select(DB::raw('SUM(likes.liked)'));
},
])->get();
If you're wanting to return categories that don't have any likes you can remove the has() method, and introduce the COALESCE() function to your raw query:
$catrgories = Category::withCount([
'likes as liked' => function ($query) {
$query->select(DB::raw('COALESCE(SUM(likes.liked), 0)'));
},
])->get();
Alternatively, you could simply load the necessary relationships and then use that fact that Eloquent returns collection to get the value after you've retrieved the results from the database:
$categories = Category::with('materials.likes')->get()->map(function ($item) {
$item->setAttribute('liked', $item->materials->map(function ($item) {
return $item->likes->map->sum('liked')->sum();
})->first());
$item->unsetRelation('materials');
return $item;
});
This would mean that you don't have to add the custom relationship.

Eloquent relationship with a where clause

I need to do a where condition on the code field from my intermediate table. My two models are;
class Agreement extends Eloquent {
protected $table = 'agreements';
public function clients(){
return $this->belongsToMany('Client', 'client_agreements')->withPivot('start_date', 'expire_date', 'code');
}
}
And;
class Client extends Eloquent {
public function agreements(){
return $this->belongsToMany('Agreement', 'client_agreements')->withPivot('start_date', 'expire_date', 'id', 'code');
}
}
My controller is currently;
public function show($code, $client_id)
{
//
$client = Client::with('agreements')->find($client_id);
$client_agreement = $client->agreements;
}
I think I need to expand the $client->agreements; code to include a where condition on the $code. I have tried so many different combinations but just keep returning the same Call to undefined method error.
I've tried things like;
$client_agreement = $client->agreements->where('code', '=', $code);
$client_agreement = $client->agreements->code->find($code);
$client_agreement = $client->agreements->pivot->code->find($code);
I always get the same error. I'm not that great on objects so maybe I'm looking at this all wrong. How is it done?
You need to access ->relation() not ->relation (which is dynamic property call):
$client_agreement = $client->agreements()
->wherePivot('code', '=', $code)
->first();

Laravel 4: Select row if a relation exists by querying relation

I am trying to query a products table, and want it to return a collection if a relation exists.
Iteration 1 below queries all rows in the products table, and lazy loads the metals table if $name matches. This is wrong.
My Route:
Route::group(array('prefix' => '{api}/v1'), function()
{
Route::controller('products', 'Api\V1\ProductController');
});
My Controller:
public function getFilter($metal = null) {
$products = $this->product;
if ($metal) {
$products->with('metal', function($query, $metal) {
$query->where('name', $metal);
});
}
return Response::api($products->get());
}
I want only $products to display if metal.name = $metal. e.g. something like:
$this->products->where('metal.name', $metal)->get;
Solution using part of Glad To Help's answer:
This provides an alternative approach 2, without the need for joins.
http://paste.laravel.com/WC4
Unfortunately you cannot do this with one swipe in Eloquent yet.
BUT, there is a way by using the inverse relation, like this:
public function getFilter($metal = null)
{
// filter the metals first
$metals = Metal::with('products')->where('name', '=' , $metal)->get();
$products = array();
foreach($metals as $metal)
{
// collect the products from the filtered metals
$products = array_merge($products, $metal->products->toArray() );
}
return $products;
}
If this is not elegant solution for you, you will either have to use Fluent to construct the query and join the products x metals table manually or pre-join them by overriding the newQuery() method.
1) alternative approach one.
public function getFilter($metal = null) {
return DB::table('products')->join('metal', 'products.id', '=' , 'metal.product_id')
->where('metal.name', $name)
->select(array('products.*'));
}
2) alternative approach two
class Product extends Eloquent{
public function newQuery($excludeDeleted = true){
return parent::newQuery()->join('metal','id','=','metal.product_id');
}
}