Call to a member function pro_events() on null - laravel

Hello I'm trying to fix this issue where the error
Call to a member function pro_events() on null
would not happen all the time. I'm not sure what's causing this.
Any idea how to prevent this error in case it would appear again? We just saw this error in the log but can't duplicate the issue. Thanks!
Organizer.php model
class Organiser extends MyBaseModel
{
protected $rules = [
'org_name' => ['required', 'unique:organisers,name'],
'email' => ['required', 'email', 'unique:organisers'],
'organiser_logo' => ['mimes:jpeg,jpg,png', 'max:10000'],
'terms_agreed' => ['required'],
'org_tags' => ['required'],
];
protected $messages = [
'org_name.required' => 'You must at least give a name for the event organiser.',
'org_name.unique' => 'Your desired organisation name is already taken.',
'organiser_logo.max' => 'Please upload an image smaller than 10Mb',
'organiser_logo.size' => 'Please upload an image smaller than 10Mb',
'organiser_logo.mimes' => 'Please select a valid image type (jpeg, jpg, png)',
];
public function pro_events() {
return $this->hasMany(\App\Models\ProEvent::class)->orderBy('event_date', 'asc');
}
SomeController.php
public function showPackageHome($organiser_id, $event_dummy = null, $event_id = null, $the_country = null, $package_type_id = null, $package_category_id = null)
{
date_default_timezone_set('Europe/London');
$now = Carbon::now();
$cacheKey = md5(vsprintf('%s.%s', [
$organiser_id,
'organiser_cache'
]));
$organiser = Cache::remember($cacheKey, 10, function() use ($organiser_id) {
return Organiser::find($organiser_id);
});
$cacheKey = md5(vsprintf('%s', [
'event_list_cache'
]));
$events = Cache::remember($cacheKey, 1, function() use ($organiser, $now) {
return $organiser->pro_events()
->where("event_status", "live")
->whereDate('event_date', '>=', $now->format("Y-m-d"))
->orderBy('event_date', 'asc')
->get();
});
ProEvent.php model
class ProEvent extends MyBaseModel
{
use SoftDeletes;
protected $table = 'pro_events';

You must go up in the call stack to find where the organizer_id comes from. A possible reason would be that the admin/loggedIn person may change the route manually and try to load an organizer that doesn't exist.
If you have a route like /organizer/{organizer_id}, then you must make sure that the provided ID actually exists in db. One way to do it would be to use findOrFail instead of find and to catch the thrown exception in case the organizer doesn't exist.
public function showPackageHome($organiser_id, $event_dummy = null, $event_id = null, $the_country = null, $package_type_id = null, $package_category_id = null)
{
date_default_timezone_set('Europe/London');
$now = Carbon::now();
$cacheKey = md5(vsprintf('%s.%s', [
$organiser_id,
'organiser_cache'
]));
$organiser = Cache::remember($cacheKey, 10, function() use ($organiser_id) {
return Organiser::findOrFail($organiser_id);
});
$cacheKey = md5(vsprintf('%s', [
'event_list_cache'
]));
$events = Cache::remember($cacheKey, 1, function() use ($organiser, $now) {
return $organiser->pro_events()
->where("event_status", "live")
->whereDate('event_date', '>=', $now->format("Y-m-d"))
->orderBy('event_date', 'asc')
->get();
});
}
In your controller method you can actually catch the exception and display something to the user:
public function yourControllerMethod(Illuminate\Http\Request $request)
{
// something more here
try {
$events = $this->showPackageHome($request->get('organizer_id'), /* the other parameters */);
return $this->view(..., ['events' => $events]);
} catch (Illuminate\Database\Eloquent\ModelNotFoundException $ex) {
// The organizer couldn't be found
return redirect()->back()->withErrors(['organizer-not-found' => 'The organizer could not be found'])
}
}

i think it's because the instance of Organizer where you called pro_events() function was null.

Related

Observer not running when creating in database

Hello I have this method that mass create student sections
Enrollment controller method this code works fine but it doesn't get in my studentSectionObserver. Although it's getting saved one by one with for loop.
public function setStudentsSection(Request $request)
{
$enrollments = Enrollment::whereIn('student_id', $request->students)->where('session_id', $request->session_id)->get();
$program_section = ProgramSection::withCount('students')->find($request->program_section_id);
if(($program_section->students_count + count($enrollments)) <= $program_section->max_students) {
$new_student_sections = array();
foreach($enrollments as $enrollment) {
$data = [
'student_id' => $enrollment->student_id,
'enrollment_id' => $enrollment->id,
'section_id' => $request->program_section_id,
'created_at' => Carbon::now()
];
array_push($new_student_sections, $data);
}
return StudentSection::insert($new_student_sections);
}
return response()->json(['errors' => ['message' => 'Selected Section is full.']], 405);
}
Then i output this activity with studentSectionObserver and added log::info but it doesn't log anything
public function created(StudentSection $student_section)
{
Log::info('test');
$student = $student_section->student()->get()->first();
$section = $student_section->section()->get()->first();
Logger::createLog("Assigned " . $student->first_name . " " . $student->last_name . " '" . $section->section->name . "'");
}
I know this observer gets triggered cause i tested it with this method whenever i add section the studentSectionObserver triggers Logger.
public function enrollStudent(EnrollmentRequest $request)
{
$check_if_exist = Enrollment::where('student_id', $request->student_id)->where('session_id', $request->session_id)->first();
if (!$check_if_exist) {
$program_section = ProgramSection::withCount('students')->find($request->section_id);
if($program_section) {
if($program_section->students_count < $program_section->max_students) {
$enrollment = Enrollment::create($request->all());
$section_data = ['student_id' => $request->student_id, 'section_id' => $request->section_id, 'enrollment_id' => $enrollment->id];
$section = StudentSection::create($section_data);
return response()->json($enrollment, 200);
}
return response()->json(['errors' => ['message' => 'Selected Section is full.']], 405);
}
$enrollment = Enrollment::create($request->all());
return response()->json($enrollment, 200);
}
return response()->json(['errors' => ['message' => 'Student is already enrolled in this session.']], 405);
}
Any help would be greatly appreciated.
As you have figured out the answer on your own.
The reason for using create method is because it triggers the event on the model. Same goes for update method.
Following is the update method under the hood:
/**
* Update the model in the database.
*
* #param array $attributes
* #param array $options
* #return bool
*/
public function update(array $attributes = [], array $options = [])
{
if (! $this->exists) {
return false;
}
return $this->fill($attributes)->save($options);
}
And the save method has these lines of code:
if ($this->fireModelEvent('saving') === false) {
return false;
}
Similarly, create method works. That's why insert doesn't trigger the event on model and you had to use create method.
Turns out i just need to use create method.
public function setStudentsSection(Request $request)
{
$enrollments = Enrollment::whereIn('student_id', $request->students)->where('session_id', $request->session_id)->get();
$program_section = ProgramSection::withCount('students')->find($request->program_section_id);
if(($program_section->students_count + count($enrollments)) <= $program_section->max_students) {
foreach($enrollments as $enrollment) {
$response = StudentSection::create([
'student_id' => $enrollment->student_id,
'enrollment_id' => $enrollment->id,
'section_id' => $request->program_section_id,
'created_at' => Carbon::now()
]);
return $response;
}
}
return response()->json(['errors' => ['message' => 'Selected Section is full.']], 405);
}
Laravel observer doesn't work on bulk objects, it only works with single object.
So when you use create() function it will trigger the observer.

Is there any efficient method on how to get id of object to my create method

I am creating a web module, and want to get ID of table licensing level two parse into my create method. Hence each ID of level will have a task and the ID need to be stored within my licensing table as a foreign key which reflects ID in Level Two table. How could I solve this, anyone can give me a good suggestion or way on doing this
public function add_show($id)
{
$level = PreLicensingLevelTwo::where('id', $id)->first();
$level->prelicensingtask = PreLicensingTask::where('pre_licensing_level_two_id', $level->id)->with('staff', 'statusdesc', 'prelicensingtaskstaff')->get();
return view('staff.regulatory.statutory.approval.display',compact('level'));
}
public function create()
{
$staff = Staff::pluck('staff_name');
$status = PreLicensingStatus::pluck('status_description', 'id');
return view('staff.regulatory.statutory.approval.create', compact('staff','status'));
}
public function show($id)
{
$one = PreLicensingLevelOne::where('pre_licensing_main_id', $id)->get();
foreach ($one as $key => $license)
{
$license->two = PreLicensingLevelTwo::where('pre_licensing_level_one_id', $license->id)->get();
}
$rendered = view('staff.regulatory.statutory.approval.show')->with('one', $one)->render();
return response()->json(array('status' => 1, 'tableData' => $rendered));
}
With help from my working collegue this is how i able to solve the question i asked
public function store(Request $request)
{
$this->validate($request, [
'task_title' => 'required',
'task_description' => 'required',
'task_due_date' => 'required',
]);
$leveltwo = PreLicensingLevelTwo::find($request->input('pre_licensing_level_two_id'));
$prelicensingtask = new PreLicensingTask;
$prelicensingtask->task_title =$request->input('task_title');
$prelicensingtask->task_description =$request->input('task_description');
$prelicensingtask->task_due_date =$request->input('task_due_date');
$prelicensingtask->created_by_staff_id = Auth::user()->ref_user->staff_id;
$prelicensingtask->status = $request->input('status');
$prelicensingtask->pre_licensing_level_two_id = $leveltwo->id;
$prelicensingtask->pre_licensing_level_one_id = $leveltwo->pre_licensing_level_one_id;
$prelicensingtask->pre_licensing_main_id = $leveltwo->pre_licensing_main_id;
$prelicensingtask->centre_id = Auth::user()->ref_user->centre_id;
$prelicensingtask->save();
return redirect()->back();
}

Send a push Notifications to users who have changed the password 30 days before

This is my case:
In my database, I have a table users. The rows in the table also have a field password_changed_at. Now I would like to select all users where the password_changed_at field is older than 30 days and send a push notification But I'm stuck on how to do this with Carbon. My code now looks like this:
public function passwordExpired() {
$dateTime = new DateTime();
$currentDateTime = $dateTime->format('Y-m-d H:i');
$users = User::where('password_changed_at', $currentDateTime)->get();
// $user = $request->user();
foreach ($users as $user) {
$password_changed_at = new Carbon(($user->password_changed_at) ? $user->password_changed_at : "");
if (Carbon::now()->diffInDays($password_changed_at) >= 30) {
foreach ($password_changed_at as $password)
{
// $user = $user->id;
$user->notify(new ReminderPassword($user));
$push = new PushNotification('apn');
$push->setMessage([
'aps' => [
'alert' => 'Reminder for your password "'.$user->email.'"',
'sound' => 'default',
'badge' => $user->unreadNotifications->count()
],
'extraPayLoad' => [
'custom' => 'My custom data',
]
]);
$push->setDevicesToken($user->deviceToken);
$push->send();
$feedback = $push->getFeedback();
}
Looks like diffInDays works the other way round (i.e. diffing an older day returns a negative value). See: https://carbon.nesbot.com/docs/#api-difference
So you can change your code like this:
public function passwordExpired() {
$dateTime = new DateTime();
$currentDateTime = $dateTime->format('Y-m-d H:i');
$users = User::where('password_changed_at', $currentDateTime)->get();
foreach ($users as $user) {
$password_changed_at = new Carbon(
($user->password_changed_at) ? $user->password_changed_at : ""
);
// DiffIndays works the other way round:
if ($password_changed_at->diffInDays(Carbon::now()) >= 30) {
$user->notify(new ReminderPassword($user));
$push = new PushNotification('apn');
$push->setMessage([
'aps' => [
'alert' => 'Reminder for your password "' . $user->email . '"',
'sound' => 'default', 'badge' => $user->unreadNotifications->count()
],
'extraPayLoad' => ['custom' => 'My custom data', ]
]);
$push->setDevicesToken($user->deviceToken);
$push->send();
$feedback = $push->getFeedback();
}
}
}
With $users = User::where('password_changed_at', $currentDateTime)->get(); you selecting all users who has changed their date today, but you want select all users which has changed their password +30 days before.
So you can just select these with using a query scope. In your Users class add this:
class Users extends Authenticatable
{
// ...
public function scopePasswordOlderThan30Days(Builder $builder)
{
$expirationDate = Carbon::now()->subDays(30);
return $builder->where('password_changed_at', '<=', $expirationDate);
}
}
In your function use it like:
public function passwordExpired()
{
$users = User::passwordOlderThan30Days()->get();
$users->each(function(User $user) {
// notify the user
})
}

Figure what fields `save()` acted on if any (detecting changes)

Doing ->save() and ->update() only updates when changes made, I think, is this true?
Here's the relevant part of code in Illuminate\Database\Eloquent\Model#performUpdate:
protected function performUpdate(Builder $query, array $options = [])
{
$dirty = $this->getDirty();
if (count($dirty) > 0)
{
// runs update query
}
return true;
}
I typically update like this:
public function update(Requests\UpdatePetRequest $request, Pet $pet)
{
$pet->update($request->all());
return $pet;
}
I want to figure from ->save and from ->update if what field names were updated? Along with what was the old value and the new value.
I currently manually do this like this:
public function update(Requests\UpdatePetRequest $request, Pet $pet)
{
$changes = [];
if ($request->exists('name') && $request->name != $pet->name) {
$changes['name'] = array([
'old' => $pet->name,
'new' => $request->name
]);
}
if ($request->exists('avatar') && $request->avatar != $pet->avatar) {
$changes['avatar'] = array([
'old' => $pet->avatar,
'new' => $request->avatar
]);
}
if (!count($changes)) {
return response()->json(['error'=>'No properties changed'], 422);
}
$pet->update($request->all());
$body = json_encode($changes);
$message = new Message(['body' => $body, 'kind' => 'PET_UPDATE']);
}
Is there an automated way to do this?
You can't do that with update(), but you can use getDirty() before save():
$model = Model::find($id);
$model->fill($request->all());
$cahnges = $model->getDirty();
$model->save();
getDirty() will return you an array with changed columns only, for example:
['name' => 'New Name', 'address' => 'New Street, 12']

Symfony3 error changing DateTime on entity with Ajax

I want to change the date of a doctrine entity but the change is not saved.
With ajax a call this function:
public function relancerTicketAction(Request $request, $id)
{
if (!$this->get('session')->get('compte'))
return $this->redirect($this->generateUrl('accueil'));
$isAjax = $request->isXMLHttpRequest();
if ($isAjax)
{
$ticket = $this->getDoctrine()->getManager()->getRepository('CommonBundle:Ticket')->find($id);
$ticket->setDateButoire($ticket->getDateButoire()->modify('+7 day'));
$this->getDoctrine()->getManager()->flush();
$response = array("code" => 100, "success" => true, 'date' => $ticket->getDateButoire()->format('d-m-Y'));
return new Response(json_encode($response));
}
$response = array("code" => 0, "success" => false);
return new Response(json_encode($response));
}
When I alert the result I get the right new value, but after reload there is no change saved.
This function called in the same conditions works:
public function traiterTicketAction(Request $request, $id)
{
if (!$this->get('session')->get('compte'))
return $this->redirect($this->generateUrl('accueil'));
$isAjax = $request->isXMLHttpRequest();
if ($isAjax)
{
$compte = $this->getDoctrine()->getManager()->getRepository('CommonBundle:Compte')->find($this->get('session')->get('compte')->getId());
$ticket = $this->getDoctrine()->getManager()->getRepository('CommonBundle:Ticket')->find($id);
$ticket->addDestinataire($compte);
$this->getDoctrine()->getManager()->flush();
$response = array("code" => 100, "success" => true);
return new Response(json_encode($response));
}
$response = array("code" => 0, "success" => false);
return new Response(json_encode($response));
}
see the docs
When calling EntityManager#flush() Doctrine computes the changesets of
all the currently managed entities and saves the differences to the
database. In case of object properties (#Column(type=”datetime”) or
#Column(type=”object”)) these comparisons are always made BY
REFERENCE. That means the following change will NOT be saved into the
database:
/** #Entity */
class Article
{
/** #Column(type="datetime") */
private $updated;
public function setUpdated()
{
// will NOT be saved in the database
$this->updated->modify("now");
}
}
So, in your case I suggest to clone dateButoire, like this
$ticket = $this->getDoctrine()->getManager()->getRepository('CommonBundle:Ticket')->find($id);
$newDateButoire = clone $ticket->getDateButoire();
$ticket->setDateButoire($newDateButoire->modify('+7 day'));
$this->getDoctrine()->getManager()->flush();

Resources