'Undefined variable' in Laravel 8 blade template on sending email - php

In my Laravel 8 project I try to send HTML e-mail, but get Undefined variable error.
I have this code in my controller:
// here the $client has a model value
Mail::to($client)->send(new ClientCreated($client));
In my app/Mail/ClientCreated.php file:
<?php
namespace App\Mail;
use App\Client;
use Illuminate\Bus\Queueable;
use Illuminate\Mail\Mailable;
use Illuminate\Queue\SerializesModels;
class ClientCreated extends Mailable
{
use Queueable, SerializesModels;
private $client;
/**
* Create a new message instance.
*
* #return void
*/
public function __construct(Client $client)
{
$this->client = $client;
}
/**
* Build the message.
*
* #return $this
*/
public function build()
{
// here the $this->client has a model value
return $this->view('emails.client.created');
}
}
Finally in my resources/views/emails/client/created.blade.php I have this code:
<p>Dear{{ $client->name }}!</p>
And I got this error message:
Undefined variable: client (View: /home/vagrant/Code/myproject/laravel/resources/views/emails/client/created.blade.php)
I read the docs and search on the Stackoverflow, but not found any help.
Any idea what I made wrong?

If you passed the variable to the view properly, but it still does not work, try to restart the queue in the console:
php artisan queue:restart

You should make $client public not private:
public $client;
"There are two ways you may make data available to your view. First, any public property defined on your mailable class will automatically be made available to the view"
Laravel 8.x Docs - Mail - Writing Mailables - View Data - Via Public Properties
The other method would be calling with:
$this->view(...)->with('client', $this->client);
"If you would like to customize the format of your email's data before it is sent to the template, you may manually pass your data to the view via the with method."
Laravel 8.x Docs - Mail - Writing Mailables - View Data - Via the with Method
If you do not want to change $client to public then use the second method.

You should make $client public
public $client;
Once the data has been set to a public property, it will automatically be available in your view, so you may access it like you would access any other data in your Blade templates.
https://laravel.com/docs/8.x/mail#view-data

Related

Laravel Mailer queue with Redis showing error "The script tried to execute a method or access a property of an incomplete object."

This is the complete error.
Illuminate\Mail\SendQueuedMailable::handle(): The script tried to
execute a method or access a property of an incomplete object. Please
ensure that the class definition "Security\Mail\WelcomeMail" of the
object you are trying to operate on was loaded before unserialize()
gets called or provide an autoloader to load the class definition in
/var/www/html/vendor/laravel/framework/src/Illuminate/Mail/SendQueuedMailable.php
We are using Laravel 5.5. And executing the following code
Mail::to($customer)->queue(new WelcomeMail($customer));
The mailer is the default mailer that comes with laravel, but we're queueing jobs to redis. Customer is a User object. The WelcomeMail is the following
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Mail\Mailable;
use Illuminate\Queue\SerializesModels;
class WelcomeMail extends Mailable implements ShouldQueue
{
use Queueable, SerializesModels;
public $user;
/**
* Create a new message instance.
*
* #return void
*/
public function __construct($user)
{
$this->user = $user;
}
/**
* Build the message.
*
* #return $this
*/
public function build()
{
return $this->view('security::emails.welcome');
}
}
I figured out what was my problem. It was more than one server (localhost, staging etc... ) had a queue listener on the same Redis instance.

How can I send Email in Laravel command instead of controller

I'm working on a project using Laravel where I want to be able to send an email when it is scheduled to send.
So far I've only found solutions to send a mail through a Route but I want to be able to send the mail when cron activates my self made command. I've already made a view of the mail that should be sent and made a page sendMail with php artisan make:mail sendMail that returns the mail view.
sendMail.php
<?php
namespace App\Mail;
use Illuminate\Support\Facades\DB;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Mail\Mailable;
use Illuminate\Queue\SerializesModels;
class sendMail extends Mailable
{
use Queueable, SerializesModels;
/**
* Create a new message instance.
*
* #return void
*/
public function __construct()
{
$winnersposts = DB::select('select post_id from winners group by post_id');
$posts = DB::select('select * from posts ');
$this->winnerposts =$winnersposts;
$this->posts=$posts;
}
/**
* Build the message.
*
* #return $this
*/
public function build()
{
return $this ->from('ivanrompa#gmail.com')
->view('emails.template');
}
}
mailAdmin.php
public function handle()
{
}
My command handle is still empty but I previously tried to implement to logic from my controller above in my command but it didn't work.
Am I writing the wrong code and is that the reason it just doesn't work or should I approach it in a different way? It is maybe good to know that I am still learning Laravel and I have never sent an email before through code. Any tips or solutions are welcome.
Assuming you have set your email configuration correctly.
Add this in your mailAdmin.php
use Mail;
use App\Mail\sendMail
public function handle()
{
Mail::to('recipient#gmail.com')->send(new sendMail);
}
Then run the command

