Blank object in Eloquent belongsTo() - laravel

I'm trying to display which one attribute (code) of Item. ServiceItem has Item as a foreign key. But I can't get the Item at all.
This one gives a blank object in blade template:
#foreach ($service->serviceItems as $serviceItem )
{{ json_encode($serviceItem->item()) }}
#endforeach
Here's my model declaration:
//ServiceItem model
class ServiceItem extends Model
{
use HasFactory;
public $fillable = ['service_id', 'item_id', 'values'];
public function service()
{
return $this->belongsTo(Service::class, 'foreign_key');
}
// this doesn't work
public function item()
{
return $this->belongsTo(Item::class, 'foreign_key');
}
}
// Service model
class Service extends Model
{
use HasFactory;
public $fillable = ['user_id', 'site_id', 'title', 'status', 'remarks', 'report', 'date'];
public function user()
{
return $this->belongsTo('\App\Models\User');
}
public function site()
{
return $this->belongsTo('\App\Models\Site');
}
public function serviceItems() {
return $this->hasMany('\App\Models\ServiceItem');
}
}
This is my controller:
public function index()
{
$services = Service::latest()->paginate(5);
return view('services.index', compact('services'))
->with('i', (request()->input('page', 1) - 1) * 5);
}
Please help me to display the code attribute in Item from Service!!! Thanks a lot!

I suppose you read the Laravel doc of model relationship definition. They referenced to put foreign key as the second parameter, not the foreign_key as word but your actual foreign key that reference the parent table. you have to change the model code.
class ServiceItem extends Model
{
use HasFactory;
public $fillable = ['service_id', 'item_id', 'values'];
public function service()
{
return $this->belongsTo(Service::class, 'service_id');
}
public function item()
{
return $this->belongsTo(Item::class, 'item_id');
}
}
and then $serviceItem->item should work as expected.

Related

Laravel eloquent multiple levels of relations

Alright so I am basically trying to retrieve all animal_registry codes based on a user ID.
Idea is that
1 user has many jobs.
Jobs are consisted of many "Jobs data".
Jobs data has many "Animal registry" entries.
These are my relations
Image relations link (click)
And these are my relations in Laravel
class User
{
public function jobs()
{
return $this->hasMany('App\Models\RegistryJobs', 'employee', 'id');
}
}
class RegistryJobs extends Model
{
protected $table = "registry_jobs";
protected function jobsData()
{
$this->hasManyThrough('App\Models\AnimalRegistry', 'App\Models\RegistryJobsData', 'id', 'animal_registry_id');
}
}
class RegistryJobsData extends Model
{
protected $table = "registry_jobs_data";
public function jobs()
{
$this->belongsTo('App\Models\RegistryJobs', 'id', 'registry_jobs_id');
}
public function animals()
{
$this->hasMany('App\AnimalRegistry', 'id', 'animal_registry_id');
}
}
class AnimalRegistry extends Model
{
protected $table = "animal_registry";
}
And now I am trying to query it from a controller in a way
$data = User::whereHas('jobs', function ($query) {
$query->where('id', 1);
})->get();
But I am unable to access the properties from the animal_registry.
Can you try like this :
public function animals(){
return $this->hasManyThrough('App\Registry_Jobs_data','App\Registry_Jobs', 'employee',
'registry_jobs_id', 'id' ,'id')->join('//Do the joining')->select();
}
Check the hasManyThrough i am not sure..

Laravel Complex Relationships Through Polymorphism

I have the following models using Laravel 5.3:
Provider:
// Provider model
$primaryKey = 'id'
public function activities()
{
return $this->hasMany(Activity::class);
}
Activity:
// Activity model
$primaryKey = 'id'
public function provider()
{
return $this-belongsTo(Provider::class);
}
public function semesters()
{
return $this->hasMany(Semester::class);
}
public function semesterPurchases()
{
return $this->hasManyThrough(Purchase::class, Semester::class, 'activity_id', 'purchasable_id')
->where('purchasable_type', Semester::class);
}
Semester:
// Semester model
$primaryKey = 'id'
public function activity()
{
return $this->belongsTo(\App\Models\Activity::class, 'activity_id', 'id');
}
Purchase:
// Purchase model
$primaryKey = 'id'
public function purchasable()
{
return $this->morphTo();
}
In my case Semester::class is the purchasable_type. Is there a way to establish a relationship between Provider::class and Purchase::class? In order to make it possible to do something like this:
$providers = Provider::select('id', 'name', 'address')
->with('purchases')
->where('providers.id', 1)
->get();
I would prefer not to go through activities like so:
$providers = Provider::select('id', 'name', 'address')
->with('activities.purchases')
->where('providers.id', 1)
->get();
which I know I can do using hasManyThrough on the Activity::class
Laravel has no native support for a direct relationship.
I've created a package for cases like this: https://github.com/staudenmeir/eloquent-has-many-deep
class Provider extends Model
{
use \Staudenmeir\EloquentHasManyDeep\HasRelationships;
public function purchases()
{
return $this->hasManyDeep(
Purchase::class,
[Activity::class, Semester::class],
[null, null, ['purchasable_type', 'purchasable_id']]
);
}
}
Provider::find($id)->purchases;

