Послать по адресу

Apr 3, 08:01 pm Категория:

От теории к практике. Быстро! А то стоит одиноко в интернете вся из себя такая продающая страница, клиентов собрала легион, а сообщить мне об этом не может. Пока писал рассуждения о форме почтовой понял, что главное – не заморачиваться. Рассуждать можно долго, а связь должна быть прямо вот сразу. Путь в документацию Laravel – это практически тупик. Если знаешь как делать, то и по документации поймешь. А не знаешь… Ну и вот.

Начнём с настройки. Laravel, если верить файлу конфигурации поддерживает доставку почты “smtp”, “mail”, “sendmail”, “mailgun”, “mandrill”, “ses”, “log”. В соответствии с выбором, который лучше произвести в файле .env, нужно указать и другие параметры, обеспечивающие работу email на конкретном сервере. Для хостинга одно, для домашнего сервера другое, а для выделенного или виртуального сервера и вовсе третье.

MAIL_DRIVER=smtp
MAIL_HOST=mailtrap.io
MAIL_PORT=2525
MAIL_USERNAME=null
MAIL_PASSWORD=null
MAIL_ENCRYPTION=null

Самое главное в почтовых формах – это обеспечение доставки электропочты. Как бы ни был хорош дизайн, он не имеет смысла, если почта не доходит до адресата. Поэтому рекомендую озаботиться этим моментом очень серьёзно и тестировать настройки не отходя от кассы. Сразу хочу предостеречь от использования для доставки своего аккаунта Gmail, если сервер находится вдали от рабочего компьютера. Google просто заблокирует отправку и будет слать предупреждения, что паролем завладели злоумышленники и корпорация добра вот только что спасла тебя от страшного.

Настроили? Проверяем. Для этого проще всего использовать tinker, известный ранее как Boris и являющийся REPL. Всё ясно? Тогда запускаем его и проверяем реальную работу доставки почты. Там ниже real@email – это реальный адрес, на который нужно доставить email. Желательно его указывать без ошибок.

[polygon@ihhi.dev]$ ./artisan tinker
Psy Shell v0.7.2 (PHP 5.5.25 — cli) by Justin Hileman
>>> Mail::send('email.test',
['data' => 'Test, test, test!'],
function($message) {$message->to('real@email')
->subject('Просто тест');
});
InvalidArgumentException with message 'View [email.test-blade] not found.'
>>>

Оп-с, неправильно записал имя blade шаблона. Хотел сделать test.blade.php в resources/views/email, но рука дрогнула. Запускаю с правильным именем шаблона.

>>> Mail::send('email.test-blade',
['data' => 'Test, test, test!'],
function($message) {$message->to('real@email')
->subject('Просто тест');
});
ErrorException with message 'PHP error:  Undefined variable: mydata in /www/dev/ihhindex/cv.ihhindex.dev/storage/framework/views/53c4829e48b94a5f7e7c823bc8903fc74064aa9f.php on line 8 (View: /www/dev/ihhindex/cv.ihhindex.dev/resources/views/email/test-blade.blade.php)'
>>>

Ну здесь обычная история: в шаблоне описанная переменная не получает данных, т.к. в него передаётся другая и он грустит. Ещё одна правка и запуск

>>> Mail::send('email.test-blade',
['data' => 'Test, test, test!'],
function($message) {$message->to('real@email')
->subject('Просто тест');
});
=> 1
>>> exit
Exit:  Goodbye.
[polygon@ihhi.dev]$

Всё получилось, почта ушла. И даже пришла. Сразу скажу, что команда, начиная с Mail:: и до }); может быть одной строкой. Здесь она отформатирована исключительно для удобства восприятия. Если будут найдены ошибки, то курсором придётся “гулять” по всей длине записи.

Теперь потребуется совершить три подвига:

  • Добавить маршруты в router.php;
  • Создать и заполнить кодом контроллер;
  • Сделать вьюшки.

Да, чуть не забыл: перед стартом производства подвигов требуется план. Даже если подвигов всего три. И далее, в соответствии с планом, вычёркиваем сделанное.

Маршруты

Route::group(['middleware' => ['web']], function () {
	Route::get('/{id?}', 'PagesController@show')->where('id', '\d+');
	Route::get('contacts', 'ContactsController@getContacts');
	Route::post('contacts', 'ContactsController@postContacts');
});

Сейчас роутер у меня выглядит предельно просто: все запросы идут через middlware web и далее разруливаются. Вторая строка про вызов одностраничика и про то, что если в адресе обнаруживается число, то генерируется соответствующая версия страницы. Это фишка не для электропочты и на “боевом” сервере отключается.

А следующие две строки с маршрутом contacts про неё родимую. Метод get – вызвать функцию getContacts, которая отображает отдельно стоящую форму отправки. Это вспомогательная функция, т.к. я надеюсь, что вменяемый посетитель сразу правильно заполнит форму и отправит её с одностраничника. Но в случае непосредственного перехода по адресу /contacts будет отображаться эта форма. Она же отображается и при ошибке ввода, так что лишней работы здесь почти нет. Но прямой ссылки на эту страницу я давать не планирую. Метод post вызывает функцию postContacts, которая должна выполнить всю работу. Обе функции в контроллере ContactsController. На этом с маршрутами можно закончить.

Контроллер

Для начала неплохо бы его сделать. И лучше пустым, чтобы не убирать лишнее.

 ./artisan make:controller ContactsController

И теперь про план в отношении этого контроллера: в последнее время из контроллеров стараются убрать всё лишнее. Не должно быть в них обработки, валидации и вообще ничего сложного и повторяющегося. И я с этим согласен. Но не сейчас. Решение рассматриваю как временное и не хочу потом выкорчёвывать следы этой деятельности в нескольких местах. Поэтому всё будет в одном контроллере. После небольшой доработки вот что получилось.

