Laravel - Pass custom data to email view - laravel

Following on from a previous question, I have an email controller set up to correctly pass user data to the view. I am now trying to modify it so I can pass some custom data instead. My controller looks like this...
namespace App\Mail;
use Illuminate\Bus\Queueable;
use Illuminate\Mail\Mailable;
use Illuminate\Queue\SerializesModels;
use Illuminate\Contracts\Queue\ShouldQueue;
class Welcome extends Mailable
{
use Queueable, SerializesModels;
public $email_data;
public function __construct($email_data)
{
$this->email_data = $email_data;
}
public function build()
{
return $this->view('emails.welcome')->with(['email_data' => $this->email_data]);
}
}
And I am sending the email like this...
/* Create Data Array For Email */
$email_data = array(
'first_name'=>'John',
'last_name'=>'Doe',
'email'=>'john#doe.com',
'password'=>'temp',
);
/* Send Email */
Mail::to($user->email)->send(new Welcome($email_data));
Is this correct? When I try using this method it does not seem to be passing the data through to the email template. How can I then access this data within the view?

Have you tried this way ?
namespace App\Mail;
use Illuminate\Bus\Queueable;
use Illuminate\Mail\Mailable;
use Illuminate\Queue\SerializesModels;
use Illuminate\Contracts\Queue\ShouldQueue;
class Welcome extends Mailable
{
use Queueable, SerializesModels;
public $data;
public function __construct($data)
{
$this->data = $data;
}
public function build()
{
return $this->view('emails.welcome')->with('data', $this->data);
}
}
and then in your controller from where you are creating your array of data,
$data = [
'first_name'=>'John',
'last_name'=>'Doe',
'email'=>'john#doe.com',
'password'=>'temp'
];
\Mail::to($user->email)->send(new Welcome($data));
Please make sure that you add
use Mail;
use App\Mail\Welcome;
in your controller.
You can access the data in your view like this
{{ $data['first_name'] }}
{{ $data['last_name'] }}
{{ $data['email'] }}
{{ $data['password'] }}
OR
You can also try Markdown mails for this

You don't need this part ->with(['email_data' => $this->email_data]) because if the property is public you can access it in the view.
And you are passing an array so you have to access the values like this :
$email_data['email'] // ...

There are two ways to pass data through the view. First, any public defenses defined in the mailable class pass automatically through the view.
<?php
namespace App\Mail;
use Illuminate\Bus\Queueable;
use Illuminate\Mail\Mailable;
use Illuminate\Queue\SerializesModels;
class Welcome extends Mailable
{
use Queueable, SerializesModels;
public $firstName;
public $lastName;
public $email;
public $password;
/**
* Create a new message instance.
*
* #return void
*/
public function __construct($firstName, $lastName, $email, $password)
{
$this->firstName = $firstName;
$this->lastName = $lastName;
$this->email = $email;
$this->password = $password;
}
/**
* Build the message.
*
* #return $this
*/
public function build()
{
return $this->view('emails.orders');
}
}
In Blade view
<div>
First Name: {{ $firstName }}
Last Name: {{ $lastName }}
Email: {{ $email }}
Password: {{ $password }}
</div>
For variables with protected and private properties, it is possible to pass data through a view with the with method
namespace App\Mail;
use Illuminate\Bus\Queueable;
use Illuminate\Mail\Mailable;
use Illuminate\Queue\SerializesModels;
class Welcome extends Mailable
{
use Queueable, SerializesModels;
protected $firstName;
protected $lastName;
protected $email;
protected $password;
/**
* Create a new message instance.
*
* #return void
*/
public function __construct($firstName, $lastName, $email, $password)
{
$this->firstName = $firstName;
$this->lastName = $lastName;
$this->email = $email;
$this->password = $password;
}
/**
* Build the message.
*
* #return $this
*/
public function build()
{
return $this->view('emails.orders')->with([
'first_name'=> $this->firstName,
......
]);
}
}
In Blade view
<div>
First Name: {{ $firstName }}
Last Name: {{ $lastName }}
Email: {{ $email }}
Password: {{ $password }}
</div>

