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

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.

Related

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);

Laravel 7.x Observer not saving, created_by updated_by user

I have a Model named "Resource".
by using this command
php artisan make:observer ResourceObserver --model=Resource
this command create a new file, i update created, updated functions and update constructor
<?php
namespace App\Observers;
use App\Resource;
class ResourceObserver
{
protected $userID;
public function __construct()
{
$this->userID = auth()->user()->id;
}
/**
* Handle the resource "created" event.
*
* #param \App\Resource $resource
* #return void
*/
public function created(Resource $resource)
{
$resource->created_by = $this->userID;
}
/**
* Handle the resource "updated" event.
*
* #param \App\Resource $resource
* #return void
*/
public function updated(Resource $resource)
{
$resource->updated_by = $this->userID;
}
/**
* Handle the resource "deleted" event.
*
* #param \App\Resource $resource
* #return void
*/
public function deleted(Resource $resource)
{
//
}
/**
* Handle the resource "restored" event.
*
* #param \App\Resource $resource
* #return void
*/
public function restored(Resource $resource)
{
//
}
/**
* Handle the resource "force deleted" event.
*
* #param \App\Resource $resource
* #return void
*/
public function forceDeleted(Resource $resource)
{
//
}
}
this is my migration:
public function up()
{
Schema::create('resources', function (Blueprint $table) {
$table->id();
// some fields here
$table->foreignId('created_by')->nullable()->default(null)->constrained('users')->onDelete('set null');
$table->foreignId('updated_by')->nullable()->default(null)->constrained('users')->onDelete('set null');
$table->timestamps();
});
}
then you should register the observer in AppServiceProvider like this:
use App\Observers\ResourceObserver;
use App\Resource;
public function boot()
{
Schema::defaultStringLength(191);
Resource::observe(ResourceObserver::class);
}
Now the problem appears when update any record it is not save the user_id
to update i use update function in ResourceController
public function update(Request $request, Resource $resource)
{
$validations = [
// some validations
];
$request->validate($validations);
try {
if (!empty($resource)) {
$resource->field_a = $request->field_a;
$resource->field_b = $request->field_b;
$resource->field_c = $request->field_c;
$resource->save();
return 'done messge';
} else {
return 'error message';
}
} catch (\Exception $e) {
return 'bug message';
}
}
Any help please?!
When issuing a mass update or delete via Eloquent, the saved, updated, deleting, and deleted model events will not be fired for the affected models. This is because the models are never actually retrieved when issuing a mass update or delete.
So, In ResourceObserver i just changed from method from updated to updating,
and created to creating

How to do hasMany and belongsToMany at same model?

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.

Busting cache on relation with Laravel 5.6

I have a model named Tournament where each Tournament is cached with some of its relations, using a key for each model (i.e. tournament.1).
return \Cache::remember('tournament.' . $id, 60*24*7, function() use ($id) {
return Tournament::where('id', $id)
->with(['prizes', 'sponsor'])
->firstOrFail();
});
When I update on the relations, I would like to forget that tournament's key. I know I could use event like this:
public static function boot()
{
static::saving(function ($prize) {
\Cache::forget('tournament.' . $prize->tournament->id);
});
return parent::boot();
}
However, doing this means I have to repeat this code for all other relations as well. I could probably create a trait for this, but is there a better way of doing what I want to achieve?
I ended up solving this using a trait.
namespace App\Traits;
trait ShouldCacheBust
{
/**
* The "booting" method of the model.
*/
public static function boot()
{
static::saving(function ($model) {
$cacheKey = static::cacheBustKey($model);
if ($cacheKey) {
\Cache::forget($cacheKey);
}
});
return parent::boot();
}
/**
* Return the key to be removed from Cache
*
* #param Model $model
* #return string|null
*/
abstract public function cacheBustKey(Model $model);
}
Then using it like this:
/**
* Return the key to be removed from Cache
*
* #param Model $model
* #return mixed|string
*/
public static function cacheBustKey(Model $model)
{
return 'tournament.' . $model->id;
}

Laravel Auth "Call to a member function getReminderToken() on null"