Laravel Eloquent many to many relationship with translation

I have a problem with a many to many relationship and the translations of the terms.
I have 4 tables:
products
- id, price, whatever
products_lang
- id, product_id, lang, product_name
accessori
- id, active
accessori_lang
- id, accessori_id, lang, accessori_name
I'm trying to assign accessories to products with an intermediate table named:
accessori_products
this is the model for Product:
class Product extends Model {
protected $table = 'products';
public function productsLang () {
return $this->hasMany('App\ProductLng', 'products_id')->where('lang','=',App::getLocale());
}
public function productsLangAll() {
return $this->hasMany('App\ProductLng', 'products_id');
}
public function accessori() {
return $this->belongsToMany('App\Accessori', 'accessori_products');
}
}
this is the model for productLng:
class ProductLng extends Model {
protected $table = 'products_lng';
public function products() {
return $this->belongsTo('App\Product', 'products_id', 'id');
}
}
Then I have the model for Accessori:
class Accessori extends Model {
protected $table = 'accessori';
public function accessoriLang() {
return $this->hasMany('App\AccessoriLng')->where('lang','=',App::getLocale());
}
public function accessoriLangAll() {
return $this->hasMany('App\AccessoriLng');
}
public function accessoriProducts() {
return $this->belongsToMany('App\Products', 'accessori_products', 'accessori_id', 'products_id');
}
}
And the model for AccessoriLng:
class accessoriLng extends Model {
protected $table = 'accessori_lng';
public function accessori() {
return $this->belongsTo('App\Accessori', 'accessori_id', 'id');
}
}
the last model is for the relationship between the two tables above:
class ProductAccessori extends Model {
protected $table = 'accessori_products';
public function accessoriProducts() {
return $this->belongsTo('App\Product', 'accessori_id', 'products_id');
}
}
I'm trying to get the accessories of each product and to get also the translation but I'm having a lot of problem with this.
It's my first time with a many to many relation with translations too.
Can anyone put me on the right direction?
controller
$products = Product::has('accessori')->with([
'productsLang ',
'accessori' => function ($accessori){
$accessori->with([
'accessoriLang'
]);
}
])->get();
return $products;
you'll get products with accessori that has accessoriLang.

type casting in laravel json response in relationships eager loading