Related

How to passing variable from controller to view queued mail?

I'm trying to pass variable $array from controller to mail blade, but whenever I run queue:listen. It always say failed.
Bellow is my code
In controller I have a variable named $array, I've putting it in dispatch
Controller
$array["view"] = "layouts.mail.order";
$array["subject"] = "Order Created";
$array["from"] = env('MAIL_USERNAME');
$array["data"] = "aaaaaaaaa";
$array["email"] = Auth::user()->email;
OrderEmailJob::dispatch($array);
OrderEmailJob
<?php
namespace App\Jobs;
use App\Mail\OrderMail;
use Illuminate\Bus\Queueable;
use Illuminate\Support\Facades\Mail;
use Illuminate\Queue\SerializesModels;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
class OrderEmailJob implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
public $array;
/**
* Create a new job instance.
*
* #return void
*/
public function __construct($array)
{
$this->array = $array;
}
/**
* Execute the job.
*
* #return void
*/
public function handle()
{
$email = new OrderMail();
Mail::to($this->array['email'])->send($array);
}
}
and this is code for the mailable
<?php
namespace App\Mail;
use Illuminate\Bus\Queueable;
use Illuminate\Mail\Mailable;
use Illuminate\Queue\SerializesModels;
class OrderMail extends Mailable
{
use Queueable, SerializesModels;
public $array;
/**
* Create a new message instance.
*
* #return void
*/
public function __construct($array)
{
$this->array = $array;
}
/**
* Build the message.
*
* #return $this
*/
public function build()
{
return $this->view($this->array['view'])
->from($this->array['from'], env('MAIL_FROM_NAME'))
->subject($this->array['subject'])
->with([
'data' => $this->array['data'],
]);
}
}
The result I want is I can use variable $array in view for my mail, because I've to printed out data from $array variable
Sorry about my english, thanks
try like this :
public $mailData;
public function __construct($mailData)
{
$this->mailData = $mailData;
}
public function build()
{
// Array for Blade
$input = array(
'action' => $this->mailData['action'],
'object' => $this->mailData['object'],
);
return $this->view('emails.notification')
->with([
'inputs' => $input,
]);
}
I'm not sure, the answer correct. But you can change the name variable $array to $data and check again. Maybe your variable name is a special case like array keyword

Laravel PHPUnit gets "ErrorException: Illegal string offset 'address' " when testnig Maillable hasFrom(...) method

Here's my Mailable class:
<?php
namespace App\Mail;
use Illuminate\Bus\Queueable;
use Illuminate\Mail\Mailable;
use Illuminate\Queue\SerializesModels;
use Illuminate\Contracts\Queue\ShouldQueue;
class OrderConfirmation extends Mailable
{
use Queueable, SerializesModels;
public $message;
public $subject;
public $from;
/**
* Create a new message instance.
*
* #return void
*/
public function __construct($message, $subject, $from)
{
$this->message = $message;
$this->subject = $subject;
$this->from = $from;
}
/**
* Build the message.
*
* #return $this
*/
public function build()
{
return $this->from($this->from)
->subject($this->subject)
->view('emails.orders.confirmation');
}
}
I'm trying to check that mail has certain From address like this:
Mail::fake();
$customer = 'test#test.com';
$from = 'from#test.com';
Mail::to($customer)->queue(new OrderConfirmation('Some Message', 'Some Subject', $from));
Mail::assertQueued(OrderConfirmation::class, function ($mail) {
return $mail->hasFrom('from#test.com');
});
but it gets "ErrorException: Illegal string offset 'address' "
/var/www/vendor/laravel/framework/src/Illuminate/Mail/Mailable.php:597
Laravel 5.6
Is it a bug or am I doing something wrong?
The reason you're getting this issue is because you're overriding the $from property in the Mailable class.
You could remove the $from property you have set up in the class and call the from() method from the constructor:
public $message;
public function __construct($message, $subject, $from)
{
$this->message = $message;
$this->subject = $subject;
$this->from($from);
}
public function build()
{
return $this->view('emails.orders.confirmation');
}
Alternatively, you could rename the $from property to something like $fromAddress.
NB The same was happening with subject as well but since the subject() method is simply there to assign a value to the subject property on the class is wasn't actually causing an issue.

