How to do hasMany and belongsToMany at same model? - laravel

I have 2 models, Employee & FieldReport. I need to create relations based on the following conditions:
Field report is owned by an employee whose character is absolute
(owner's data must be displayed and cannot be edited), where the
report field also has a tag to mark who the employees are in that
report field.
An employee, himself, has many field reports.
For now, I've made a relationship, something like this:
Employee has many Field Reports.
Employee belongs to many Field Reports.
Field Report belongs to Employee.
Field Report belongs to many Employees.
Then I have a problem where PHP doesn't allow the same method name (in the Employee model).
Example:
Has many has the method name fieldReports ()
Belongs to many also have the method name fieldReports ()
Whereas if I define the function name custom, I cannot get the value to fill the first pivot column and generate an error like the following:
SQLSTATE [23000]: Integrity constraint violation: 19 NOT NULL
constraint failed: field_report_participant.field_report_id (SQL:
insert into "field_report_participant" ("id", "participant_id") values
​​(1, 2))
Is there any solution? This is how my scripts looks like:
Employee.php
/**
* Each employee has many fieldReports.
*
* #return \Illuminate\Database\Eloquent\Relationship\HasMany
*/
public function fieldReports()
{
return $this->hasMany(FieldReport::class);
}
/**
* Each employee belongs to many fieldReports.
*
* #return \Illuminate\Database\Eloquent\Relationship\BelongsToMany
*/
public function fieldReports()
{
return $this->belongsToMany(FieldReport::class);
}
FieldReportController.php
/**
* Store a newly created resource in storage.
*
* #param \App\Http\Requests\RequestFieldReport $request
* #return \Illuminate\Http\Response
*/
public function store(RequestFieldReport $request)
{
$fieldReport = $this->data($request, $this->storeImages($request));
$fieldReport->participants()->sync(
$request->participants
);
return response()->json([
'created' => true,
'data' => $fieldReport,
], 201);
}
FieldReport.php
/**
* Each field report belongs to a company.
*
* #return \Illuminate\Database\Eloquent\Relationship\BelongsTo
*/
public function company()
{
return $this->belongsTo(Company::class);
}
/**
* Each field report belongs to a employee.
*
* #return \Illuminate\Database\Eloquent\Relationship\BelongsTo
*/
public function employee()
{
return $this->belongsTo(Employee::class);
}
/**
* Each field report belongs to many participants.
*
* #return \Illuminate\Database\Eloquent\Relationship\BelongsToMany
*/
public function participants()
{
return $this->belongsToMany(Employee::class, 'field_report_participant', 'participant_id', 'id');
}
create_field_reports_table.php
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class CreateFieldReportsTable extends Migration
{
/**
* Run the migrations.
*
* #return void
*/
public function up()
{
Schema::create('field_reports', function (Blueprint $table) {
$table->id();
$table->bigInteger('company_id');
$table->bigInteger('employee_id');
$table->string('title', 100);
$table->text('chronology');
$table->json('images')->nullable();
$table->timestamp('closed_at')->nullable();
$table->string('closed_by', 100)->nullable();
$table->timestamp('opened_at')->nullable();
$table->string('opened_by', 100)->nullable();
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* #return void
*/
public function down()
{
Schema::dropIfExists('field_reports');
}
}
field_report_participant_table.php
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class CreateFieldReportParticipantTable extends Migration
{
/**
* Run the migrations.
*
* #return void
*/
public function up()
{
Schema::create('field_report_participant', function (Blueprint $table) {
$table->id();
$table->bigInteger('field_report_id');
$table->bigInteger('participant_id');
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* #return void
*/
public function down()
{
Schema::dropIfExists('field_report_participant');
}
}

After an hour pulling off my hair, trying to do a backflip and asked on each different forums, finally I had the answer. Unfortunately, he has no account on this forum and can't give the answer for this question.
The problem is I put a wrong key on the participants method which causing the field_report_id placed in a wrong place, in this case; id. Which is solved by doing this:
/**
* Each field report belongs to many participants.
*
* #return \Illuminate\Database\Eloquent\Relationship\BelongsToMany
*/
public function participants()
{
return $this->belongsToMany(Employee::class, 'field_report_participant', 'field_report_id', 'participant_id');
}
And then, on the Employee class, I could create exactly different method and link it with the pivot table. Like this:
/**
* Each employee belongs to many assignedFieldReports.
*
* #return \Illuminate\Database\Eloquent\Relationship\BelongsToMany
*/
public function assignedFieldReports()
{
return $this->belongsToMany(FieldReport::class, 'field_report_participant', 'participant_id', 'field_report_id');
}
Hopefully, it can help someone facing this exact same issue on the future.

Related

laravel how to call a method when a row inserted in model?

I have two model (Cart & AcceptedCart) and I want to run this method when a row insrted in AcceptedCart model :
public function dataUpdated()
{
$cart = Cart::where('id' , $this->cart_id)->first();
$sum = 0;
$acceptedCarts = AcceptedCart::where('cart_id' , $this->cart_id)->get();
foreach($acceptedCarts as $acceptedCart){
$sum += $acceptedCart->accepted_count;
}
if ($sum == $cart->product_quantity){
$cart->full_accepted = true;
$cart->save();
}
}
as you see, I change full_accpted = true in the cart model.
the AcceptedCart migration is :
public function up()
{
Schema::create('accepted_carts', function (Blueprint $table) {
$table->id();
$table->unsignedBigInteger('cart_id');
$table->unsignedBigInteger('accepted_by')->nullable();
$table->integer('accepted_count');
$table->timestamps();
$table->foreign('cart_id')->references('id')->on('carts');
});
}
and Cart migration is :
public function up()
{
Schema::create('carts', function (Blueprint $table) {
$table->id();
$table->boolean('full_accepted')->default(false);
$table->text('address');
$table->timestamps();
});
}
how can I call this dataUpdated method every time a row inserted to AcceptedCart model?
You can use the models booted() method to achieve this simple task, also you can use the separate observer class to listen to model events like created/updated/deleted, etc.
E.g. 1. How you can listen to model events in the same model.
class AcceptedCart extends Model
{
/**
* The "booted" method of the model.
*
* #return void
*/
protected static function booted()
{
static::created(function ($acceptedCart) {
$acceptedCart->dataUpdated();
});
// Similarly you can do for updated/deleted events as well
}
}
E.g. 2. You can use Observer class to listen to events
<?php
namespace App\Observers;
use App\Models\AcceptedCart;
class AcceptedCartObserver
{
/**
* Handle the AcceptedCart "created" event.
*
* #param \App\Models\AcceptedCart $acceptedCart
* #return void
*/
public function created(AcceptedCart $acceptedCart)
{
$acceptedCart->dataUpdated();
}
/**
* Handle the AcceptedCart "updated" event.
*
* #param \App\Models\AcceptedCart $acceptedCart
* #return void
*/
public function updated(AcceptedCart $acceptedCart)
{
// Similarly for update
}
}
You can learn more here about Model Observers
You might want to consider using Observers.
Events can be fired when a Model is created/updated and so on.
You can find out more here.

SQLSTATE[42703]: Undefined column: 7 ERROR: column

even if I add protected $primaryKey = 'TEA_ID' in the model am getting this error , am using postgres as database
my migration:
/**
* Run the migrations.
*
* #return void
*/
public function up()
{
Schema::create('T_TEAM_TEA', function (Blueprint $table) {
$table->increments('TEA_ID');
$table->integer('TEA_MANAGER') ;
$table->string('TEA_NAME');
$table->string('TEA_DESCRIPTION');
$table->integer('TEA_SITE') ;
$table->timestamps();
});
}
my model :
/**
* The table associated with the model.
*
* #var string
*/
protected $table = 'T_TEAM_TEA';
/**
* Protected var for acronym
*
* #var string
*/
protected $acronym = 'TEA';
/**
* The primary key associated with the table.
*
* #var string
*/
public $primaryKey = 'TEA_ID';
/**
* Mass assignement
*
* #var array
*/
/**
* Relation for site table
*
* #return HasOne
*/
public function site()
{
return $this->belongsTo(
Site::class,
(new Site)->getKeyName(),
$this->acronym . '_SITE'
);
}
/**
* Relation for user table
*
* #return HasMany
*/
public function users()
{
return $this->hasMany(
User::class,
(new User)->getAcronym() . '_TEAM',
$this->primaryKey
);
}
/**
* Get Acronym
*
* #return string
*/
public function getAcronym()
{
return $this->acronym;
}
mistake in this
public $primaryKey = 'TEA_ID';
fix like this.
protected $primaryKey = 'TEA_ID';
If you have no data or any important data so far in the database you can remigrate freshly by this command
php artisan migrate:fresh
this will remigrate everything since everytime you do a change you migrate in your migrations table. The change won't be affected unless this table has reflected changes...

How to use laravel decrement methods in a one to many relationship particularly to a specific column

I have two tables warrants and expenditures as follows
warrants table
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class CreateWarrantsTable extends Migration
{
/**
* Run the migrations.
*
* #return void
*/
public function up()
{
Schema::create('warrants', function (Blueprint $table) {
$table->id();
$table->string('allocation');
$table->double('originalWarrant',8,2);
$table->string('description');
$table->string('awno');
$table->date('warrant_date') ;
$table->string('donor_code') ;
$table->string('donor_name');
$table->string('ministry') ;
$table->softdeletes();
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* #return void
*/
public function down()
{
Schema::dropIfExists('warrants');
}
}
expenditures table
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class CreateExpendituresTable extends Migration
{
/**
* Run the migrations.
*
* #return void
*/
public function up()
{
Schema::create('expenditures', function (Blueprint $table) {
$table->id();
$table->date('expdate');
$table->string('supliers');
$table->string('details');
$table->string('pvno')->nullable();
$table->string('lpono')->nullable();
$table->string('invoice_no')->nullable();
$table->string('dwno')->nullable();
$table->integer('warrant_id') ;
$table->double('actual_exp',8,2);
$table->softdeletes();
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* #return void
*/
public function down()
{
Schema::dropIfExists('expenditures');
}
}
I have been trying to decrement a column called originalWarrant (i.e. the amount warranted) in the warrants table from expenditures table. Below is my store method in my ExpenditureController
public function store(CreateExpenditureRequest $request)
{
// $input = $request->all()
$expenditure = $this->expenditureRepository->create(
[
'expdate' => $request->expdate,
'supliers' => $request->supliers,
'details' => $request->details,
'pvno' => $request->pvno,
'lpono' => $request->lpono,
'invoice_no' => $request->invoice_no,
'dwno' => $request->dwno,
'warrant_id' => $request->warrant_id,
'actual_exp' => $request->actual_exp,
'output' => $request->output]
);
$warrant = $this->warrantRepository->decreaseAllocationAmount('originalWarrant',$request->actual_exp);
Flash::success('Expenditure saved successfully.');
return redirect(route('trackexpenses.expenditures.index'));
}
I put my decreaseAllocationAmount() in my WarrantRepository as below
<?php
namespace App\Repositories\Trackexpenses;
use App\Models\Trackexpenses\Warrant;
use App\Repositories\BaseRepository;
/**
* Class WarrantRepository
* #package App\Repositories\Trackexpenses
* #version December 18, 2020, 4:12 am UTC
*/
class WarrantRepository extends BaseRepository
{
/**
* Configure the Model
**/
public function model()
{
return Warrant::class;
}
public function decreaseAllocationAmount($columnname = 'originalWarrant', $actual_exp)
{
return $this->model->query()
->orderBy($columnname)
->decrement($columnname, $actual_exp);
}
}
With my decreaseAllocationAmount() methods above is able to decrement originalWarrant given the actual_exp, however all orinalWarrant amount are decremented. How to decrement a particular originalWarrant column with a given $actual_exp specific for the originalWarrant?
For you to not decrement all rows of Warrants, you should make conditional SQL logic based on the model.
public function decreaseAllocationAmount(Expenditure $expenditure, $columnname = 'originalWarrant', $actual_exp)
{
return $this->model->query()
->where('id', $expenditure->warrant_id)
->orderBy($columnname)
->decrement($columnname, $actual_exp);
}
When you call it, you need to pass the $expenditure.
$warrant = $this->warrantRepository->decreaseAllocationAmount($expenditure, 'originalWarrant',$request->actual_exp);

"SQLSTATE[HY000]: General error: 1366 Incorrect integer value:"

I am a beginner in Laravel, making reply functions.
I would appreciate it if you could fix this code.
I got this error:
"SQLSTATE[HY000]: General error: 1366 Incorrect integer value: '<div>da</div>' for column 'content' at row 1 (SQL: insert into `replies` (`content`, `discussion_ ▶"
2019_07_26_035335_create_replies_table.php
This is how my table looks:
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class CreateRepliesTable extends Migration
{
/**
* Run the migrations.
*
* #return void
*/
public function up()
{
Schema::create('replies', function (Blueprint $table) {
$table->bigIncrements('id');
$table->integer('user_id');
$table->integer('discussion_id');
$table->integer('content');
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* #return void
*/
public function down()
{
Schema::dropIfExists('replies');
}
}
RepliesController.php
namespace LaravelForum\Http\Controllers;
use Illuminate\Http\Request;
// 2019/07/29
// C:\laravel-apps\bulletin-board\app\Http\Requests\CreateReplyRequest.php
use LaravelForum\Http\Requests\CreateReplyRequest;
// postscript
use LaravelForum\Discussion;
class RepliesController extends Controller
{
/**
* Display a listing of the resource.
*
* #return \Illuminate\Http\Response
*/
public function index()
{
//
}
/**
* Show the form for creating a new resource.
*
* #return \Illuminate\Http\Response
*/
public function create()
{
//
}
/**
* Store a newly created resource in storage.
*
* #param \Illuminate\Http\Request $request
* #return \Illuminate\Http\Response
*/
public function store(CreateReplyRequest $request, Discussion $discussion)
{
// C:\laravel-apps\bulletin-board\app\Http\Requests\CreateReplyRequest.php
auth()->user()->replies()->create([
'content' => $request->content ,
'discussion_id' => $discussion->id
]);
session()->flash('success', 'Reply added');
return redirect()->back();
}
/**
* Display the specified resource.
*
* #param int $id
* #return \Illuminate\Http\Response
*/
public function show($id)
{
//
}
/**
* Show the form for editing the specified resource.
*
* #param int $id
* #return \Illuminate\Http\Response
*/
public function edit($id)
{
//
}
/**
* Update the specified resource in storage.
*
* #param \Illuminate\Http\Request $request
* #param int $id
* #return \Illuminate\Http\Response
*/
public function update(Request $request, $id)
{
//
}
/**
* Remove the specified resource from storage.
*
* #param int $id
* #return \Illuminate\Http\Response
*/
public function destroy($id)
{
//
}
}
C:\laravel-apps\bulletin-board\app\Reply.php
<?php
namespace LaravelForum;
class Reply extends Model
{
//
public function owner()
{
return $this->belongsTo(User::class, 'user_id');
}
public function discussion()
{
return $this->belongsTo(Discussion::class);
}
}
C:\laravel-apps\bulletin-board\app\Http\Requests\CreateReplyRequest.php
<?php
namespace LaravelForum\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
class CreateReplyRequest extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*
* #return bool
*/
public function authorize()
{
return true;
}
/**
* Get the validation rules that apply to the request.
*
* #return array
*/
public function rules()
{
return [
//
'content' => 'required'
];
}
}
you are using $table->integer('content'); interger value for content column. instead of using integer value use $table->text('content'); for the content. As i felt you are refering reply body as content.

Laravel Many-to-Many Pivot Table

I have a fairly simple question about the use of Pivot tables in laravel. Firstly ill give some information about my situation, I have two tables name "Vehicles", and "Events". Now I would like to create a table that will be used to hold vehicles that have registered for an event. Now the relationship that between these two tables would be that "Many Vehicles can register for Many Events" and vice versa. would a Pivot table be the best way to accomplish this, and if so could more singular values be in the same table?
You can associate an event with multiple vehicles and a vehicle to multiple events by doing something like this with your models (not tested):
Vehicle.php
<?php
namespace App;
use App\Event;
use Illuminate\Database\Eloquent\Model;
class Vehicle extends Model
{
...
/**
* Get the events that this vehicle belongs to.
*
* #return \App\Event
*/
public function events()
{
return $this->belongsToMany(Event::class, 'vehicle_event');
}
}
Event.php
<?php
namespace App;
use App\Vehicle;
use Illuminate\Database\Eloquent\Model;
class Event extends Model
{
...
/**
* Get the vehicles that this event has.
*
* #return \App\Vehicle
*/
public function events()
{
return $this->hasMany(Vehicle::class, 'vehicle_event');
}
}
You'll also need a migration file for the pivot table:
...
/**
* Run the migrations.
*
* #return void
*/
public function up()
{
Schema::create('vehicle_event', function(Blueprint $table)
{
$table->integer('vehicle_id')->unsigned()->index();
$table->foreign('vehicle_id')->references('id')->on('vehicles');
$table->integer('event_id')->unsigned()->index();
$table->foreign('event_id')->references('id')->on('events');
});
}
/**
* Reverse the migrations.
*
* #return void
*/
public function down()
{
Schema::dropIfExists('vehicle_event');
}
...
Then you can to use attach() and detach() to associate vehicles with events or vice versa.

Resources