Laravel 5 eloquent - add child field to parent model - php

I have a user model which has a child relationship called teacher. How can I add a field from the related teacher model to the dataset returned of the parent user model?
I would like the user model returned to have a structure like below:
user.firstname
user.lastname
user.teacher.address
I have tried using the following and variations thereof with no success:
$query->select('firstname', 'lastname')
->addSelect( \DB::raw('teachers.address AS address') );
user.php model:
use Notifiable;
use SoftDeletes;
use EncryptableTrait;
/**
* The attributes that are mass assignable.
*
* #var array
*/
protected $fillable = [
'title',
'firstname',
'firstname_h',
'lastname',
'lastname_h',
'email',
'email_h',
'password',
'userable_id',
'userable_type'
];
/**
* The attributes that are mass encryptable, using the EncryptableTrait.
*
* #var array
*/
protected $encryptable = [
'firstname',
'lastname',
'email',
];
/**
* The attributes that should be hidden for arrays.
*
* #var array
*/
protected $hidden = [
'password', 'remember_token',
];
public function userable()
{
return $this->morphTo();
}
public function teacher() // Using custom BelongsToMorph relationship type
{
return BelongsToMorph::build($this, Teacher::class, 'userable');
}
public function roles()
{
return $this->belongsToMany('App\Role')->withTimestamps();
}
public function schools()
{
return $this->belongsToMany('App\School')->withPivot('suspended', 'rating');
}
public function thisSchool()
{
return $this->belongsToMany('App\School')->where('school_id', Auth::user()->userable->id)->withPivot('id', 'suspended', 'rating', 'notes');
}
public function addRole($user, $role_id)
{
$user->roles()->attach($role_id);
}
public function removeRole($user, $role_id)
{
$user->roles()->detach($role_id);
}
public function isAdmin($user)
{
foreach ($user->roles as $role) {
if($role->id == 4) {
return true;
} else {
$return = false;
}
}
return $return;
}
public function isSchoolAdmin($user)
{
foreach ($user->roles as $role) {
if($role->id == 2) {
return true;
} else {
$return = false;
}
}
return $return;
}
public function events()
{
return $this->belongsToMany('App\Event')->withPivot('cancelled', 'cancelled_by');
}
public function devices()
{
return $this->hasMany('App\Device');
}
public function teachingstages()
{
return $this->belongsToMany('App\Teachingstage', 'teacher_teachingstage')->orderBy('teachingstage_id');
}
public function teachingsubjects()
{
return $this->belongsToMany('App\Teachingsubject', 'teacher_teachingsubject');
}
teacher.php model:
use EncryptableTrait;
protected $table = "teachers";
/**
* The attributes that are mass assignable.
*
* #var array
*/
protected $fillable = [
'mobile',
'dob',
'gender',
'address',
'postcode',
'latitude',
'longitude',
'max_distance',
'public',
'photo',
'experience',
'active',
'verified',
'payscale',
'ta_number',
'temp_or_perm',
'locked'
];
/**
* The attributes that are mass encryptable, using the EncryptableTrait.
*
* #var array
*/
protected $encryptable = [
'mobile',
'address',
'postcode',
'experience',
'ta_number'
];
public function user()
{
return $this->morphOne('App\User', 'userable');
}
public function criterias()
{
return $this->hasMany('App\Criteria');
}
public function bookingrequests()
{
return $this->belongsToMany('App\Bookingrequest')->withPivot('sent', 'sent_at', 'declined', 'created_at', 'updated_at');
}
public function blacklist()
{
return $this->hasMany('App\Blacklist');
}
This is my existing query that I am having issues with:
$query = User::where('userable_type', 'App\Teacher');
$query->with('userable');
$query->select('firstname', 'lastname')
->addSelect( \DB::raw('teachers.address AS address') );
$query->whereDoesntHave('thisSchool');
$otherTeachers = $query->get();
This is an existing app and everything works as expected; my question is more about how I can add a child model column as an alias to the parent model (I will then use the new alias columns to calculate something).
Thanks in advance,
K...