This is my post model.
class Post extends Model
{
use SoftDeletes;
protected $table = 'posts';
protected $fillable = ['title','featuring_image', 'brief', 'body', 'seen_count'];
public function user(){
return $this->belongsTo(User::class);
}
public function comments()
{
return $this->hasMany(Comment::class);
}
public function someComments()
{
return $this->comments()->limit(Constants::COMMENTS_COUNT_LIMIT);
}
public function commentsCount()
{
return $this->comments()
->selectRaw('post_id, count(*) as count')
->groupBy('post_id');
}
public function likes()
{
return $this->hasMany(Like::class);
}
public function isLiked()
{
return $this->likes()->where('user_id', auth()->check() ? auth()->user()->id : 0);
}
public function likesCount()
{
return $this->likes()
->selectRaw('post_id, count(*) as count')
->groupBy('post_id');
}
}
I executed this query on this model.
$post = Post::with(['categories', 'user', 'commentsCount', 'likesCount', 'isLiked'])->find($post->id);
Because of the relation between this table and like and comment table, The output of this query for 'commentsCount', 'likesCount', 'isLiked' is an array. But I need to receive numbers for 'commentsCount' and 'likesCount', and a boolean for 'isliked' as an output, in laravel josn response.
You might find it easier to use the withCount() the comes with Eloquent instead.
Then for is_liked you could use a scope to get the value and the cast it to a boolean:
public function scopeIsLiked($query)
{
if (is_null($query->getQuery()->columns)) {
$query->select([$query->getQuery()->from . '.*']);
}
$relation = Relation::noConstraints(function () {
return $this->likes();
});
$q = $this->likes()->getRelationExistenceCountQuery(
$relation->getRelated()->where('user_id', auth()->check() ? auth()->user()->id : 0)->newQuery(), $query
);
$query->selectSub($q->toBase(), 'is_liked');
}
Please note you will need to add the use statement for Relation to the top of the class:
use Illuminate\Database\Eloquent\Relations\Relation;
You model could then look like:
class Post extends Model
{
use SoftDeletes;
protected $table = 'posts';
protected $fillable = ['title', 'featuring_image', 'brief', 'body', 'seen_count'];
public function user()
{
return $this->belongsTo(User::class);
}
public function comments()
{
return $this->hasMany(Comment::class);
}
public function someComments()
{
return $this->comments()->limit(Constants::COMMENTS_COUNT_LIMIT);
}
public function likes()
{
return $this->hasMany(Like::class);
}
/**
* Scope to add the "is_liked" flag.
*
* #param $query
*/
public function scopeIsLiked($query)
{
if (is_null($query->getQuery()->columns)) {
$query->select([$query->getQuery()->from . '.*']);
}
$relation = Relation::noConstraints(function () {
return $this->likes();
});
$q = $this->likes()->getRelationExistenceCountQuery(
$relation->getRelated()->where('user_id', auth()->check() ? auth()->user()->id : 0)->newQuery(), $query
);
$query->selectSub($q->toBase(), 'is_liked');
}
}
And your query would look something like:
$post = Post::with('categories', 'user')
->withCount('likes', 'comments')
->isLiked()
->find($post->id);
Hope this helps!
You can use Laravel casts:
Inside the each model you can add the following to cast a value, per example:
protected $casts = [
'isLiked' => 'boolean',
];
Rwd's answer gives a nice solution using scopes, but for laravel 5.4+ you could get away with aliasing the withCount() result and then casting it to boolean with a $cast variable on the model or an accessor (with accessor, you can only get snake case is_liked). This way we don't need to write complex scopes.
The model would be
class Post extends Model
{
// rest of model
protected $casts = ['isLiked'=>'boolean'];
public function likes()
{
return $this->hasMany(Like::class);
}
}
Then in your controller
$post = Post::with('categories', 'user')
->withCount(
[
'likes as likesCount', 'comments as commentsCount',
'likes as isLiked' =>function($query){
$query->where('user_id', auth()->check() ? auth()->user()->id : 0);
}
]
)
->find($post->id);
And now you get likesCount (int), commentsCount (int) and isLiked (boolean)

Laravel scout check if relation is not empty?

namespace App;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
use Laravel\Scout\Searchable;
class Event extends Model
{
protected $table = 'events';
public $timestamps = true;
use Searchable;
use SoftDeletes;
protected $dates = ['deleted_at'];
public function entities()
{
return $this->belongsTo('App\Entity', 'entity_id');
}
public function users()
{
return $this->belongsTo('App\User', 'id');
}
public function events()
{
return $this->belongsTo('App\DirtyEvent', 'id');
}
public function toSearchableArray()
{
$data = $this->toArray();
$data['entities'] = $this->entities->toArray();
return $data;
}
}
This is my model for Event, as you can see I am using toSearchableArray which is Laravel scout function to import 'relations' to algolia. However the problem is that sometimes it is empty. So for example
event id 1 has entity_id 1
but in another example
event id 2 has entity_id = null
How can I modify this function to check if the entities() relation is not empty before putting it into array?
if i understand u correctly this should help. if the relationship does not exist return an empty array and scout won't update the index
public function toSearchableArray()
{
if(is_null($this->entities)){
return [];
}
$this->entities
return $this->toArray();
}
please update foreign_key in relation as this
user_id as foreign_key instead of id
event_id as foreign_key instead of id
public function users()
{
return $this->belongsTo('App\User', 'user_id');
}
public function events()
{
return $this->belongsTo('App\DirtyEvent', 'event_id');
}
I think if load the relation before the toArray().
public function toSearchableArray()
{
$this->entities;
return $this->toArray();
}

Resources