<?php namespace App\Http\Controllers;
use Mail;
use Validator;
use Illuminate\Http\Request;
use App\Http\Requests;
class ContactsController extends Controller
{
    //
}

Я добавил в контроллер почту и валидатор. Теперь быстренько организую функции. Сначала отображение формы

	/**
	 * Show contact form
	 * 
	 * @return view
	 */
    public function getContacts(){
        return view('frontend.pages.contact');
    }

Теперь обработку

/**
 * Post data from contact form
 * 
 * @param Request $request 
 * @return view
 */
public function postContacts(Request $request){
	$data = $request->all();
    $messages = [
        'required'  => 'Это поле обязательно для заполнения.',
        'string'    => 'Введены недопустимые символы.',
        'min' 		=> 'Маловато знаков. Минимум - :min',
        'max' 		=> 'Многовато знаков. Максимум - :max',
        'email'     => 'Это  не похоже на адрес email',
        'url'      	=> 'Это  не похоже на адрес сайта',
    ];
	$validator = Validator::make($data, [
        'contactname' 	=> 'required|min:3|max:255',
        'email' 		=> 'email|required',
        'website' 		=> 'url',
        'message' 		=> 'required|min:10|max:255',
    ], $messages);
	if ($validator->fails()) {
        return redirect('contacts')
                    ->withErrors($validator)
                    ->withInput();
    }
    Mail::send('email.form', ['data' => $data], function($message) use ($data)
    {
     	$message->from($data['email'] , $data['contactname']);
    	$message->to('real@email', 'CV Form')->subject('CV mail form');
    });
    return view('frontend.pages.form-ok', ['name' => $data['contactname']]);
}

Надеюсь всё понятно:

  • Строки 9-16 – я создал свои версии сообщений об ошибках ввода. Делать перевод в файлах локализации не хотелось по описанным выше причинам. И ещё один нюанс: использовать сообщение “Поле contactname обязательно для заполнения” мне не хочется, а стандартные сообщения показывают не названия, которые видит посетитель, а имена, используемые при генерации полей и они часто сильно отличаются.
  • Строки 17-22 – правила проверки пользовательского ввода. Обращаю внимание на поле website – оно не обязательно для заполнения, но если уж посетитель решил в него что-нибудь написать, то потребуется сделать это правильно. И ввести http:// перед адресом, или создать правило самому.
  • Строки 23-27 – в случае ошибки сообщаем об этом пользователю и используем вспомогательный шаблон, а не весь одностраничник. И передаём в него как сообщения об ошибках, так и данные, введённые пользователем. Многие не вводят повторно данные в форму, если они исчезли при ошибке.
  • Строки 28-32 – формирование и отправка почты. Так же я передаю в шаблон form.blade.php весь массив данных из формы. С названием вьюхи я ошибся и оно выглядит провокационно, но пока менять не буду.
  • Строка 33 – вызов страницы с сообщением об успешной отправке. Успех, кстати, не гарантирован, но проверки я не делаю. Потом нужно будет добавить. При формировании сообщения я использую имя автора, для чего передаю его в шаблон. Мне не трудно, а человеку приятно. Да, ещё, я вместо редиректа использую вью. Мне так больше нравится.

Шаблоны

И третья часть марлезонского балета: шаблоны blade. Вспомогательная почтовая форма. Она используется при прямом вызове или при наличии ошибок ввода. Ошибки можно выводить скопом в специально отведённом для этого месте, или под соответствующим полем ввода. Я выбрал второй вариант. При наличии ошибки поле ввода обводится красным бордюром и под ним выводится первое сообщение об ошибке. Одно.

@extends('frontend.layouts.default')
@section('content')

Контакты

Контактная форма

{!! $errors->first('contactname', ':message') !!}
{!! $errors->first('email', ':message') !!}
{!! $errors->first('website', ':message') !!}
{!! $errors->first('message', ':message') !!}

Карта. Во-первых - это красиво.


@endsection

И в случае успеха выводится сообщение с помощью вот такого шаблона.

@extends('frontend.layouts.default')
@section('content')

Контакты

Контактная форма обработана

{{$name}}, всё отлично, письмо отправлено. Теперь попробуйте послать мне бандероль или денежный перевод.

Перейти на единственную страницу сайта

прыг

Карта. Во-первых - это красиво.


@endsection

И… И всё, на этом можно переходить к испытаниям и ждать сообщения от покупателей. А, не, не всё. Я забыл про шаблон для отправки почты. Исправляюсь. Шаблон для тестирования можно сделать на его основе, если что.

<!DOCTYPE HTML>
<html lang="en-US">
<head>
	<meta charset="UTF-8">
	<title></title>
</head>
<body>
	

Hello,

Name: {{ $data['contactname'] }}

E-mail: {{ $data['email'] }}

@if ($data['website'])

Site: {{ $data['website'] }}

@endif

Text: {{ $data['message'] }}

---
Best regards,
CV Team

</body> </html>

Вот теперь всё. Кажется. На самом деле я уже готов всё переделать, но всплыла более насущная проблема: полное отсутствие присутствия админки. Я как-то забыл про неё, а заглянул в роутер и оба-на, нету. Не то, чтобы я хотел активно что-то редактировать на одностраничнике. Но лендинг должен собирать статистику. Можно подключить GA, LI или ещё что-нибудь. Можно добавить их просмотр в админку. Можно сделать свой сбор данных и их анализировать или смотреть “сырыми”. Это детали. И для их реализации админка нужна 100 пудов.

Теги этой статьи: , , ,

 

Комментарии

2017-10-18 10:18 pm , Оставь комментарий