No idea why I'm getting this error...
Call to a member function getRememberToken() on null (View: /home/vagrant/temptools/resources/views/layouts/main.blade.php) (View: /home/vagrant/temptools/resources/views/layouts/main.blade.php)
I have an Auth::check() on that blade page
I'm using https://github.com/invisnik/laravel-steam-auth
Routes:
Route::get('login', 'AuthController#redirectToSteam')->name('login');
Route::get('login/handle', 'AuthController#handle')->name('login.handle');
Route::post('logout', 'Auth\LoginController#logout')->name('logout');
AuthController:
namespace App\Http\Controllers;
use Invisnik\LaravelSteamAuth\SteamAuth;
use App\User;
use Auth;
class AuthController extends Controller
{
/**
* The SteamAuth instance.
*
* #var SteamAuth
*/
protected $steam;
/**
* The redirect URL.
*
* #var string
*/
protected $redirectURL = '/';
/**
* AuthController constructor.
*
* #param SteamAuth $steam
*/
public function __construct(SteamAuth $steam)
{
$this->steam = $steam;
}
/**
* Redirect the user to the authentication page
*
* #return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector
*/
public function redirectToSteam()
{
return $this->steam->redirect();
}
/**
* Get user info and log in
*
* #return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector
*/
public function handle()
{
if ($this->steam->validate()) {
$info = $this->steam->getUserInfo();
if (!is_null($info)) {
$user = $this->findOrNewUser($info);
Auth::login($user, true);
return redirect($this->redirectURL); // redirect to site
}
}
return $this->redirectToSteam();
}
/**
* Getting user by info or created if not exists
*
* #param $info
* #return User
*/
protected function findOrNewUser($info)
{
$user = User::where('id', $info->steamID64)->first();
if (!is_null($user)) {
return $user;
}
return User::create([
'name' => $info->personaname,
'avatar' => $info->avatarfull,
'id' => $info->steamID64
]);
}
}
app/User:
namespace App;
use Illuminate\Notifications\Notifiable;
use Illuminate\Foundation\Auth\User as Authenticatable;
class User extends Authenticatable
{
use Notifiable;
protected $fillable = [
'id', 'name', 'avatar',
];
protected $hidden = [
'remember_token',
];
}
create_users_table migration:
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class CreateUsersTable extends Migration
{
/**
* Run the migrations.
*
* #return void
*/
public function up()
{
Schema::create('users', function (Blueprint $table) {
$table->bigInteger('id')->unsigned();
$table->string('name');
$table->string('avatar');
$table->rememberToken();
$table->timestamps();
$table->primary('id');
});
}
/**
* Reverse the migrations.
*
* #return void
*/
public function down()
{
Schema::dropIfExists('users');
}
}
Have deleted the password recovery migration.
I also get the error if I hit the logout path:
Call to a member function getRememberToken() on null
========
Looking into errors, the error seems to be in laravel/framework/sec/Illuminate/Auth/EloquentUserProvider.php line 67
public function retrieveByToken($identifier, $token)
{
$model = $this->createModel();
$model = $model->where($model->getAuthIdentifierName(), $identifier)->first();
$rememberToken = $model->getRememberToken();
return $model && $rememberToken && hash_equals($rememberToken, $token) ? $model : null;
}
Still no idea how to fix it though
Looks like this package uses Laravel Auth... How do you set unique ID for your users? Generally you should auto increment them... Don't forget that Laravel's auth is reliant on many conventions... Look at AuthenticatesUsers trait for a peek... but one of the fields required is email...
trait AuthenticatesUsers
{
/**
* Get the login username to be used by the controller.
*
* #return string
*/
public function username()
{
return 'email';
}
}
Take a look around the Auth structure, look at the default 'web' guard (look at auth.php in the config directory as a starting point... ).
public function up()
{
Schema::create('users', function (Blueprint $table) {
$table->increments('id');
$table->string('name');
$table->string('email')->unique(); //Unique ID for login in laravel? The AuthenticatesUser trait uses email as username...
$table->string('password');
$table->string('avatar');
$table->rememberToken();
$table->timestamps();
});
}
Hope this helps...
Go into this function parent:
public function retrieveByToken($identifier, $token){
$model = $this->createModel();
$model = $model->where($model->getAuthIdentifierName(), $identifier)->first();
$rememberToken = $model->getRememberToken();
return $model && $rememberToken && hash_equals($rememberToken, $token) ? $model : null;
}
dump the model and $identifier,
create a model row with that identifier and it will fixed!

Resources