OK, I worked this out myself in the end.
I added a scope to my user model:
public function scopeJoinWithTeacher($query)
{
return $query->leftJoin("teachers", "teachers.id", "=", "users.userable_id");
}
I then implemented this new scope in my query and aliased columns from child to parent model in the get():
$query = User::where('userable_type', 'App\Teacher');
$query->with('userable');
$query->whereDoesntHave('thisSchool');
$query->JoinWithTeacher();
$query->orderBy( 'distance', 'ASC' );
$otherTeachers = $query->get(['teachers.longitude AS longitude', 'teachers.latitude AS latitude', 'users.*']);
I now have the longitude and latitude columns from the teacher child relation in my parent model returned from eloquent. In my specific case, I then go further to use these alias fields to calculated distance and create a new alias called distance in my user model.
Hope that helps somebody who was attempting the same thing!
K...

Related

how can i handle this error : Undefined offset: 0

I'm producing an online school platform and in part of it student can see it's classes with their informations..but the related function return this error : Undefined offset: 0 (View: C:\xampp\htdocs\OnlineSchool\resources\views\admin\student\ClassReport.blade.php)
there are some relations between models
My Models:
USER(students and teachers) ، LEVEL(level of classes) ، Classroom.
=> there is a many to many relation between student and classroom (pivot table)
please save me from this stupid error
user:
class User extends Authenticatable
{
use Notifiable;
/**
* The attributes that are mass assignable.
*
* #var array
*/
protected $fillable = [
'name', 'email', 'password','image','level','code_meli',
];
/**
* The attributes that should be hidden for arrays.
*
* #var array
*/
protected $hidden = [
'password', 'remember_token',
];
/**
* The attributes that should be cast to native types.
*
* #var array
*/
protected $casts = [
'email_verified_at' => 'datetime',
];
public function classroom(){
return $this->hasMany (classroom::class);
}
public function ClassRoomStudent(){
return $this->belongsToMany (classroom::class ,'classroom_user','user_id','classroom_id');
}
}
classroom:
class classroom extends Model
{
protected $fillable = [
'title', 'teacher_id', 'level_id','day','time','price',
];
public function Student(){
return $this->belongsToMany (user::class ,'classroom_user','classroom_id','user_id');
}
public function level(){
return $this->belongsTo (level::class );
}
public function teacher(){
return $this->belongsTo (user::class );
}
}
level :
class level extends Model
{
protected $fillable = [
'title',
];
public function classroom(){
return $this->hasMany (classroom::class);
}
public function exam(){
return $this->hasMany (exam::class);
}
}
and my function in controller:
public function MyClasses(){
$student_id=auth ()->user ()->id;
$classrooms=classroom::with ('level','teacher','factor')->wherehas('student',function ($q) use($student_id){
$q->where('id',$student_id);
})->get();
return view ('admin.student.ClassReport',compact ('classrooms','student_id'));
}
at the end .. my blade:
#foreach($classrooms as $class)
<tr>
<td>{{$i++}}</td>
<td>{{$class->title}}</td>
<td>{{$class->teacher[0]->name}}</td>
.
.
.
.
</tr>
#endforeach
The Classroom belongs to only one teacher, no need to use de zero index, just type $class->teacher->name

Laravel return Has many relationship

