Laravel update hasMany relationship - laravel

I just read more documentation and issues for this problem to resolve that , but nothing work for me, i have 2 table wit this models:
class Month extends Model
{
protected $guarded = ['id'];
public function lessons()
{
return $this->hasMany(Lesson::class);
}
}
class Lesson extends Model
{
protected $guarded = ['id'];
public function months()
{
return $this->belongsTo(Month::class);
}
}
I can save some data with relation ship with this sample code and that work fine:
$month = Month::find(1);
$lesson = new Lesson();
$lesson->title = $request->title;
$lesson->content = $request->content;
$lesson->file_url = $uploadedFilePath;
$lesson->filename = $filename;
$lesson->time = $request->time;
$month = $month->lessons()->save($lesson);
now I try to update some lesson fields with this code:
$lesson = Lesson::find($id);
$lesson->update([
'title' => $request->title,
'content' => $request->content,
'file_url' => $uploadedFilePath,
'filename' => $filename,
'time' => $request->time
]);
$month = Month::find($request->months['0']);
$lesson = Lesson::find($lesson->id);
$lesson->months()->associate($month)->save();
in that I try to change month_id column on Lesson table in database with for example $month->id value, how can I do that?
UPDATED:
class Lesson extends Model
{
protected $guarded = ['id'];
public function month()
{
return $this->belongsTo(Month::class);
}
}
Controller:
$lesson->update([
'title' => $request->title,
'content' => $request->content,
'file_url' => $uploadedFilePath,
'filename' => $filename,
'time' => $request->time
]);
$month = Month::find($request->months['0']);
$lesson = Lesson::find($lesson->id);
$lesson->month()->associate($month)->save();
$lesson->update(['month_id' => $month->id]);
Migrations:
Schema::create('months', function (Blueprint $table) {
$table->increments('id');
$table->string('title');
$table->string('description');
$table->string('price');
$table->timestamps();
});
Schema::create('lessons', function (Blueprint $table) {
$table->increments('id');
$table->integer('month_id')->unsigned();
$table->string('title');
$table->longText('content');
$table->string('file_url');
$table->string('filename');
$table->string('time', 50);
$table->foreign('month_id')->references('id')->on('months')->onDelete('cascade');
$table->timestamps();
});