Laravel 5.5 email setup using Mailgun and Bogardo

I am attempting to setup automated email notification in my Laravel 5.5 app using Mailgun. I have the Mailgun SDK installed along with the recommended Laravel library - Bogardo. The reason I am using the Bogardo library instead of just using the Mailgun SDK or built in Laravel email functionality is neither of these allow for click tracking, bounces and other analytic functionality (that I know of). I am able to send emails just fine using Tinker. However, I am not 100% sure how to properly call my new mailable to send an email that way. Here is 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 BaseEmail extends Mailable
{
use Queueable, SerializesModels;
/**
* Create a new message instance.
*
* #return void
*/
public function __construct()
{
//
}
/**
* Build the message.
*
* #return $this
*/
public function build()
{
$data = ['This is a message from Mailgun!'];
return Mailgun::raw($data, function($message) {
$message
->to('email#domain.com', 'Name Name')
->subject('Yoohoo!')
->from('otheremail#domain.com', 'Name')
->tag(['tag','tag2']);
});
}
}
When I call:
$mail = new App\Mail\BaseEmail();
$mail->send();
I get the following error
TypeError: Too few arguments to function Illuminate\Mail\Mailable::send(), 0 passed in /web/vendor/psy/psysh/src/Psy/ExecutionLoop/Loop.php(90) : eval()'d code on line 1 and exactly 1 expected
and
$mail->send('this');
I get
TypeError: Argument 1 passed to Illuminate\Mail\Mailable::send() must be an instance of Illuminate\Contracts\Mail\Mailer, string given on line 1
Sorry if this is trivial, but I have been following their docs and have Googled everything that I can think of with no luck.
Any direction would be fantastic!
Thanks!
It appears that the Bogardo package does not support Laravel Mailables...
https://github.com/Bogardo/Mailgun/issues/72
You don't need to use the send() method when you're using raw().This code will send an email:
Mailgun::raw($data, function($message) {
$message->to('email#domain.com', 'Name Name')
->subject('Yoohoo!')
->from('otheremail#domain.com', 'Name')
->tag(['tag','tag2']);
});
You also don't need to use Mailable when you're using the package.

Symfony3 save login Timestamp in database after authentication success

Well, the title says it all. I have a login form which works fine. But what I have to do is to save the timestamp when the user successfully logs in in addition to a field which stores the timestamp when the database record is changed. So these are two different fields. I have found this answer here which does what I want. Unfortunately the class ContainerAware is not present in Symfony3 so I don't know how to get a EntityManager instance into my Handler. I'm pretty sure, that there is a simple solution, but I just can't find it.
With help of the hint from #micguo I got a step further. Here is my code so far:
use Symfony\Component\Security\Http\Authentication\AuthenticationSuccessHandlerInterface;
use Symfony\Component\DependencyInjection\ContainerAwareTrait;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Component\HttpFoundation\RedirectResponse;
class AuthenticationHandler implements AuthenticationSuccessHandlerInterface{
use ContainerAwareTrait;
/**
* {#inheritDoc}
* #see \Symfony\Component\Security\Http\Authentication\AuthenticationSuccessHandlerInterface::onAuthenticationSuccess()
*/
public function onAuthenticationSuccess(Request $request, TokenInterface $token) {
$token->getUser()->setAnmeldat(new \DateTime("now"));
$this->container->get('doctrine')->getEntityManager()->flush();
return new RedirectResponse($this->container->get('router')->generate('/auth/bnme'));
}
}
But when I try to log in, Symfony throws an Exception:
Error: Call to a member function get() on a non-object .
What is wrong here?
Use the ContainerAwareTrait instead
To use ContainerAwareTrait, you need to make a definition in your services.yml file.
Create Service implementing ContainerAwareInterface