The relationship is User who can have many Events they are associated to.
I want to be able to make an API call to get all the events associated by the user. I have changed my primary key from id to uuid. I have made the foreign key association to the Events table as well. The primary key in the events table is also a column called UUID.
I am getting error
Return value of App\Http\Controllers\UsersController::getAllEvents() must be an instance of App\Http\Resources\UserResource, instance of Illuminate\Database\Eloquent\Relations\HasMany returned
My routes table:
Route::apiResource('/users', 'UsersController');
Route::apiResource('/events', 'EventsController');
Route::get('/users/allevents/{user}', 'UsersController#getAllEvents');
So the URL im hitting is:
http://127.0.0.1:8000/api/users/allevents/0a0jqZ7qzuhemKnzB3wOPUc2Ugp2
0a0jqZ7qzuhemKnzB3wOPUc2Ugp2 is the UUID of a user. I want to get all the events associated to that user.
My User model:
class User extends Model
{
use Notifiable;
use SoftDeletes;
protected $dates = ['deleted_at'];
/**
* The attributes that are mass assignable.
*
* #var array
*/
protected $fillable = [
'uuid', 'email', 'firstName', 'lastName', 'level', 'venmo'
];
public function getRouteKeyName()
{
return 'uuid';
}
public function events() {
return $this->hasMany(Event::class);
}
}
My Event Model:
class Event extends Model
{
use SoftDeletes;
protected $table = 'events';
protected $dates = ['deleted_at'];
// public function getRouteKeyName()
// {
// return 'uuid';
// }
protected $fillable = [
'id', 'availableSpots', 'uuid', 'chosenDate', 'date', 'epochTime', 'level', 'price', 'time', 'created_at', 'updated_at', 'user_uuid'
];
public $incrementing = false;
protected $primaryKey = 'uuid';
protected $keyType = 'string';
public function user(){
return $this->belongsTo(User::class, 'user_uuid', 'uuid');
}
}
My UsersController:
class UsersController extends Controller
{
public function show(User $user): UserResource
{
return new UserResource($user);
}
/**
* #param Request $request
* #param User $user
* #return UserResource
*/
public function update(Request $request, User $user): UserResource
{
$user->update($request->all());
return new UserResource($user);
}
/**
* #param User $user
* #return UserResource
* #throws \Exception
*/
public function destroy(User $user): UserResource
{
$user->delete();
return new UserResource($user);
}
public function getAllEvents(User $user): UserResource {
return $user->events();
}
}
You are using wrong type of the method return it doesn't return UserResource it return events array so by removing the wrong type it will work
public function getAllEvents(User $user) {
return $user->events;
}
public function getAllEvents(User $user)
{
return $user->events;
}

Return all relationship data in laravel

I want to retrieve data using eloquent model and return it in the following json response.
user[
transactions[],
clients[
ubications[],
contactos[],
plans[],
]
]
Currently I am receiving user,transcation and clients data but I am not able to retreive the data inside client property e.g ubications[],contactos[] and plans[].So I need help regarding the sub properties as I have already implemented the relationship.
Here are the models I am using
User.php
class User extends Authenticatable
{
use Notifiable,HasApiTokens;
/**
* The attributes that are mass assignable.
*
* #var array
*/
protected $fillable = [
'username', 'email', 'password',
];
/**
* The attributes that should be hidden for arrays.
*
* #var array
*/
protected $hidden = [
'password', 'remember_token',
];
/**
* The attributes that should be cast to native types.
*
* #var array
*/
protected $casts = [
'email_verified_at' => 'datetime',
];
public function token(){
return $this->access_token;
}
public function transaction(){
return $this->hasMany(Transaction::class);
}
public function plan(){
return $this->hasManyThrough(Plan::class,Client::class);
}
public function ubication(){
return $this->hasManyThrough(Ubicacion::class,Client::class);
}
public function contacto(){
return $this->hasManyThrough(Contacto::class,Client::class);
}
public function client(){
return $this->hasMany(Client::class);
}
}
Client.php
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Client extends Model
{
protected $fillable=[
'nombre',
'ruc',
'status',
'user_id'
];
public function contacto(){
return $this->hasMany(Contacto::class);
}
public function feedback(){
return $this->hasMany(Feedback::class);
}
public function plan(){
return $this->hasMany(Plan::class);
}
public function ubication(){
return $this->hasMany(Ubicacion::class);
}
public function user(){
return $this->belongsTo(User::class);
}
}
You can use nested data Eager Loading:
Laravel Documentation Eager Loading
$user = User::find(1)
->with('clients', 'clients.contacto', 'clients.ubications', 'clients.plans')
->get();

Insert into many to many relation table in Laravel

