Why is a observer class not working in model? - laravel

I have a Base model that I used to extend in all other Models. I created an observer for it called BaseObserver and registered it at boot method of EventServiceProvider. I have a creating event and would like to put my logic there every time I create a new other Model.
The problem is that the creating method in BaseObserver is not being called. But, when I created a closure for creating in Base model, it worked. What seems to be the problem here?
Base.php
namespace App\Models;
use Jenssegers\Mongodb\Eloquent\Model;
use Jenssegers\Mongodb\Eloquent\SoftDeletes;
class Base extends Model
{
use SoftDeletes;
protected $dates = ['deleted_at'];
// This closure will work but If I commented this out, BaseObserver's creating method won't work
protected static function booted()
{
static::creating(function ($base) {
dd('hellp from base model');
});
}
}
BaseObserver.php
namespace App\Observers;
use App\Models\Base;
class BaseObserver
{
public function creating(Base $base)
{
dd('hello from base obserer');
$base->created_by = auth()->user()?->_id;
}
public function updating(Base $base)
{
dd('hello from base obserer');
$base->updated_by = auth()->user()?->_id;
}
}
EventServiceProvider.php
namespace App\Providers;
use App\Models\Base;
use App\Observers\BaseObserver;
use Illuminate\Auth\Events\Registered;
use Illuminate\Auth\Listeners\SendEmailVerificationNotification;
use Illuminate\Foundation\Support\Providers\EventServiceProvider as ServiceProvider;
class EventServiceProvider extends ServiceProvider
{
protected $listen = [
Registered::class => [
SendEmailVerificationNotification::class,
],
];
public function boot()
{
Base::observe(BaseObserver::class);
}
public function shouldDiscoverEvents()
{
return false;
}
}
Team.php
namespace App\Models;
use App\Models\Base;
use Illuminate\Database\Eloquent\Factories\HasFactory;
class Team extends Base
{
use HasFactory;
protected $fillable = [
'name',
'leader_id',
'member_ids',
];
}
Result

it has to work
class Base extends Model
{
protected static function booted()
{
static::observe(BaseObserver::class);
}
}

Related

Unable to find observer in Laravel

I tried to register my ObserverHelper in the AppServiceProvider as below, but I am getting the following error.
Unable to find observer: App\Helpers\App\Observers\FileLogObserver
AppServiceProvider.php
use Illuminate\Support\ServiceProvider;
use App\Helpers\ObserverHelper;
class AppServiceProvider extends ServiceProvider
{
public function register()
{
}
public function boot()
{
ObserverHelper::register();
}
}
ObserverHelper.php
namespace App\Helpers;
class ObserverHelper
{
protected static $observers = [
'App\Models\FileLogs' => App\Observers\FileLogObserver::class,
];
public static function register()
{
foreach (self::$observers as $model => $observer) {
$model::observe($observer);
}
}
}
Try adding a \ (backslash that references the global namespace) in front of the App\Observers\FileLogObserver::class, or import that class.
With backslash (reference global namespace):
<?php
namespace App\Helpers;
class ObserverHelper
{
protected static $observers = [
'App\Models\FileLogs' => \App\Observers\FileLogObserver::class,
];
public static function register()
{
foreach(self::$observers as $model => $observer) {
$model::observe($observer);
}
}
}
or with import:
<?php
namespace App\Helpers;
use App\Observers\FileLogObserver;
class ObserverHelper
{
protected static $observers = [
'App\Models\FileLogs' => FileLogObserver::class,
];
public static function register()
{
foreach(self::$observers as $model => $observer) {
$model::observe($observer);
}
}
}
Note: Even though your code is a valid solution, consider creating a separate provider for defining observers (ObserverServiceProvider for example).

Override Eloquent Relation Create Method

