In my application a User can make an InvestmentApplication. These models are related to each other like so:
/**
* Get this user's applications
*
* @return void
*/
public function applications()
{
return $this->hasMany(InvestmentApplication::class, 'user_id', 'id');
}
/**
* Get the user associated with the investment application.
*/
public function user()
{
return $this->belongsTo(User::class, 'user_id', 'id');
}
Here is the part in my ApplicationController responsible for making applications:
/**
* Store a new investment application for investing into the fund
*
* @param StoreFundApplication $request
*
* @return void
*/
public function store(StoreFundApplication $request)
{
$this->authorize('create', InvestmentApplication::class);
$data = $request->validated() + [
'type' => InvestmentApplication::TYPE_FUND,
'status' => 'Pending',
];
$application = auth()->user()->applications()->create($data);
event(new ApplicationSubmitted($application));
return redirect()->route('user.applications.show', [$application]);
}
This triggers ApplicationSubmitted which looks like this:
<?php
namespace App\Events;
use App\InvestmentApplication;
use Illuminate\Broadcasting\InteractsWithSockets;
use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Queue\SerializesModels;
class ApplicationSubmitted
{
use Dispatchable, InteractsWithSockets, SerializesModels;
/**
* The instance of InvestmentApplication
*
* @var InvestmentApplication
*/
public $investmentApplication;
/**
* Create a new event instance.
*
* @return void
*/
public function __construct(InvestmentApplication $investmentApplication)
{
$this->investmentApplication = $investmentApplication;
}
}
This event has attached listeners:
ApplicationSubmitted::class => [
LogApplicationSubmitted::class,
SendUserApplicationSubmittedNotification::class,
SendAdminApplicationSubmittedNotification::class,
GenerateInvestmentApplicationPDF::class,
],
In SendUserApplicationSubmittedNotification I use $investmentApplication->user->first_name but in my test the user returns null.
My test:
<?php
namespace Tests\Feature;
use App\Events\ApplicationSubmitted;
use App\InvestorDetail;
use App\InvestmentApplication;
use App\Mail\Admin\UserApplicationSubmitted;
use App\Notifications\InvestmentApplicationSubmitted;
use App\User;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Support\Facades\Notification;
use Illuminate\Support\Facades\Mail;
use Tests\TestCase;
class FundApplicationTest extends TestCase
{
use RefreshDatabase;
/** @test */
public function a_user_who_has_not_completed_their_investor_details_cannot_access_the_fund_application_form()
{
$user = factory(User::class)->create();
$this->actingAs($user->fresh())
->get(route('user.application.fund.create'))
->assertStatus(302);
}
/** @test */
public function a_user_who_has_completed_their_investor_details_can_access_the_fund_application_form()
{
$user = factory(User::class)->states('verified', 'certified', 'passive')->create();
$user->investorDetails->update(factory(InvestorDetail::class)->raw([
'user_id' => $user->id,
]));
$this->assertTrue($user->investorDetails->is_completed);
$this->actingAs($user)
->get(route('user.application.fund.create'))
->assertStatus(200);
}
/** @test */
public function a_user_who_has_completed_their_investor_details_can_submit_a_fund_application()
{
$this->expectsEvents(ApplicationSubmitted::class);
$user = factory(User::class)->states('verified', 'certified', 'passive')->create();
$user->investorDetails->update(factory(InvestorDetail::class)->raw([
'user_id' => $user->id,
]));
$this->assertTrue($user->investorDetails->is_completed);
$application = [
'type' => InvestmentApplication::TYPE_FUND,
'deal_id' => null,
'amount_pledged' => 10000,
'payment_method' => InvestmentApplication::PAYMENT_BANK_TRANSFER,
];
$this->actingAs($user)
->post(route('user.application.fund.store'), $application)
->assertStatus(302);
$this->assertDatabaseHas('investment_applications', [
'user_id' => $user->id,
'type' => $application['type'],
'deal_id' => null,
'amount_pledged' => $application['amount_pledged'],
'payment_method' => $application['payment_method'],
]);
}
/** @test */
public function submitting_a_fund_application_creates_an_activity_for_this_user()
{
Notification::fake();
$user = factory(User::class)->states('verified', 'certified', 'passive')->create();
$user->investorDetails->update(factory(InvestorDetail::class)->raw([
'user_id' => $user->id,
]));
$this->assertTrue($user->investorDetails->is_completed);
$application = [
'type' => InvestmentApplication::TYPE_FUND,
'deal_id' => null,
'amount_pledged' => 10000,
'payment_method' => InvestmentApplication::PAYMENT_BANK_TRANSFER,
];
$this->actingAs($user)
->post(route('user.application.fund.store'), $application)
->assertStatus(302);
$this->assertDatabaseHas('investment_applications', [
'user_id' => $user->id,
'type' => $application['type'],
'deal_id' => null,
'amount_pledged' => $application['amount_pledged'],
'payment_method' => $application['payment_method'],
]);
$this->assertDatabaseHas('user_activities', [
'user_id' => $user->id,
]);
}
/** @test */
public function submitting_a_fund_application_sends_a_notification_to_the_user()
{
Notification::fake();
$user = factory(User::class)->states('verified', 'certified', 'passive')->create();
$user->investorDetails->update(factory(InvestorDetail::class)->raw([
'user_id' => $user->id,
]));
$this->assertTrue($user->investorDetails->is_completed);
$application = [
'user_id' => $user->id,
'type' => InvestmentApplication::TYPE_FUND,
'deal_id' => null,
'amount_pledged' => 10000,
'payment_method' => InvestmentApplication::PAYMENT_BANK_TRANSFER,
];
$this->actingAs($user)
->post(route('user.application.fund.store'), $application)
->assertStatus(302);
$this->assertDatabaseHas('investment_applications', [
'user_id' => $user->id,
'type' => $application['type'],
'deal_id' => null,
'amount_pledged' => $application['amount_pledged'],
'payment_method' => $application['payment_method'],
]);
Notification::assertSentTo($user, InvestmentApplicationSubmitted::class);
}
/** @test */
public function submitting_a_fund_application_sends_a_notification_to_npi()
{
Mail::fake();
$user = factory(User::class)->states('verified', 'certified', 'passive')->create();
$user->investorDetails->update(factory(InvestorDetail::class)->raw([
'user_id' => $user->id,
]));
$this->assertTrue($user->investorDetails->is_completed);
$application = [
'user_id' => $user->id,
'type' => InvestmentApplication::TYPE_FUND,
'deal_id' => null,
'amount_pledged' => 10000,
'payment_method' => InvestmentApplication::PAYMENT_BANK_TRANSFER,
];
$this->actingAs($user)
->post(route('user.application.fund.store'), $application)
->assertStatus(302);
$this->assertDatabaseHas('investment_applications', [
'user_id' => $user->id,
'type' => $application['type'],
'deal_id' => null,
'amount_pledged' => $application['amount_pledged'],
'payment_method' => $application['payment_method'],
]);
Mail::assertSent(UserApplicationSubmitted::class, function ($mail) {
return $mail->hasTo('[email protected]');
});
}
}
If I use $this->withOutExceptionHandling() I can do the following in the notification itself:
<?php
namespace App\Notifications;
use Illuminate\Bus\Queueable;
use Illuminate\Notifications\Messages\MailMessage;
use Illuminate\Notifications\Notification;
use Illuminate\Contracts\Queue\ShouldQueue;
use App\User;
class InvestmentApplicationSubmitted extends Notification implements ShouldQueue
{
use Queueable;
/**
* The investment application submitted
*
* @var InvestmentApplication
*/
public $investmentApplication;
/**
* Create a new notification instance.
*
* @return void
*/
public function __construct($investmentApplication)
{
$this->investmentApplication = $investmentApplication;
}
/**
* Get the notification's delivery channels.
*
* @param mixed $notifiable
* @return array
*/
public function via($notifiable)
{
return ['mail'];
}
/**
* Get the mail representation of the notification.
*
* @param mixed $notifiable
* @return \Illuminate\Notifications\Messages\MailMessage
*/
public function toMail($notifiable)
{
dd($this->investmentApplication->user);
dd(User::find($this->investmentApplication->user_id));
return (new MailMessage)
->subject("{$notifiable->first_name}, your investment application was submitted")
->markdown('emails.user.investment-application-submitted', [
'application' => $this->investmentApplication,
]);
}
}
The line - dd($this->investmentApplication->user); returns null but the line underneath returns a valid User object.
I am unsure why the investmentApplication thinks it's related user is null, even though I'm posting the store route that uses the relationship to create the application in the first place.