stueynet's avatar

Sending a welcome email

So I am working on my second commercial app now. My first one was Laravel 4. Was fun to build. Is awesome. However I focused more on speed while building it out. So natually it has a lot of large controllers, and doesn't really use a lot of the great features or design patters available.

So for my next app, I want to focus on the code. So right out of the gate I am spending a lot of time just thinking about structure and I have hit my first snafu. Sending registration emails.

I am using the Laravel 5 out of the box reg and login stuff which is really easy. but I would like to send some emails when users register. I feel like an event is the best way to do this so I have set up a UserWasRegistered event with a listener to NotifyNewUser, and later I will set up another listener for NotifyAdminOfNewUser. The problem is I don't know where to fire the event.

Within my UserWasRegistered event I inject the user as follows:

public function __construct(User $user)
    {
        $this->user = $user;
    }

But given the built in Laravel 5 registration where would I put the event firing ?

event(new UserWasRegistered)

The AuthController.php uses \Illuminiate\Foundation\Auth\RegistersUsers. Obviously I don't want to put it there. What is the correct way to hook into Laravel 5's built in user registration?

0 likes
12 replies
davorminchorov's avatar

Events can be fired in the controller just like everything else but I believe the best place to fire events might be in the service part of the application which means inside a service class. You already have a Registar.php service class in the Services folder so fire it there.

stueynet's avatar

I don't have a services folder or a Register.php file in it. I am using the latest version of L5 and I am using the baked in Auth features.

stueynet's avatar

Hey guys. Sorry to bump this one but I was hoping for someone to explain this. Its fairly straightforward. How would one send a Welcome email when using the built in Laravel registration features? I am hoping to do so via an event.

stueynet's avatar

Thanks mstnorris. I have seen that video and I am good with the mechanics of emailing. I have a fully running commercial app that sends plenty of email. What I am trying to figure out is the best practice method for sending an email specifically using the built in Laravel auth. So to be more specific:

The AuthController that ships with laravel uses the AuthenticatesAndRegistersUsers trait which uses RegistersUsers. In there the postRegister method does the actual creation of the user on line 38

public function postRegister(Request $request)
    {
        $validator = $this->validator($request->all());

        if ($validator->fails()) {
            $this->throwValidationException(
                $request, $validator
            );
        }

        Auth::login($this->create($request->all()));

        return redirect($this->redirectPath());
    }

So since these are in the Illuminate core, I should likely want to extend this. Should I be just copying the entire method to the local App\Http\Controllers\Auth\AuthController.php and then insert my event hook there? Or is there another way to hook in there.

FutureWeb's avatar

I am trying to achieve the same thing did you ever find how to do it?

Swaz's avatar

@FutureWeb In Laravel 5.2, I think you could just do this.

//app/Http/Controllers/Auth/AuthController.php
protected function create(array $data)
{
    // add event here
    event(new UserWasRegistered)

    return User::create([
        'name' => $data['name'],
        'email' => $data['email'],
        'password' => bcrypt($data['password']),
    ]);
}
davorminchorov's avatar

No, the user has to be created first and passed to the event itself so the application knows which user to send the email to.

nolros's avatar

1.create a create user job

class CreateUser extends Job implements ShouldQueue
{
    use InteractsWithQueue, SerializesModels, DispatchesJobs;
    

    /**
     * @var
     */
    public $data;

    /**
     * Create a new job instance.
     *
     * @return void
     */
    public function __construct($data)
    {
        $this->data = $data;
    }

    /**
     * Execute the job.
     *
     * @return void
     */
    public function handle()
    {
        $data = $this->data;
        
        if ($user = User::create([
            'full_name'         => $data['full_name'],
            'email'             => $data['email'],
            'password'          => $data['password'],

        ])) {
            
            event(new UserHasRegistered($user));
            
        }
    }
}

2.create an event :

class UserHasRegistered extends Event
{
    use SerializesModels;
    /**
     * @var
     */
    public $user;