I want to override create method, but with relation, it didn't touch the create method.
There are Two Models:
class User extends Model
{
public function user_detail()
{
return $this->hasOne(UserDetail::class);
}
}
class UserDetail extends Model
{
public static function create(array $attributes = [])
{
//I was trying to do something like
/*
if(isset($attributes['last_name']) && isset($attributes['first_name']))
{
$attributes['full_name']=$attributes['first_name'].' '.$attributes['last_name'];
}
unset($attributes['first_name'],$attributes['last_name']);
*/
Log::debug('create:',$attributes);
$model = static::query()->create($attributes);
return $model;
}
}
When I use UserDetail::create($validated), and there is a log in laravel.log, so I know the code touched my custom create method.
But if I use
$user = User::create($validated);
$user->user_detail()->create($validated);
There is no log in laravel.log, which means laravel didn't touch the create method, then how I supposed to do to override create method under this circumstance?(I'm using laravel 5.7)
Thank you #Jonas Staudenmeir, after I read the documentation, here is my solution.
If the $attributes are not in protected $fillable array, then I do it in the __construct method.
class UserDetail extends Model
{
protected $fillable=['full_name','updated_ip','created_ip'];
public function __construct(array $attributes = [])
{
if (isset($attributes['first_name']) && isset($attributes['last_name'])) {
$attributes['full_name'] = $attributes['first_name'].' '.$attributes['last_name'];
}
parent::__construct($attributes);
}
}
Otherwise, I do it in Observer.
namespace App\Observers;
use App\Models\UserDetail;
class UserDetailObserver
{
public function creating(UserDetail $userDetail)
{
$userDetail->created_ip = request()->ip();
}
public function updating(UserDetail $userDetail)
{
$userDetail->updated_ip = request()->ip();
}
}
Register Observer in AppServiceProvider.
namespace App\Providers;
use App\Models\UserDetail;
use App\Observers\UserDetailObserver;
class AppServiceProvider extends ServiceProvider
{
public function boot()
{
UserDetail::observe(UserDetailObserver::class);
}
}
I choose Observer instead of Event&Listener is for easy maintenance.

SQLSTATE[42S02]: Base table or view not found: 1146 Table 'seaurchin.availableroom' doesn't exist (42S02)

I'm trying to get the available room at specified date by the client. So far I tried using join and left join to get the available room.
Controller
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\RedirectResponse;
use App\client;
use App\reservation;
use App\booking;
use App\availableRoom;
use App\roomType;
use App\amenities;
use App\payment;
use App\roomReserved;
use App\Mail\ReservationDetail;
use Carbon\Carbon;
class ReservationController extends Controller
{
private $_availablerooms;
/**
* ReservationController constructor.
*/
public function __construct()
{
$this->_availablerooms = new availableRoom();
}
/**
* #param Request $request
* #return mixed
*/
public function checkAvailable(Request $request){
$checkInDate = date("d-m-Y", strtotime($request->start_date));
$checkOutDate = date("d-m-Y", strtotime($request->end_date));
$availableRooms = $this->_availablerooms->from('availableRoom as r')
->selectRaw('*,r.roomDoorNum, r.isAvailable, rt.title as roomType,res.roomReservedID')
->join('roomtype as rt','rt.roomTypeID','=','r.roomTypeID')
->leftjoin('roomReserved as rr','rr.roomID','=','r.roomID')
->leftjoin('reservation as res','res.roomReservedID','=', DB::raw('rr.roomReservedID AND (res.reservationDate BETWEEN '."$checkInDate".' AND ' ."$checkOutDate". ' OR res.expiryDate BETWEEN '."$checkInDate".' AND ' ."$checkOutDate".')' ))
->get();
return $availableRooms;
//return view('rooms');lorem
}
}
The problem is I'm getting this error now.
SQLSTATE[42S02]: Base table or view not found: 1146 Table
'seaurchin.availableroom' doesn't exist (42S02)
availableRoom model
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class availableRoom extends Model
{
protected $primaryKey = 'roomID';
protected $fillable = ['roomTypeID', 'roomDoorNum', 'isAvailable'];
public function roomAmenity()
{
return $this->hasMany('App\roomAmenity');
}
public function roomType()
{
return $this->hasOne('App\roomType');
}
public function roomAsset()
{
return $this->hasMany('App\roomAsset');
}
}
roomType model
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class roomType extends Model
{
protected $primaryKey = 'roomTypeID';
protected $fillable = ['title', 'nightRate', 'capacity', 'childrenAllowed', 'maxAdult', 'description'];
public function availableRoom()
{
return $this->hasMany('App\availableRoom');
}
}
roomReserved model
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class roomReserved extends Model
{
protected $primaryKey = 'roomReservedID';
protected $fillable = ['reservationID', 'roomID'];
public function reservation()
{
return $this->hasOne('App\Reservation');
}
}
reservation model
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class reservation extends Model
{
protected $primaryKey = 'reservationID';
protected $fillable = ['reservationDate', 'expiryDate', 'paymentReceived', 'status', 'actualCheckIn', 'actualCheckOut', 'roomReservedID'];
public function booking()
{
return $this->hasOne('App\Booking');
}
public function roomReserved()
{
return $this->hasMany('App\roomReserved');
}
}

