Search code examples
phplaravelvalidationsmtp

Laravel validate SMTP server settings


I'm trying to validate SMTP server settings using SwiftMailer in my Laravel application.

My main issue is that if SMTP server validation fails, I want it to return the user to the form with the error message in the same way that $this->validate() does.

Here is same sample code so you can see what I'm trying to do:

public function update($id)
{
    $this->validate(request(), [
        "name" => "required|unique:email_servers,name,$id",
        "address" => "required|unique:email_servers,address,$id",
        "username" => "required",
        "password" => "nullable|confirmed",
        "security" => "nullable|exists:email_securities,value",
        "host" => "required",
        "port" => "required",
    ])->after(function ($validator) {
        try{            
            if (request()->input('security')) {
                $transport = Swift_SmtpTransport::newInstance(request()->input('host'), request()->input('port'), request()->input('security'));
            }
            else {
                $transport = Swift_SmtpTransport::newInstance(request()->input('host'), request()->input('port'));
            }

            $transport->setUsername(request()->input('username'));
            $transport->setPassword(request()->input('password'));
            $mailer = \Swift_Mailer::newInstance($transport);
            $mailer->getTransport()->start();
        }
        catch (Swift_TransportException $e) {
            $validator->errors()->add('transport_exception', $e->getMessage());
        }
        catch (Exception $e) {
            $validator->errors()->add('exception', $e->getMessage());
        }
    });

    $email_server = EmailServer::findOrFail($id);
    $email_server->update(array_filter(request()->all()));

    activity()->by(auth()->user())->on($email_server)->withProperties($email_server)->log('Updated Email Server');
    request()->session()->flash('status', 'Email Server updated!');

    return redirect()->route('backend.email_servers');
}

Now, obviously this doesn't work as $this->validate() has no after() callback.

How do I make this work the way I want so that if I were to use Validator::make it would act the same way as $this->validate()?


Solution

  • I figured it out by looking at the ValidatesRequests trait:

        $validator = Validator::make(request()->all(), [
            "name" => "required|unique:email_servers",
            "address" => "required|unique:email_servers",
            "username" => "required",
            "password" => "required|confirmed",
            "security" => "required|exists:email_securities,name",
            "host" => "required",
            "port" => "required",
        ]);
        $validator->after(function ($validator) {
            $transport_status = $this->transportStatus();
    
            if ($transport_status != 'OK') {
                $validator->errors()->add('transport_status', $transport_status);
            }
        });
    
        if ($validator->fails()) {
            $this->throwValidationException(request(), $validator);
        }
        else {
            $email_server = EmailServer::create(request()->all());
    
            activity()->by(auth()->user())->on($email_server)->withProperties($email_server->toArray())->log('Created Email Server');
            request()->session()->flash('status', 'Email Server created!');
    
            return redirect()->route('backend.email_servers');
        }
    
    public function transportStatus()
    {
        try {
            $security = (request()->input('security') != 'None') ? request()->input('security') : null;
            $transport = Swift_SmtpTransport::newInstance(request()->input('host'), request()->input('port'), $security);
            $transport->setUsername(request()->input('username'));
            $transport->setPassword(request()->input('password'));
            $mailer = \Swift_Mailer::newInstance($transport);
            $mailer->getTransport()->start();
    
            return 'OK';
        }
        catch (Swift_TransportException $e) {
            return $e->getMessage();
        }
    }