Laravel Mail view not returning passed data

I am trying to send email using Laravel default Mail facade:-
Mail::to($user->email)->send(New NotifyUserExpiring($diff,$Sub->user));
In Mail\NotifyUserExpiring :-
<?php
namespace App\Mail;
use Illuminate\Bus\Queueable;
use Illuminate\Mail\Mailable;
use Illuminate\Queue\SerializesModels;
use Illuminate\Contracts\Queue\ShouldQueue;
class NotifyUserExpiring extends Mailable
{
use Queueable, SerializesModels;
/**
* Create a new message instance.
*
* #return void
*/
protected $user;
protected $diff;
public function __construct($diff,$user)
{
$this->user = $user;
$this->diff = $diff;
}
/**
* Build the message.
*
* #return $this
*/
public function build()
{
return $this->view('web.mail.NotifyUserExpiring')->with('user',$this->user)->with('diff',$this->diff);
}
}
And in web.mail.NotifyUserExpiring View file i am using the blade way of printing variable :-
Hello {{ $user->first_name }}
Message Here
When i check my mail inbox , i am reciving email with exact {{ $user->first_name }}
Hello {{ $user->first_name }}
Message Here
I am expecting that when i insert {{ $user->first_name }} in mail view file , it should return user first name.
<div>
Hello {{ $user->first_name }}
Message body test
</div>
Make sure your mail view file name is suffixed as .blade.php so that it goes through the Blade rendering engine.
The with() method you can pass as an array, see the documentation:
return $this->view('web.mail.NotifyUserExpiring')->with([
'user',$this->user,
'diff',$this->diff
]);

Passing a collection to a mailable| Laravel 5.4

I am trying to get a mailable setup which has a collection of files. Mail controller looks like:
<?php
namespace App\Mail;
use App\Document;
use App\Order;
use Illuminate\Bus\Queueable;
use Illuminate\Mail\Mailable;
use Illuminate\Queue\SerializesModels;
use Illuminate\Contracts\Queue\ShouldQueue;
use App\User;
class OrderComplete extends Mailable
{
use Queueable, SerializesModels;
public $user;
public $order;
public $documents;
/**
* Create a new message instance.
*
* #return void
*/
public function __construct(User $user, Order $order, Document $document)
{
//
$this->user = $user;
$this->order = $order;
$this->documents = $document;
}
/**
* Build the message.
*
* #return $this
*/
public function build()
{
return $this->markdown('emails.customers.complete');
}
}
Controller calling the mailable looks like;
use App\Document;
// other code...
$documents = Document::where('order_id', $orderId)
->where('product', 'like', '%response')
->get();
Mail::to($customer)
->send(new OrderComplete($customer, $order, $documents));
But I keep getting this error:
Type error: Argument 3 passed to App\Mail\OrderComplete::__construct() must be an instance of App\Document, instance of Illuminate\Database\Eloquent\Collection given, called in /Users/ap/sites/propair/app/Http/Controllers/OrderController.php on line 253
I'm pretty confused as I thought this should work?
thanks
This function declaration:
public function __construct(..., Document $document)
means PHP will enforce that $document is an instance of App\Document.
If you want to pass it a collection instead, you'll need to do:
public function __construct(..., \Illuminate\Database\Eloquent\Collection $documents)

Undefined variable: currentUser

