I'm having an issue with Eloquent relationship. The relationship is... Each User can have an Owner which is also a user.
When I try to fetch User with Parent:
On *nix OS and PHP 5.4.20, I get same User as Parent so parent and user both are same.
Whereas on PHP5.4.7 (Win 7 if that matters), it returns correct data. By the way this code is an Event Handler of some event.
User Model
class User extends Eloquent implements UserInterface, RemindableInterface, PresentableInterface {
protected $fillable = array(
'first_name', 'last_name', 'email', 'password', 're_type_password', 'birth_date',
'phone', 'address', 'state', 'city', 'zip', 'profile_pic', 'owner_id', 'can_edit_appointments',
'can_accept_invitations', 'can_edit_profile', 'can_receive_notification', 'is_active', 'is_admin', 'token', 'failed_login_attempts_count'
);
public function __construct($validator = null, $subAccountValidator = null)
{
parent::__construct();
$this->validator = $validator ?: App::make('ReminderMillie\Services\Validators\UserValidator');
$this->subAccountValidator = $subAccountValidator ?: App::make('ReminderMillie\Services\Validators\SubAccountValidator');
}
public function getDates()
{
return array('created_at', 'updated_at', 'birth_date');
}
/**
* Relations
*/
public function business()
{
return $this->hasOne('Business', 'owner_id');
}
public function parent()
{
return $this->belongsTo('User', 'owner_id');
}
public function subAccounts()
{
return $this->hasMany('User', 'owner_id');
}
}
I think you inverse is incorect...
please check this
public function parent()
{
return $this->belongsTo('User');
}
public function subAccounts()
{
return $this->hasMany('User', 'id', 'owner_id');
}
Related
I need help please, to figure out for convenient ways to link between User/Staff/Parent/Student.
A Staff/Parent/Student is a user.
A Staff can be a Parent too. Similarly, a Parent may be a Staff too.
A student belongsToMany Parent, and a Parent belongsToMany Student.
Here are the models I've created :
App\Models\Student.php
protected $fillable = [
'name',
'email',
'student_user_id',
'created_at',
'updated_at',
'deleted_at',
];
public function student_user()
{
return $this->belongsTo(User::class, 'student_user_id');
}
public function guardians()
{
return $this->belongsToMany(StudentGuardian::class);
}
==========================================================
App\Models\StudentGuardian.php
protected $fillable = [
'name',
'email',
'guardian_user_id',
'is_staff',
'guardian_staff_id',
'created_at',
'updated_at',
'deleted_at',
];
public function students()
{
return $this->belongsToMany(Student::class);
}
public function guardian_user()
{
return $this->belongsTo(User::class, 'guardian_user_id');
}
public function guardian_staff()
{
return $this->belongsTo(Staff::class, 'guardian_staff_id');
}
=====================================
App\Models\Staff.php
protected $fillable = [
'name',
'email',
'staff_user_id',
'staff_guardian_id',
'is_student_guardian',
'created_at',
'updated_at',
'deleted_at',
];
public function staff_user()
{
return $this->belongsTo(User::class, 'staff_user_id');
}
public function staff_guardian()
{
return $this->belongsTo(StudentGuardian::class, 'staff_guardian_id');
}
In the StudentsController, I don't know how to call the students related to the authenticated user
you can use polymorphic relation to handle it.
https://laravel.com/docs/9.x/eloquent-relationships#polymorphic-relationships
I'm working on a questionnaire project and I ran into an error saying:
Undefined index: exams
This happened when I was trying to store responses to my database.
Here is my controller code:
public function store(Math $math)
{
$data = request()->validate([
'responses.*.answer_id' => 'required',
'responses.*.question_id' => 'required'
]);
$exam = $math->exams()->create($data['exams']);
$exam->examanswers()->createMany($data['examanswers']);
return 'Thank You';
}
Here is my exam model:
{
use HasFactory;
protected $fillable = ['exam'];
public function math()
{
return $this->belongsTo(Math::class);
}
public function examanswers()
{
return $this->hasMany(ExamAnswer::class);
}
}
question model:
{
use HasFactory;
protected $fillable = ['question'];
public function math()
{
return $this->belongsTo(Math::class);
}
public function answers()
{
return $this->hasMany(Answer::class);
}
}
Math model:
{
use HasFactory;
protected $fillable = [
'user_id', 'title', 'purpose', 'exam'
];
public function user()
{
return $this->belongsTo(User::class);
}
public function questions()
{
return $this->hasMany(Question::class);
}
public function exams()
{
return $this->hasMany(Exam::class);
}
}
Please help me look into it.
request()->validate(RULES) will return an array with all the existing rules' indexes. It will not return all data present, just what it is in the rules and present.
Read how $request->validate() works.
For example:
If you send home = 'Address', name = 'John' and email = 123, but your rules are:
$data = $request->validate([
'home' => 'required',
'name' => 'required',
]);
Then, if you want to use $data you would have (dd($data)):
$data['home']: Address
$data['name']: John
But email = 123 would not be present in $data.
I'm trying to figure out how to create all the data based on this relationship testing in Laravel.
Company Model
class Company
{
public function stores()
{
return $this->hasMany(Store::class, 'company_id');
}
public function employers()
{
return $this->belongsToMany(User::class, 'employers',
'company_id', 'user_id');
}
}
Store Model
class Store
{
public function company()
{
return $this->belongsTo(Company::class, 'company_id');
}
public function employers()
{
return $this->belongsToMany(User::class, 'employers',
'store_id', 'user_id');
}
}
User Model
class User
{
public function company()
{
return $this->belongsToMany(Company::class, 'employers',
'user_id', 'company_id');
}
public function store()
{
return $this->belongsToMany(Store::class, 'employers',
'user_id', 'store_id');
}
}
$company = Company::factory()->hasStores(
Store::factory()->hasEmployers(User::factory())
)->create();
dd($company) // App\Models\Company {#2470... Ok!
$store = $company->store()->first();
dd($store) // App\Models\Store {#2479... Ok!
$user = $store->employers()->first();
dd($user) // null (T-T)
Background: this is an application that allows a proprietor to own several companies. For that reason, I got many relationships, and even so, employees sometimes can only belong to a single company or store.
Try:
$store = $company->store->first();
dump($store);
$user = $store->employers->first();
dump($user);
Try something like this with DB Facade
private $employ;
public function setUp(): void
{
$this->employ = Employ::factory()->create([
'id' => 14,
'name' => 'Name Employ'
]);
}
public function test_pivote_table()
{
$user = User::factory()->create([
'name' => 'User test'
);
//here :)
DB::table('name_pivote_table')->insert([
'user_id' => $user->id,
'employ_id' => $this->employ->id
]);
}
Credits to Fguzman :)
I am building a small application in Laravel where I got stuck with the sum of inner relational data,
I have a model Company which has Many relation associatedProjects and associatedProjects belongs to relation project and project hasOne technicalDescription.
Company Model:
class Company extends Model {
public function roles()
{
return $this->belongsToMany('Noetic\Plugins\Conxn\Models\Variables\Company\Role', 'company_role_relation', 'company_id', 'role_id')->withTimestamps();
}
public function specialisations()
{
return $this->belongsToMany('Noetic\Plugins\Conxn\Models\Variables\Company\Role', 'company_specialisation_relation', 'company_id', 'specialisation_id')->withTimestamps();
}
public function associatedProjects()
{
return $this->hasMany('Noetic\Plugins\Conxn\Models\Project\AssociateCompany','company_id','id');
}
}
AssociateCompany Model:
class AssociateCompany extends Model {
protected $table = 'project_associate_company';
protected $fillable = [
'project_id', 'company_role_id', 'company_specialisation_id', 'company_id', 'link', 'file_name'
];
public function project()
{
return $this->belongsTo('Noetic\Plugins\Conxn\Models\Project','project_id','id');
}
public function company()
{
return $this->belongsTo('Noetic\Plugins\Conxn\Models\Company','company_id','id');
}
public function companyRole()
{
return $this->belongsTo('Noetic\Plugins\Conxn\Models\Variables\Company\Role',
'company_role_id','id');
}
public function specialisation()
{
return $this->belongsTo('Noetic\Plugins\Conxn\Models\Variables\Company\Role',
'company_specialisation_id','id');
}
}
Project Model
class Project extends Model {
protected $fillable = [
'user_id','koshy_id', 'name', 'slug', 'owner_spv', 'spv_link', 'latitude', 'longitude',
'landmark', 'city', 'district', 'state', 'pin_code', 'region_id', 'country', 'building_use',
'sector', 'conxn_id', 'parent_project_id', 'website', 'project_logo', 'tracked', 'verified',
'code_link', 'status', 'active', 'premium','area'
];
public function technicalDescription()
{
return $this->hasOne('Noetic\Plugins\Conxn\Models\Project\TechnicalDescription','project_id','id');
}
public function associateCompany()
{
return $this->hasMany('Noetic\Plugins\Conxn\Models\Project\AssociateCompany','project_id','id');
}
}
Now this technicalDescription has fields construction_cost, now I want to first count total number of associatedProject and fetch sum of all the project's construction_cost which is in technicalDescription, some what I have done this code:
$company = Company:: where( 'status', 'saved')
->withCount( 'associatedProjects' )
->with('associatedProjects.project.technicalDescription')
->get()
->transform(function ($value) {
$value['project_value'] = $value['associatedProjects']->flatten(2)
->pluck('project.technicalDescription')->sum('construction_cost');
return $value;
})
->sortByDesc('project_value')
->forpage( $request->page , 10 );
$next = $request->page+1 ;
$previous =$request->page-1 ? abs($request->page-1):1 ;
I am unable to use paginate over here as laravel collection doesn't have such method, moreover the query logic also doesn't appear accurate.
Any suggestions are welcome. Thanks
You can use a BelongsToMany relationship to get the technicalDescriptions directly:
class Company extends Model {
public function technicalDescriptions() {
return $this->belongsToMany(
'Noetic\Plugins\Conxn\Models\Project\TechnicalDescription',
'project_associate_company',
'company_id',
'project_id',
null,
'project_id'
);
}
}
$company = Company::where('status', 'saved')
->withCount(['technicalDescriptions as project_value' => function($query) {
$query->select(DB::raw('sum(construction_cost)'));
}])
->orderByDesc('project_value')
->paginate();
When creating a simple one-to-one relationship in Laravel 5.5, $person->user is returning a null value whenever I use the method/relation name user. If I change the name to foo, User, or login the code seems to work fine. This is the second project I've had this same issue on. Can anyone see what I'm doing wrong?
In Person model:
public function user() {
return $this->belongsTo(User::class, 'user_id', 'id');
}
public function foo() {
return $this->belongsTo(User::class, 'user_id', 'id');
}
public function getUser() {
if ($this->user_id) {
return User::find($this->user_id);
} else {
return null;
}
}
In PersonTest:
$user = factory(User::class)->create();
$person = factory(Person::class)->create(['user_id' => $user->id]);
// This works
$this->assertTrue( $person->getUser()->is($user) );
// This works
$this->assertTrue( !is_null($person->foo) );
if ( $person->foo ) {
$this->assertTrue( $person->foo->is($user) );
}
// This fails
$this->assertTrue( !is_null($person->user) );
if ( $person->user ) {
$this->assertTrue( $person->user->is($user) );
}
By request, here is all of the code relating to Person,
Entire App\Models\Person.php:
use App\Models\User;
use App\Models\Asset;
use App\Traits\HasGuid;
use App\Traits\HasNotes;
use App\Traits\HasModifiedBy;
use App\Traits\HasAttachments;
use App\Traits\HasRelationships;
use App\Transformers\PersonTransformer;
use App\Models\Abstracts\HasTypeModelAbstract;
use App\Models\Interfaces\HasTypeModelInterface;
class Person extends HasTypeModelAbstract implements HasTypeModelInterface {
use HasModifiedBy,
HasNotes,
HasAttachments,
HasRelationships;
protected $fillable = [
'person_type_id',
'email',
'fname',
'lname',
'user_id',
'modified_by_user_id',
'audited_at',
'custom_attributes'
];
protected $casts = [
'custom_attributes' => 'json',
'user_id' => 'integer',
'modified_by_user_id' => 'integer',
'person_type_id' => 'integer'
];
protected $dates = [
'audited_at'
];
public static $transformer = PersonTransformer::class;
public function user() {
return $this->belongsTo(User::class, 'user_id', 'id');
}
public function type() {
return $this->belongsTo(PersonType::class, 'person_type_id');
}
public function assets() {
return $this->hasMany(Asset::class, 'person_id');
}
Traits:
trait HasNotes {
protected static function bootHasNotes() {
static::deleting(function ($instance) {
$instance->notes->each(function ($note) {
$note->delete();
});
});
}
public function notes() {
return $this->morphMany(Note::class, 'notable');
}
}
trait HasModifiedBy {
protected static function bootHasModifiedBy() {
static::saving(function ($instance) {
$instance->modified_by_user_id = Auth::id();
});
}
public function modifiedBy() {
return $this->belongsTo(User::class, 'modified_by_user_id');
}
}
trait HasAttachments {
protected static function bootHasAttachments() {
static::deleting(function ($instance) {
$instance->attachments->each(function ($attachment) {
$attachment->delete();
});
});
}
public function attachments() {
return $this->morphMany(Attachment::class, 'attachable');
}
}
trait HasRelationships {
protected static function bootHasRelationships()
{
static::deleting(function ($instance) {
Relation::forObject( $instance )->delete();
});
}
public function related() { ...[long polymorphic relationship here]... }
/App/Models/Abstracts/HasTypeModelAbstract
use Illuminate\Database\Eloquent\Model;
// This thing just appends some custom attributes dynamically in the JSON and array forms. And no, 'user' is not a custom attribute key.
abstract class HasTypeModelAbstract extends Model {
public function newFromBuilder($attributes = array(), $connection = NULL) {
$instance = parent::newFromBuilder($attributes);
$instance->appendCustomAttributes();
return $instance;
}
protected function appendCustomAttributes() {
$this->append( $this->getCustomAttributesFromType() );
}
public function getCustomAttributesFromType() {
if ($this->type) {
return $this->type->custom_attributes ?
array_keys((array) $this->type->custom_attributes) : [];
} else {
return [];
}
}
protected function setCustomAttributesFromType($attributes = array()) {
if ($this->type) {
$custom_attribute_keys = $this->getCustomAttributesFromType();
$custom_attributes = (array) $this->custom_attributes ?: [];
foreach ($custom_attribute_keys as $key) {
$attributes[$key] = array_get($custom_attributes, $key);
}
}
return $attributes;
}
protected function addMutatedAttributesToArray(array $attributes, array $mutatedAttributes) {
$this->appendCustomAttributes($this, $attributes);
$attributes = $this->setCustomAttributesFromType($attributes);
return parent::addMutatedAttributesToArray($attributes, $mutatedAttributes);
}
protected function mutateAttribute($key, $value)
{
$keys = $this->getCustomAttributesFromType();
if ( in_array($key, $keys) ) {
return $this->getCustomAttributeValue( $key, $value );
}
return parent::mutateAttribute($key, $value);
}
protected function getCustomAttributeValue($key, $value) {
$custom_attributes = (array) $this->custom_attributes ?: [];
return array_get($custom_attributes, $key, $value);
}
I have to be honest - quickly looking at the code I don't see anything wrong but it doesn't mean everything is for sure ok.
If I were you, I would try to limit Person model just to:
class Person extends \Illuminate\Database\Eloquent\Model {
protected $fillable = [
'person_type_id',
'email',
'fname',
'lname',
'user_id',
'modified_by_user_id',
'audited_at',
'custom_attributes'
];
protected $casts = [
'custom_attributes' => 'json',
'user_id' => 'integer',
'modified_by_user_id' => 'integer',
'person_type_id' => 'integer'
];
protected $dates = [
'audited_at'
];
public static $transformer = PersonTransformer::class;
public function user() {
return $this->belongsTo(User::class, 'user_id', 'id');
}
public function type() {
return $this->belongsTo(PersonType::class, 'person_type_id');
}
public function assets() {
return $this->hasMany(Asset::class, 'person_id');
}
}
and now I would verify if everything is fine. If it's fine, now you could investigate this further, add one trait and verify, add second trait and verify, finally extend from same class.
There must be bug somewhere but looking at this code it's hard do find anything
user is reserved name in eloquent.
try User instead of user
public function User() {
return $this->belongsTo(User::class, 'user_id', 'id');
}