Attempting to bind Guzzle Curl Client to Laravel's Service Container -- then Type Hint the Client Fails when attempting to __construct()

So I figured I'd try to actually use this fancy IoC container in Laravel. I'm starting with Guzzle but I cannot get it to work. Perhaps there is a gap in my understanding. I really appreciate any help here.
so I've got a class for connecting to a RESTful Api. Here is a sample from it:
use GuzzleHttp\Exception\BadResponseException;
use GuzzleHttp\Client;
use GuzzleHttp\Subscriber\Oauth\Oauth1;
class EtApi {
//you can pass in the model if you wanna
//protected $model;
//client Id
protected $clientId;
//client secret
protected $clientSecret;
//base_uri
protected $getTokenUri;
protected $client;
//build
function __construct(Client $client)
{
$this->client = $client;
$this->clientId = 's0m3R4nd0mStr1nG';
$this->clientSecret = 's0m3R4nd0mStr1nG';
$this->getTokenUri = 'https://rest.api/requestToken';
$this->accessToken = $this->getToken($this->clientId, $this->clientSecret, $this->getTokenUri);
}
}
I've successfully installed and used Guzzle by manually newing it up inside of methods like $client = new Client(); but that's not very DRY and it's not the right way of doing things. So I created a ServiceProvider at app\Providers\GuzzleProvider.php. I made sure this was registered in app/config/app.php under $providers = ['App\Providers\GuzzleProvider']. Here is the Provider Code:
<?php namespace App\Providers;
use Illuminate\Support\ServiceProvider;
use GuzzleHttp\Client;
use GuzzleHttp\Subscriber\Oauth\Oauth1;
class GuzzleProvider extends ServiceProvider {
/**
* Bootstrap the application services.
*
* #return void
*/
public function boot()
{
//
}
/**
* Register the application services.
*
* #return void
*/
public function register()
{
//
$this->app->bind('Client', function () {
return new Client;
});
}
}
So when I try to access my EtApi methods that load fails during the instantiation (__construct) with the following error.
ErrorException in EtApi.php line 23:
Argument 1 passed to App\EtApi::__construct() must be an instance of GuzzleHttp\Client, none given, called in /home/vagrant/webdocs/et_restful_test/app/Http/Controllers/EtConnectController.php on line 23 and defined
Do any of you Laravel Masters have any idea why I can't bind Guzzle using this code and Laravel's magic will just inject the obj into the constructor? The [docs1 say I should be able to do this. I must be missing something. Thank You!
It's a little hard to say for certain based on the information in your question, but based on this
Argument 1 passed to App\EtApi::__construct() must be an instance of GuzzleHttp\Client, none given, called in /home/vagrant/webdocs/et_restful_test/app/Http/Controllers/EtConnectController.php on line 23 and defined
It sounds like you're directly instantiating your App\Eti class on line 23 of EtConnectController.php with code that looks something like this
$api = new App\EtApi;
If that's the case, there's a key piece of Laravel's dependency injection you're missing. Laravel can't change the behavior of standard PHP -- i.e. if you create a new class with PHP's built-in new keyword, then Laravel never has the change to inject any dependencies in __construct.
If you want to take advantage of dependency injection, you also need to instantiate your object via Laravel's app container. There's many different way to do that -- here's two them
//$api = new App\EtApi;
\App::make('App\EtApi'); //probably "the right" way
$api = app()['App\EtApi']
If you do that, Laravel will read the type hints in __construct and try to inject dependencies for your object.
Just change your register function to
/**
* Register the application services.
*
* #return void
*/
public function register()
{
//
$this->app->bind('GuzzleHttp\Client\Client', function () {
return new Client;
});
}
That should do the trick => the IOC resolves the fqcn and not the short one, so exposing it in your container you'll need to bind it to the fqcn too!
Hope it helps!

Categories