Firstly, the name of method months() should be renamed to month because it's returning single month not multiple months.
Secondly, If your Lesson has a field called month_id then its far simpler than you are thinking about. We can just change these two lines:
$lesson = Lesson::find($lesson->id);
$lesson->months()->associate($month)->save();
To the following line:
$lesson->update(['month_id' => $month->id);
It should update the month_id of your $lesson to the $month->id

Related

PhpUnit - Expected Status 200 But Received 500

I have users table with hasMany educational backgrounds & educational awards. Then that educational backgrounds hasMany educational awards
Here's my Testcase when user uploads image my endpoint receives it
public function testuploadUsersImageEducationalAwards()
{
Storage::fake('public');
$photo = UploadedFile::fake()->create('photo.png')->size(25000);
$data = [
'photo' => $photo,
'award' => $this->faker->word,
'educational_background_id' => EducationalBackground::factory()->create()->id
];
$this->withoutExceptionHandling();
$response = $this->sendPostRequestToEndpoint($data, 200);
$data['file_name'] = $response['file_name'];
unset($data['photo']);
$response->assertJson($data)
->assertJsonStructure([
'id',
'award',
'photo',
'educational_background_id',
'created_at',
'updated_at',
]);
$this->assertDatabaseHas('users.educational_awards', $data);
}
Here's my endpoint with assert status 200
private function sendPostRequestToEndpoint(array $data, $status)
{
return $this->json("POST", '/api/users/educational-award/upload-picture', $data)->assertStatus($status);
}
UPDATE
Here's my EducationalBackgroundFactory
class EducationalBackgroundFactory extends Factory
{
protected $model = EducationalBackground::class;
public function definition()
{
return [
'user_id' => User::factory()->create()->id,
'studies_type' => $this->faker->randomElement([EducationalBackground::BASIC, EducationalBackground::SECONDARY, EducationalBackground::UNDERGRADUATE, EducationalBackground::GRADUATESCHOOL]),
'year' => Carbon::now()->format("Y"),
'course' => $this->faker->word,
];
}
}
Here's my EducationalBackground model
class EducationalBackground extends Model
{
use HasFactory;
const BASIC = "basic";
const SECONDARY = "secondary";
const UNDERGRADUATE = "undergrad";
const GRADUATESCHOOL = "grad";
protected $table = 'users.educational_backgrounds';
protected $fillable = [
'user_id',
'studies_type',
'year',
'course',
];
public function user()
{
return $this->belongsTo('App\Models\User', 'user_id');
}
public function educationalAwards()
{
return $this->hasMany("App\Models\Users\EducationalAward", "educational_background_id");
}
}
Here's my migration
public function up()
{
Schema::create('users.educational_backgrounds', function(Blueprint $table) {
$table->bigIncrements('id');
$table->integer('user_id')->unsigned();
$table->foreign('user_id')->references('id')->on('users');
$table->enum('studies_type', ['basic', 'secondary', 'undergrad', 'grad']);
$table->integer('year');
$table->string('course')->nullable();
$table->timestamps();
});
}
Here's my controller code
public function uploadUsersImageEducationalAwards(UserImageRequest $request, EducationalBackground $educational_background)
{
$uploaded_image = $request->photo->store('users/educational_awards');
$file_type = $request->photo->getClientOriginalExtension();
$file = EducationalAward::create([
'educational_background_id' => $educational_background->id,
'award' => $request->award,
'photo' => $uploaded_image,
]);
return response()->json($file, 200);
}
But this gives me 500 status which i found a way to log error in details. Here's an image for more clarity
remove unset function before sending response.

Save multiple data into database from distance relationships in laravel

I am trying to save multiple data which is having a many-to-many relationship. My store method is like the below.
public function store(Specification $specification, Fraction $fraction, Request $request)
{
$data = return request()->validate([
'specification_no' => 'required|string',
'grade' => 'required|integer',
'gname' => 'required|integer',
'gsize' => 'required|integer',
'fractions.*.fraction_min' => 'required',
'fractions.*.fraction_max' => 'required',
'fractions.*.unit_id' => 'required',
'fraction_sieves.*.sieve_id' => 'required',
'params.*.para_min' => 'required',
'params.*.para_max' => 'required',
'units.*.unit_id' => 'required',
]);
// Save specificatio without duplicates.
$specification = new Specification($this->specificationValidation());
$checkSpecification = Specification::where('specification_no', request()->specification_no)->first();
if (!$checkSpecification) {
$specification->save();
$specification->grades()->syncWithoutDetaching($data['grade']);
$specification->gnames()->syncWithoutDetaching($data['gname']);
$specification->gsizes()->syncWithoutDetaching($data['gsize']);
$specification->sieves()->syncWithoutDetaching($data['fraction_sieves']);
// $specification->load('sieves.fractions');
$fraction = $specification->sieves()->fractions()->createMany($data['fractions']);
dd($fraction);
}
return redirect()->back()->with('alert', 'Duplicate Specification number.');
}
Models & migrations like below.
Fraction-Model
class Fraction extends Model{
protected $guarded = [];
public function sieves()
{
return $this->belongsToMany(Sieve::class);
}
}
migration - fraction
public function up(){
Schema::create('fractions', function (Blueprint $table) {
$table->bigIncrements('id');
$table->double('fraction_min');
$table->double('fraction_max');
$table->unsignedBigInteger('unit_id');
$table->timestamps();
});
}
model - sieve
class Sieve extends Model{
protected $guarded = [];
public function specifications(){
return $this->belongsToMany(Specification::class);
}
public function fractions(){
return $this->belongsToMany(Fraction::class);
}
}
migration pivot table - fraction_sieve
public function up()
{
Schema::create('fraction_sieve', function (Blueprint $table) {
$table->bigIncrements('id');
$table->unsignedBigInteger('sieve_id');
$table->unsignedBigInteger('fraction_id');
$table->timestamps();
});
}
public function down()
{
Schema::dropIfExists('fraction_sieve');
}
When I use the below code
$fraction = $specification->sieves()->fractions()->createMany($data['fractions']);
to save fractions to fractions table with distance relationships from specifications->sieves->fractions, I am getting errors like this.
BadMethodCallException
Call to undefined method Illuminate\Database\Eloquent\Relations\BelongsToMany::fractions()
Normally this could be the way of creating new multiple data into db. But I can not understand why I'm getting errors. Can someone explain what I've messed up?
This is the wrong way you are trying to use: ->sieves()->fractions()
because the Sieve and Fraction model have many to many relationship so firstly you need to specify which sieves you want to create fractions for:
->sieves()->first()->fractions()->....
or
->sieves()->find(3)->fractions()->....

Cant persist data to the database? (Laravel)

I'm new to Laravel. My data doesn't seem to get to the database. Here's my Controller code:
public function store(Request $request)
{
$rules = [
'first_name' => 'required|string|min:3|max:255',
'last_name' => 'required|string|min:3|max:255',
'gender' => 'required|string|min:3|max:255',
'qualifications' => 'required|string|min:3|max:255'
];
$validator = FacadesValidator::make($request->all(), $rules);
if ($validator->fails()) {
return redirect('/home')
->withInput()
->withErrors($validator);
} else{
$data = $request->input();
try {
$crud = new CRUD;
$crud->first_name = $request->get('first_name');
$crud->last_name = $request->get('last_name');
$crud->gender = $request->get('gender');
$crud->qualifications = $request->get('qualifications');
$crud->save();
return redirect('/home')->with('status',"Insert successfully");
} catch (\Throwable $th) {
return redirect('/home')->with('failed',"Insert Failed");
}
}
}
And my Model:
protected $table = '$user';
protected $fillable = [
'first_name', 'last_name', 'gender', 'qualifications'
];
public $timestamps = true;
And my route(Web.php):
Route::post('/store', [App\Http\Controllers\CRUDController::class, 'store'])->name('insert');
Here is my migration for the users table:
Schema::create('user', function(Blueprint $table) {
$table->bigIncrements('id');
$table->string('first_name');
$table->string('last_name');
$table->string('gender');
$table->string('qualifications');
$table->timestamps();
});
You should fix your table name in your model, since your table is called user:
protected $table = "user";
Also, you can use mass assignment to fill your models:
$crud = CRUD::create($request->validated());
It should fix your problem.

Insert data from multistep form with Laravel Relationships

I have a question for you.
I have a multisteps form:
Loan (this is sent from the calculator)
Create an account (email + password)
Personal data (first name, last name, phone number etc ...)
Addresses (street, city, state + if have correspondence address etc ...)
Employment (name of employer, address of employer, etc ...)
Finish (Review your data before sending ...)
the total number of inputs that are in the form is 60
I would like to split it into more tables
users
loans
personal
addresses
eployment
While I tried this, but something tells me that this method is not very safe even though it is working.
Therefore, I am turning here for advice and help as you would have done something like this?
Model User.php
class User extends Authenticatable
{
use Notifiable;
/**
* The attributes that are mass assignable.
*
* #var array
*/
protected $fillable = [
'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 loans() {
return $this->belongsToMany(Loan::class)->withTimestamps();
}
public function personal() {
return $this->belongsTo(Personal::class);
}
public function adress() {
return $this->belongsTo(Adress::class);
}
public function employment() {
return $this->belongsTo(Eployment::class);
}
}
Model Loan.php
class Loan extends Model
{
protected $hidden = ['amount', 'month', 'payment'];
public function users() {
return $this->belongsToMany(User::class)->withTimestamps();
}
}
Model Personal.php
class Personal extends Model
{
protected $fillable = [
'first_name', 'last_name', 'identification_number', 'identity_card_number', 'date_of_birth', 'phone'
];
public function users() {
return $this->hasMany(User::class);
}
}
Model Adress.php
protected $fillable = [
'adress', 'adress_number', 'city', 'postcode', 'country', 'correspond_adress', 'correspond_adress_number', 'correspond_city', 'correspond_postcode', 'correspond_country', 'type_of_housing', 'since_year', 'marital_status', 'number_of_kids'
];
public function users() {
return $this->hasMany(User::class);
}
Model Employment.php
class Eployment extends Model
{
protected $fillable = [
'type_of_occupation', 'client_ico', 'client_dic', 'employer_name', 'employer_ico', 'employment_adress', 'employment_city', 'month_of_arrival', 'year_of_arrival', 'net_monthly_income', 'other_income', 'payment_method', 'expenditure_payments', 'loan_repayments', 'wage_deductions', 'other_expenditure', 'have_bank_account', 'iban_account'
];
public function users() {
return $this->hasMany(User::class);
}
}
DB: (users, loans, personal, adresses, eployment
Schema::create('users', function (Blueprint $table) {
$table->id();
$table->string('email')->unique();
$table->timestamp('email_verified_at')->nullable();
$table->string('password');
$table->rememberToken();
$table->timestamps();
});
Schema::create('loans', function (Blueprint $table) {
$table->id();
$table->string('amount');
$table->string('month');
$table->string('payment');
$table->timestamps();
});
Schema::create('loan_user', function (Blueprint $table) {
$table->id();
$table->unsignedBigInteger('user_id');
$table->unsignedBigInteger('loan_id');
$table->foreign('user_id')->references('id')->on('users')->onUpdate('cascade')->onDelete('cascade');
$table->foreign('loan_id')->references('id')->on('loans')->onUpdate('cascade')->onDelete('cascade');
$table->timestamps();
});
Schema::create('adresses', function (Blueprint $table) {
$table->id();
$table->unsignedBigInteger('user_id');
$table->string('adress');
$table->string('adress_number');
$table->string('city');
$table->string('postcode');
$table->string('country');
$table->string('correspond_adress')->nullable();
$table->string('correspond_adress_number')->nullable();
$table->string('correspond_city')->nullable();
$table->string('correspond_postcode')->nullable();
$table->string('correspond_country')->nullable();
$table->string('type_of_housing');
$table->string('since_year');
$table->string('marital_status');
$table->string('number_of_kids');
$table->timestamps();
$table->foreign('user_id')->references('id')->on('users')->onUpdate('cascade')->onDelete('cascade');
});
Schema::create('eployments', function (Blueprint $table) {
$table->id();
$table->unsignedBigInteger('user_id');
$table->string('type_of_occupation');
$table->string('client_ico')->nullable();
$table->string('client_dic')->nullable();
$table->string('employer_name')->nullable();
$table->string('employer_ico')->nullable();
$table->string('employment_adress')->nullable();
$table->string('employment_city')->nullable();
$table->string('month_of_arrival')->nullable();
$table->string('year_of_arrival')->nullable();
$table->string('net_monthly_income');
$table->string('other_income')->nullable();
$table->string('payment_method');
$table->string('expenditure_payments');
$table->string('loan_repayments')->nullable();
$table->string('wage_deductions')->nullable();
$table->string('other_expenditure')->nullable();
$table->string('have_bank_account');
$table->string('iban_account');
$table->timestamps();
$table->foreign('user_id')->references('id')->on('users')->onUpdate('cascade')->onDelete('cascade');
});
LoanController.php
public function store(Loan $loan, User $user, Personal $personal, Adress $adress, Eployment $eployment, Request $request)
{
$user = User::create([
'email' => $request->email,
'password' => Hash::make($request->password),
]);
$data = new Loan;
$data->amount = $request->amount;
$data->month = $request->month;
$data->payment = $request->payment;
$personal = new Personal;
$personal->user_id = $user->id;
$personal->first_name = $request->first_name;
$personal->last_name = $request->last_name;
$personal->identification_number = $request->identification_number;
$personal->identity_card_number = $request->identity_card_number;
$personal->date_of_birth = $request->date_of_birth;
$personal->phone = $request->phone;
$adress = new Adress;
$adress->user_id = $user->id;
$adress->adress = $request->adress;
$adress->adress_number = $request->adress_number;
$adress->city = $request->city;
$adress->postcode = $request->postcode;
$adress->country = $request->country;
$adress->correspond_adress = $request->correspond_adress;
$adress->correspond_adress_number = $request->correspond_adress_number;
$adress->correspond_city = $request->correspond_city;
$adress->correspond_postcode = $request->correspond_postcode;
$adress->correspond_country = $request->correspond_country;
$adress->type_of_housing = $request->type_of_housing;
$adress->since_year = $request->since_year;
$adress->marital_status = $request->marital_status;
$adress->number_of_kids = $request->number_of_kids;
$eployment = new Eployment;
$eployment->user_id = $user->id;
$eployment->type_of_occupation = $request->type_of_occupation;
$eployment->client_ico = $request->client_ico;
$eployment->client_dic = $request->client_dic;
$eployment->employer_name = $request->employer_name;
$eployment->employer_ico = $request->employer_ico;
$eployment->employment_adress = $request->employment_adress;
$eployment->employment_city = $request->employment_city;
$eployment->month_of_arrival = $request->month_of_arrival;
$eployment->year_of_arrival = $request->year_of_arrival;
$eployment->net_monthly_income = $request->net_monthly_income;
$eployment->other_income = $request->other_income;
$eployment->payment_method = $request->payment_method;
$eployment->expenditure_payments = $request->expenditure_payments;
$eployment->loan_repayments = $request->loan_repayments;
$eployment->wage_deductions = $request->wage_deductions;
$eployment->other_expenditure = $request->other_expenditure;
$eployment->have_bank_account = $request->have_bank_account;
$eployment->iban_account = $request->iban_account;
$data->save();
$user->personal()->associate($user);
$personal->save();
$user->adress()->associate($user);
$adress->save();
$user->eployment()->associate($user);
$eployment->save();
$user->loans()->attach($data);
return redirect('/');
}
I don't know if I understood Laravel Relationships correctly but I try to ...
Excuse my English I'm Slovak and I helped with Google Translator
Well if you want to do everything with one request (building large form and manipulating it with JS) your store method is quite good.
You have to remove Loan $loan, User $user, Personal $personal, Adress $adress, Eployment $eployment, from your store method because your are not using model route binding for this: https://laravel.com/docs/5.8/routing#route-model-binding.
Also you don't need to associate ($user->personal()->associate($user);) or attach everything because you already adding user_id to every model you create.
Also don't forget form validation.

Laravel 5.4 Eloquent not Saving certain fields

I have been working on logging all user activities in Model events... But for some reason, the records are stored in the user_action table but the action_model field. This is my code.
User Action Class
`
class UserAction extends Model
{
use SoftDeletes;
protected $table = 'user_actions';
/**
*
*/
protected $fillable = [
'user_id','action', ' action_model', 'action_id'
];
public function user()
{
return $this->belongsTo(User::class, 'user_id');
}
}
`
UserActionObervable
class UserActionObserver
{
public function saved($model)
{
$type = $model->getTable();
// dd($type); when dump the value exists
if ($model->wasRecentlyCreated == true) {
// Data was just created
$action = 'created';
} else {
// Data was updated
$action = 'updated';
}
if (Sentinel::check()) {
UserAction::create([
'user_id' => Sentinel::getUser()->id,
'action' => $action,
'action_model' => 'model', //I tried to pass in constant
'action_id' => $model->id
]);
}
}
public function deleting($model)
{
if (Sentinel::check()) {
UserAction::create([
'user_id' => Sentinel::getUser()->id,
'action' => 'deleted',
'action_model' => $model->getTable(),
'action_id' => $model->id
]);
}
}
}
This is the schema
Schema::create('user_actions', function (Blueprint $table) {
$table->increments('id');
$table->integer('user_id')->unsigned()->nullable();
$table->string('action'); // created / updated / deleted
$table->string('action_model');
$table->integer('action_id')->nullable();
$table->timestamps();
$table->engine = 'InnoDB';
$table->foreign('user_id')->references('id')
->on('users')->onDelete('cascade');
});
protected $fillable = [
'user_id','action', ' action_model', 'action_id'
];
Try to remove the space before action_model. The field in $fillable doesn't match the key you're passing into the create() method.

Resources