Singleton created twice

In Laravel 5.4 I have registered a Service Provider that creates a singleton to my Context class which holds application context.
ContextServiceProvider
namespace App\Providers;
use Illuminate\Support\ServiceProvider;
use App;
class ContextServiceProvider extends ServiceProvider
{
/**
* Bootstrap the application services.
*
* #return void
*/
public function boot()
{
// Set-up application context
$context = app('context');
}
/**
* Register the application services.
*
* #return void
*/
public function register()
{
$this->app->singleton('context', function ($app) {
return new App\Context();
});
}
}
Then I create a Eloquent model with a global scope.
Model Media
namespace App\Models;
use App\Scopes\SchoolScope;
use Illuminate\Database\Eloquent\Model;
class Media extends Model
{
public static function boot()
{
parent::boot();
static::addGlobalScope(new SchoolScope());
}
}
Now when I access the Context singleton in the scope SchoolScope, the singleton is created twice!
SchoolScope
namespace App\Scopes;
use Illuminate\Database\Eloquent\Scope;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Builder;
use App\Models\School;
class SchoolScope implements Scope
{
protected $school;
public function __construct()
{
$this->school = app('context')->school;
}
public function apply(Builder $builder, Model $model)
{
$builder->where('school_id', '=', $this->school->id);
}
}
Does anyone know why the singleton is created twice?

Call to a member function save() on a non-object

I am building a small laravel app beginning level. I got error in code in I couldn't solve out.
Here is the code
post model
namespace App;
use Illuminate\Database\Eloquent\Model;
class post extends Model
{
public function user()
{
return $this->belongsTo('app\user');
}
}
user model
namespace App;
use Illuminate\Contracts\Auth\Authenticatable;
use Illuminate\Database\Eloquent\Model;
class user extends Model implements Authenticatable
{
use \Illuminate\Auth\Authenticatable;
public function posts()
{
$this->hasMany('app\post');
}
}
postcontroller
namespace App\Http\Controllers;
use App\post;
use Illuminate\Http\Request;
class postcontroller extends Controller{
public function postCreatePost(Request $request){
$post = new post();
$post->body = $request['body'];
$request->user()->posts()->save($post);
return redirect()->route('dashboard');
}
}
Thank you in advance for any try from you to solve this query.
Make sure inside your user model you're returning the relationship.
class user extends Model implements Authenticatable
{
use \Illuminate\Auth\Authenticatable;
public function posts()
{
return $this->hasMany('app\post');
}
}
Your posted code doesn't have a return inside the posts function.
i think this should fix
add your table field to protected $fillable = [] array
user
namespace App;
use Illuminate\Database\Eloquent\Model;
class post extends Model
{
protected $fillable = ['body'];
public function user()
{
return $this->belongsTo('app\user');
}
}
post
namespace App;
use Illuminate\Contracts\Auth\Authenticatable;
use Illuminate\Database\Eloquent\Model;
class user extends Model implements Authenticatable
{
use \Illuminate\Auth\Authenticatable;
protected $fillable = ['username', 'field2', 'blabla'];
public function posts()
{
return $this->hasMany('app\post');
}
}
postcontroller
namespace App\Http\Controllers;
use App\post;
use Illuminate\Http\Request;
class postcontroller extends Controller{
public function postCreatePost(Request $request){
$post = new post(['body' => $request->body]);
$request->user->posts()->save($post);
return redirect()->route('dashboard');
}
}

Resources