    /**
     * Create a new event instance.
     *
     * @param $user
     */
    public function __construct($user)
    {
        //
        $this->user = $user;
    }

    /**
     * Get the channels the event should be broadcast on.
     *
     * @return array
     */
    public function broadcastOn()
    {
        return [];
    }
}

3.add event listener in EventServiceProvider

class EventServiceProvider extends ServiceProvider
{
    /**
     * The event listener mappings for the application.
     *
     * @var array
     */
    protected $listen = [
        'App\Events\UserHasRegistered' => [
            'App\Listeners\SendWelcomeEmail@welcome',
        ]
    ];

    /**
     * Register any other events for your application.
     *
     * @param  \Illuminate\Contracts\Events\Dispatcher  $events
     * @return void
     */
    public function boot(DispatcherContract $events)
    {
        parent::boot($events);
    }

4.create a SendWelcomeEmail listener (NOTE: you could also create a sendMail job and create event in CreateUser i.e. event(SendMail) ). You would create a listener if sendmail is listening for multiple events UserHasregistered , UserHasChangedPassword, etc. Also note I have not tested the SendWelcome below ... literately typed it as text

class SendWelcomeEmail
{

    use DispatchesJobs;

    $protected $mailer;



    /**
     * Create the event listener.
     *
     * @return void
     */
    public function __construct(Mailer $mailer)
    {
        $this->mailer = $mailer;
    }

    /**
     * Handle the event.
     *
     * @param  UserHasRegistered  $event
     * @return void
     */
    public function welcome(UserHasRegistered $event)
    {
     $data = [
       'user' => $event->user,
          'from' => '[email protected]',
          'subject' => 'Subject'
    ]; 

        
        $this->mailer->send('emails.auth.verify', $data, function($message) {
            $message->to($data['user']->email, $data['user']->username)
                    ->subject($data['subject']);
        });
    }
}
Swaz's avatar

Thanks @Ruffles, perhaps like this then.

//app/Http/Controllers/Auth/AuthController.php
protected function create(array $data)
{
    $user = User::create([
        'name' => $data['name'],
        'email' => $data['email'],
        'password' => bcrypt($data['password']),
    ]);

    event(new UserRegistered($user));

    return $user;
}
1 like
davorminchorov's avatar

Yeah, that's better :)

A service class is nothing more than a normal class just doing one thing at a time. RegisterUser, RegistersUsers, UserCreator, UserRegistrator are example names (I am sure there are better names). Add this class into your Services folder or a Users Folder, depending how you structure your application.

class RegisterUser {

    public function register(array $data = []) {

        $user = User::create($data);

        event(new UserRegistered($user));

        return $user;
    }

}

So, instead of using an Eloquent model inside your controller, you have it here. So how do you use this service class? It's simple, just inject it inside of the controller method (also known as method injection, dependency injection) like so:

class UsersController extends Controller 
{
    public function register (RegisterUserForm $request, RegisterUser $registerUser) {

        $registerUser->register($request->all());

        flash()->success('Thank you for registering! Enjoy your stay!');

        return view('pages.home');
    }
}
scottycam's avatar

I was working on this myself today. Thought it might help others if I post my solution, I am on 5.4.

There is a trait 'RegistersUsers' used during the process of registering a user. It has a function named 'registered' which is called after the new user has been created. By default it is blank and does nothing.

In your RegisterController class you can override this function to perform actions after a user is successfully created but before they are redirected.

To send out welcome emails I simply added this function to RegisterController.

    protected function registered(Request $request, $user)
    {
        (new WelcomeEmail)->sendTo($user->email, ['name' =>$user->name]);
    }

I have a custom email process so that line won't work for anyone else, just enter the code here you use to send emails.

You will also have to add 'use Illuminate\Http\Request;' to the RegisterController.

Note that the function is passed the newly created user object $user, so you can easily access the users info, $user->name, $user->email, etc.

5 likes

Please or to participate in this conversation.