In my laravel project, I have tables that i want to insert a many to many relationship between 2 of them. I want to bind an User(that must be a cleaner kind) to one House of many from current Host user authenticated. To do so, I'm implementing the following function in Controller:
public function hireCleanerToHouse (Request $request)
{
$house_id = $request->houseAssign;
$email = $request->email;
$house = House::find($house_id);
$cleanerUser = User::where('email', $email)->first();
if ($cleanerUser && $house){
$cleanerUser->houses()->attach($house);
}
return response()->json('success', 200);
}
May I am missing a detail of logic that cant let me insert any data. Im pretty new using laravel and the Eloquent ORM.
to help understand better, here are the Models from project. The functions that take care of a separates tables (CRUD) are all working fine.
If there are some other tip to improve legibity or if I'm ignoring some best pratice, I will gladly accept it.
User:
class User extends Authenticatable
{
use Notifiable;
/**
* The attributes that are mass assignable.
*
* #var array
*/
protected $fillable = [
'name', 'email', 'password'
];
/**
* The attributes that should be hidden for arrays.
*
* #var array
*/
protected $hidden = [
'password', 'remember_token',
];
public function host()
{
return $this->hasOne(Host::class);
}
public function cleaner()
{
return $this->hasOne(Cleaner::class);
}
}
House:
class House extends Model
{
protected $fillable = ['name', 'address', 'host_id'];
protected $dates = ['created_at', 'updated_at'];
protected $appends = ['next_cleaning'];
public function host()
{
return $this->belongsTo(Host::class);
}
public function cleaners()
{
return $this->belongsToMany(
Cleaner::class,
'cleaners_houses',
'house_id',
'cleaner_id'
);
}
public function cleanings()
{
return $this->hasMany(CleaningProject::class);
}
public function getNextCleaningAttribute()
{
return $this->cleanings()->orderBy('created_at', 'desc')->first();
}
}
Cleaner:
class Cleaner extends Model
{
protected $dates = ['created_at', 'updated_at'];
public function houses()
{
return $this->belongsToMany(
House::class,
'cleaners_houses',
'cleaner_id',
'house_id'
);
}
public function hosts()
{
return $this->belongsToMany(
Host::class,
'cleaners_hosts',
'cleaner_id',
'host_id'
);
}
public function user()
{
return $this->belongsTo(User::class);
}
public function cleanings()
{
return $this->hasMany(CleaningProject::class);
}
public function getNameAttribute()
{
return $this->user->name;
}
}
Host
class Host extends Model
{
protected $dates = ['created_at', 'updated_at'];
protected $appends = ['name'];
public function houses()
{
return $this->hasMany(House::class);
}
public function cleaners()
{
return $this->belongsToMany(
Cleaner::class,
'cleaners_hosts',
'host_id',
'cleaner_id'
);
}
public function user()
{
return $this->belongsTo(User::class);
}
public function getNameAttribute()
{
return $this->user->name;
}
}
And also the migration that bind many Cleaners to many House is already created:
Migration
class CreateCleanersHousesTable extends Migration
{
/**
* Run the migrations.
*
* #return void
*/
public function up()
{
Schema::create('cleaners_houses', function (Blueprint $table) {
$table->increments('id');
$table->integer('cleaner_id')->references('id')->on('cleaners');
$table->integer('house_id')->references('id')->on('houses');
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* #return void
*/
public function down()
{
Schema::dropIfExists('cleaners_houses');
}
}
here's the solution that I found:
public function hireCleanerToHouse (Request $request)
{
$email = $request->email;
$houseId = $request->idHouse;
$idUserEmail = User::where('email', $email)->first();
$cleaner = Cleaner::where('user_id', $idUserEmail->id)->first();
$house = House::find($houseId);
$cleaner->houses()->attach($house->id);
return response()->json([$cleaner, $house], 200);
}
As you may see the problemn was because the model Cleaner only contains 'id' and 'user_id', so i had to get first the user.id and find the cleaner where user_id = user.id.
Also I don't passed the $house->id in the attach() to match the relationship. Its now working fine. hope it helps someone else.

Laravel 5.4 Model Accessor Methods not working

i'm trying make an accessor, for post permalink. If i understand correctly it will change my premalink when i create new entry, but it doesn't
<?php
class Story extends Model
{
use UuidTrait;
public $incrementing = false;
protected $table = 'stories';
protected $fillable = [
'title', 'text', 'tags', 'user_id', 'permalink',
];
public function user()
{
return $this->belongsTo('App\Model\User', 'user_id');
}
/**
* Set the permalink.
*
* #param string $value
* #return void
*/
public function sePermalinkAttribute($value)
{
if(empty($value)){
$value = $this->attributes['title'];
}
$this->attributes['permalink'] = str_slug($value);
}
}
But i get NULL when save my model. Why does accessor not working?
$user->stories()->create($data['data']);

Categories