I was following the laracasts video for creating follow option but on clicking on the username it is showing the above error and I don't know where to define this variable. Followscontroller
<?php
namespace App\Http\Controllers;
use Redirect;
use App\User;
use Laracasts\Commander\CommanderTrait;
use App\FollowUserCommand;
use Sentinel;
use Illuminate\Support\Facades\Input;
use App\Http\Requests;
use App\Http\Controllers\Controller;
class FollowsController extends Controller
{
use CommanderTrait;
/**
* Follow a User
*
* #param \Illuminate\Http\Request $request
* #return \Illuminate\Http\Response
*/
public function store()
{
$input = array_add(Input::all(), 'user_id', Sentinel::getuser()->id);
$this->execute(FollowUserCommand::class, $input);
return Redirect::back();
}
/**
* Unfollow a User
*
* #param int $id
* #return \Illuminate\Http\Response
*/
public function destroy($id)
{
//
}
}
FollowUserCommand
<?php namespace App;
use App\User;
class FollowUserCommand {
public $user_id;
public $userIdToFollow;
function __construct($user_id, $userIdToFollow)
{
$this->user_id = $user_id;
$this->userIdToFollow = $userIdToFollow;
}
}
FollowUserCommandHandler
<?php namespace App;
use Laracasts\Commander\CommandHandler;
class FollowUserCommandHandler implements CommandHandler {
protected $userRepo;
function __construct(UserRepository $userRepo)
{
$this->userRepo = $userRepo;
}
public function handle($command)
{
$user = $this->userRepo->findById($command->user_id);
$this->userRepo->follow($command->userIdToFollow, $user);
return $user;
}
}
UserRepository
<?php namespace App;
use App\User;
class UserRepository {
public function save(User $user)
{
return $user->save();
}
public function getPaginated($howMany = 4)
{
return User::orderBy('first_name', 'asc')->paginate($howMany);
}
public function findByUsername($username)
{
return User::with(['feeds' => function($query)
{
$query->latest();
}
])->whereUsername($username)->first();
}
public function findById($id)
{
return User::findOrFail($id);
}
public function follow($userIdToFollow, User $user)
{
return $user->follows()->attach($userIdToFollow);
}
}
User.php
<?php namespace App;
use Cartalyst\Sentinel\Users\EloquentUser;
use Illuminate\Database\Eloquent\SoftDeletes;
class User extends EloquentUser {
/**
* The database table used by the model.
*
* #var string
*/
protected $table = 'users';
/**
* The attributes to be fillable from the model.
*
* A dirty hack to allow fields to be fillable by calling empty fillable array
*
* #var array
*/
protected $fillable = [];
protected $guarded = ['id'];
/**
* The attributes excluded from the model's JSON form.
*
* #var array
*/
protected $hidden = ['password', 'remember_token'];
/**
* To allow soft deletes
*/
use SoftDeletes;
protected $dates = ['deleted_at'];
public function feeds()
{
return $this->hasMany('App\Feed');
}
public function comment()
{
return $this->hasMany('App\Comment');
}
// This function allows us to get a list of users following us
public function follows()
{
return $this->belongsToMany(self::class, 'follows', 'follower_id', 'followed_id')->withTimestamps();
}
// Get all users we are following
public function following()
{
return $this->belongsToMany('User', 'followers', 'user_id', 'follow_id')->withTimestamps();
}
// if current user follows another user
public function isFollowedBy(User $otherUser)
{
$idsWhoOtherUserFollows = $otherUser->follows()->lists('followed_id');
return in_array($this->id, $idsWhoOtherUserFollows) ;
}
}
form.blade.php
#if($user->isFollowedBy($currentUser))
<p>You are following {{ $user->username }}<p>
#else
{!! Form::open(['route' => 'follows_path']) !!}
{!! Form::hidden('userIdToFollow', $user->id) !!}
<button type="submit" class="btn btn-primary">Follow {{ $user->username }} </button>
{!! Form::close() !!}
#endif
Assuming the tutorial implements the Auth class, you can get the current user by changing #if($user->isFollowedBy($currentUser)) to #if($user->isFollowedBy(\Illuminate\Support\Facades\Auth::user())). It is otherwise very difficult to read through your code, but kudos to you for trying to be thorough.
You obviously don't want to use Auth::user() in this way. Trying using it as Auth::user() without the full namespace, but otherwise add the namespace as use Illuminate\Support\Facades\Auth; in the controller handling that view.

Resources